diff options
author | Vitaly Takmazov | 2018-11-08 21:38:27 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2018-11-08 21:38:27 +0300 |
commit | 7aaa3f9a29c280f01c677c918932620be45cdbd7 (patch) | |
tree | 39947b2c889afd08f9c73ba54fab91159d2af258 /juick-server/src/main/assets | |
parent | 3ea9770d0d43fbe45449ac4531ec4b0a374d98ea (diff) |
Merge everything into single Spring Boot application
Diffstat (limited to 'juick-server/src/main/assets')
-rw-r--r-- | juick-server/src/main/assets/embed.js | 334 | ||||
-rw-r--r-- | juick-server/src/main/assets/logo.png | bin | 2447 -> 0 bytes | |||
-rw-r--r-- | juick-server/src/main/assets/logo@2x.png | bin | 4822 -> 0 bytes | |||
-rw-r--r-- | juick-server/src/main/assets/scripts.js | 935 | ||||
-rw-r--r-- | juick-server/src/main/assets/style.css | 956 |
5 files changed, 0 insertions, 2225 deletions
diff --git a/juick-server/src/main/assets/embed.js b/juick-server/src/main/assets/embed.js deleted file mode 100644 index d4cbab8e..00000000 --- a/juick-server/src/main/assets/embed.js +++ /dev/null @@ -1,334 +0,0 @@ - -function insertAfter(newNode, referenceNode) { - referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); -} - -function setContent(containerNode, ...newNodes) { - removeAllFrom(containerNode); - newNodes.forEach(n => containerNode.appendChild(n)); - return containerNode; -} - -function removeAllFrom(fromNode) { - for (let c; c = fromNode.lastChild; ) { fromNode.removeChild(c); } -} - -function htmlEscape(html) { - let textarea = document.createElement('textarea'); - textarea.textContent = html; - return textarea.innerHTML; -} - -// rules :: [{pr: number, re: RegExp, with: string}] -// rules :: [{pr: number, re: RegExp, with: Function}] -// rules :: [{pr: number, re: RegExp, brackets: true, with: [string, string]}] -// rules :: [{pr: number, re: RegExp, brackets: true, with: [string, string, Function]}] -function formatText(txt, rules) { - let idCounter = 0; - function nextId() { return idCounter++; } - function ft(txt, rules) { - let matches = rules.map(r => { r.re.lastIndex = 0; return [r, r.re.exec(txt)]; }) - .filter(([,m]) => m !== null) - .sort(([r1,m1],[r2,m2]) => (r1.pr - r2.pr) || (m1.index - m2.index)); - if (matches && matches.length > 0) { - let [rule, match] = matches[0]; - let subsequentRules = rules.filter(r => r.pr >= rule.pr); - let idStr = `<>(${nextId()})<>`; - let outerStr = txt.substring(0, match.index) + idStr + txt.substring(rule.re.lastIndex); - let innerStr = (rule.brackets) - ? (() => { let [l ,r ,f] = rule.with; return l + ft((f ? f(match[1]) : match[1]), subsequentRules) + r; })() - : match[0].replace(rule.re, rule.with); - return ft(outerStr, subsequentRules).replace(idStr, innerStr); - } - return txt; - } - return ft(htmlEscape(txt), rules); // idStr above relies on the fact the text is escaped -} - -function fixWwwLink(url) { - return url.replace(/^(?!([a-z]+:)?\/\/)/i, '//'); -} - -function makeNewNode(embedType, aNode, reResult) { - const withClasses = el => { - if (embedType.className) { - el.classList.add(...embedType.className.split(' ')); - } - return el; - }; - return embedType.makeNode(aNode, reResult, withClasses(document.createElement('div'))); -} - -function makeIframe(src, w, h, scrolling='no') { - let iframe = document.createElement('iframe'); - iframe.style.width = w; - iframe.style.height = h; - iframe.frameBorder = 0; - iframe.scrolling = scrolling; - iframe.setAttribute('allowFullScreen', ''); - iframe.src = src; - iframe.innerHTML = 'Cannot show iframes.'; - return iframe; -} - -function makeResizableToRatio(element, ratio) { - element.dataset['ratio'] = ratio; - makeResizable(element, w => w * element.dataset['ratio']); -} - -// calcHeight :: Number -> Number -- calculate element height for a given width -function makeResizable(element, calcHeight) { - const setHeight = el => { - if (document.body.contains(el) && (el.offsetWidth > 0)) { - el.style.height = (calcHeight(el.offsetWidth)).toFixed(2) + 'px'; - } - }; - window.addEventListener('resize', () => setHeight(element)); - setHeight(element); -} - -function extractDomain(url) { - const domainRe = /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i; - return domainRe.exec(url)[1]; -} - -function urlReplace(match, p1, p2, p3) { - let isBrackets = (p1 !== undefined); - return (isBrackets) - ? `<a href="${fixWwwLink(p2 || p3)}">${p1}</a>` - : `<a href="${fixWwwLink(match)}">${extractDomain(match)}</a>`; -} - -function urlReplaceInCode(match, p1, p2, p3) { - let isBrackets = (p1 !== undefined); - return (isBrackets) - ? `<a href="${fixWwwLink(p2 || p3)}">${match}</a>` - : `<a href="${fixWwwLink(match)}">${match}</a>`; -} - -function messageReplyReplace(messageId) { - return function(match, mid, rid) { - let replyPart = (rid && rid != '0') ? '#' + rid : ''; - return `<a href="/${mid || messageId}${replyPart}">${match}</a>`; - }; -} - -/** - * Given "txt" message in unescaped plaintext with Juick markup, this function - * returns escaped formatted HTML string. - * - * @param {string} txt - * @param {string} messageId - current message id - * @param {boolean} isCode - * @returns {string} - */ -function juickFormat(txt, messageId, isCode) { - const urlRe = /(?:\[([^\]\[]+)\](?:\[([^\]]+)\]|\(((?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))\))|\b(?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))/gi; - const bqReplace = m => m.replace(/^(?:>|>)\s?/gmi, ''); - return (isCode) - ? formatText(txt, [ - { pr: 1, re: urlRe, with: urlReplaceInCode }, - { pr: 1, re: /\B(?:#(\d+))?(?:\/(\d+))?\b/g, with: messageReplyReplace(messageId) }, - { pr: 1, re: /\B@([\w-]+)\b/gi, with: '<a href="/$1">@$1</a>' }, - ]) - : formatText(txt, [ - { pr: 0, re: /((?:^(?:>|>)\s?[\s\S]+?$\n?)+)/gmi, brackets: true, with: ['<q>', '</q>', bqReplace] }, - { pr: 1, re: urlRe, with: urlReplace }, - { pr: 1, re: /\B(?:#(\d+))?(?:\/(\d+))?\b/g, with: messageReplyReplace(messageId) }, - { pr: 1, re: /\B@([\w-]+)\b/gi, with: '<a href="/$1">@$1</a>' }, - { pr: 2, re: /\B\*([^\n]+?)\*((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<b>', '</b>'] }, - { pr: 2, re: /\B\/([^\n]+?)\/((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<i>', '</i>'] }, - { pr: 2, re: /\b\_([^\n]+?)\_((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<span class="u">', '</span>'] }, - { pr: 3, re: /\n/g, with: '<br/>' }, - ]); -} - -function getEmbeddableLinkTypes() { - return [ - { - name: 'Jpeg and png images', - id: 'embed_jpeg_and_png_images', - className: 'picture compact', - ctsDefault: false, - re: /\.(jpe?g|png|svg)(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i, - makeNode: function(aNode, reResult, div) { - div.innerHTML = `<a href="${aNode.href}"><img src="${aNode.href}"></a>`; - return div; - } - }, - { - name: 'Gif images', - id: 'embed_gif_images', - className: 'picture compact', - ctsDefault: true, - re: /\.gif(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i, - makeNode: function(aNode, reResult, div) { - div.innerHTML = `<a href="${aNode.href}"><img src="${aNode.href}"></a>`; - return div; - } - }, - { - name: 'Video (webm, mp4, ogv)', - id: 'embed_webm_and_mp4_videos', - className: 'video compact', - ctsDefault: false, - re: /\.(webm|mp4|m4v|ogv)(?:\?[\w&;\?=]*)?$/i, - makeNode: function(aNode, reResult, div) { - div.innerHTML = `<video src="${aNode.href}" title="${aNode.href}" controls></video>`; - return div; - } - }, - { - name: 'Audio (mp3, ogg, weba, opus, m4a, oga, wav)', - id: 'embed_sound_files', - className: 'audio singleColumn', - ctsDefault: false, - re: /\.(mp3|ogg|weba|opus|m4a|oga|wav)(?:\?[\w&;\?=]*)?$/i, - makeNode: function(aNode, reResult, div) { - div.innerHTML = `<audio src="${aNode.href}" title="${aNode.href}" controls></audio>`; - return div; - } - }, - { - name: 'YouTube videos (and playlists)', - id: 'embed_youtube_videos', - className: 'youtube resizableV singleColumn', - ctsDefault: false, - re: /^(?:https?:)?\/\/(?:www\.|m\.|gaming\.)?(?:youtu(?:(?:\.be\/|be\.com\/(?:v|embed)\/)([-\w]+)|be\.com\/watch)((?:(?:\?|&(?:amp;)?)(?:\w+=[-\.\w]*[-\w]))*)|youtube\.com\/playlist\?list=([-\w]*)(&(amp;)?[-\w\?=]*)?)/i, - makeNode: function(aNode, reResult, div) { - let [url, v, args, plist] = reResult; - let iframeUrl; - if (plist) { - iframeUrl = '//www.youtube-nocookie.com/embed/videoseries?list=' + plist; - } else { - let pp = {}; args.replace(/^\?/, '') - .split('&') - .map(s => s.split('=')) - .forEach(z => pp[z[0]] = z[1]); - let embedArgs = { rel: '0' }; - if (pp.t) { - const tre = /^(?:(\d+)|(?:(\d+)h)?(?:(\d+)m)?(\d+)s|(?:(\d+)h)?(\d+)m|(\d+)h)$/i; - let [, t, h, m, s, h1, m1, h2] = tre.exec(pp.t); - embedArgs['start'] = (+t) || ((+(h || h1 || h2 || 0))*60*60 + (+(m || m1 || 0))*60 + (+(s || 0))); - } - if (pp.list) { - embedArgs['list'] = pp.list; - } - v = v || pp.v; - let argsStr = Object.keys(embedArgs) - .map(k => `${k}=${embedArgs[k]}`) - .join('&'); - iframeUrl = `//www.youtube-nocookie.com/embed/${v}?${argsStr}`; - } - let iframe = makeIframe(iframeUrl, '100%', '360px'); - iframe.onload = () => makeResizableToRatio(iframe, 9.0 / 16.0); - return setContent(div, iframe); - } - }, - { - name: 'Vimeo videos', - id: 'embed_vimeo_videos', - className: 'vimeo resizableV', - ctsDefault: false, - re: /^(?:https?:)?\/\/(?:www\.)?(?:player\.)?vimeo\.com\/(?:video\/|album\/[\d]+\/video\/)?([\d]+)/i, - makeNode: function(aNode, reResult, div) { - let iframe = makeIframe('//player.vimeo.com/video/' + reResult[1], '100%', '360px'); - iframe.onload = () => makeResizableToRatio(iframe, 9.0 / 16.0); - return setContent(div, iframe); - } - } - ]; -} - -function embedLink(aNode, linkTypes, container, afterNode) { - let anyEmbed = false; - let linkId = (aNode.href.replace(/^https?:/i, '').replace(/\'/gi,'')); - let sameEmbed = container.querySelector(`*[data-linkid='${linkId}']`); // do not embed the same thing twice - if (sameEmbed === null) { - anyEmbed = [].some.call(linkTypes, function(linkType) { - let reResult = linkType.re.exec(aNode.href); - if (reResult) { - if (linkType.match && (linkType.match(aNode, reResult) === false)) { return false; } - let newNode = makeNewNode(linkType, aNode, reResult); - if (!newNode) { return false; } - newNode.setAttribute('data-linkid', linkId); - if (afterNode) { - insertAfter(newNode, afterNode); - } else { - container.appendChild(newNode); - } - aNode.classList.add('embedLink'); - return true; - } - }); - } - return anyEmbed; -} - -function embedLinks(aNodes, container) { - let anyEmbed = false; - let embeddableLinkTypes = getEmbeddableLinkTypes(); - Array.from(aNodes).forEach(aNode => { - let isEmbedded = embedLink(aNode, embeddableLinkTypes, container); - anyEmbed = anyEmbed || isEmbedded; - }); - return anyEmbed; -} - -/** - * Embed all the links inside element "x" that match to "allLinksSelector". - * All the embedded media is placed inside "div.embedContainer". - * "div.embedContainer" is inserted before an element matched by "beforeNodeSelector" - * if not present. Existing container is used otherwise. - * - * @param {Element} x - * @param {string} beforeNodeSelector - * @param {string} allLinksSelector - */ -export function embedLinksToX(x, beforeNodeSelector, allLinksSelector) { - let isCtsPost = false; - let allLinks = x.querySelectorAll(allLinksSelector); - - let existingContainer = x.querySelector('div.embedContainer'); - if (existingContainer) { - embedLinks(allLinks, existingContainer); - } else { - let embedContainer = document.createElement('div'); - embedContainer.className = 'embedContainer'; - - let anyEmbed = embedLinks(allLinks, embedContainer); - if (anyEmbed) { - let beforeNode = x.querySelector(beforeNodeSelector); - x.insertBefore(embedContainer, beforeNode); - } - } -} - -function embedLinksToArticles() { - let beforeNodeSelector = 'nav.l'; - let allLinksSelector = 'p:not(.ir) a, pre a'; - Array.from(document.querySelectorAll('#content article')).forEach(article => { - embedLinksToX(article, beforeNodeSelector, allLinksSelector); - }); -} - -function embedLinksToPost() { - let beforeNodeSelector = '.msg-txt + *'; - let allLinksSelector = '.msg-txt a'; - Array.from(document.querySelectorAll('#content .msg-cont')).forEach(msg => { - embedLinksToX(msg, beforeNodeSelector, allLinksSelector); - }); -} - -/** - * Embed all the links in all messages/replies on the page. - */ -export function embedAll() { - if (document.querySelector('#content article[data-mid]')) { - embedLinksToArticles(); - } else { - embedLinksToPost(); - } -} - -export const format = juickFormat; diff --git a/juick-server/src/main/assets/logo.png b/juick-server/src/main/assets/logo.png Binary files differdeleted file mode 100644 index 4e0f6d56..00000000 --- a/juick-server/src/main/assets/logo.png +++ /dev/null diff --git a/juick-server/src/main/assets/logo@2x.png b/juick-server/src/main/assets/logo@2x.png Binary files differdeleted file mode 100644 index 6febeaf9..00000000 --- a/juick-server/src/main/assets/logo@2x.png +++ /dev/null diff --git a/juick-server/src/main/assets/scripts.js b/juick-server/src/main/assets/scripts.js deleted file mode 100644 index 9ee0639e..00000000 --- a/juick-server/src/main/assets/scripts.js +++ /dev/null @@ -1,935 +0,0 @@ -require('element-closest'); -require('classlist.js'); -require('url-polyfill'); -require('formdata-polyfill'); -import { embedLinksToX, embedAll, format } from './embed'; - -if (!('remove' in Element.prototype)) { // Firefox <23 - Element.prototype.remove = function() { - if (this.parentNode) { - this.parentNode.removeChild(this); - } - }; -} - -NodeList.prototype.forEach = Array.prototype.forEach; -HTMLCollection.prototype.forEach = Array.prototype.forEach; - -NodeList.prototype.filter = Array.prototype.filter; -HTMLCollection.prototype.filter = Array.prototype.filter; - -Element.prototype.selectText = function() { - let d = document; - if (d.body.createTextRange) { - let range = d.body.createTextRange(); - range.moveToElementText(this); - range.select(); - } else if (window.getSelection) { - let selection = window.getSelection(); - let rangeSel = d.createRange(); - rangeSel.selectNodeContents(this); - selection.removeAllRanges(); - selection.addRange(rangeSel); - } -}; - -function autosize(el) { - let offset = (!window.opera) - ? (el.offsetHeight - el.clientHeight) - : (el.offsetHeight + parseInt(window.getComputedStyle(el, null).getPropertyValue('border-top-width'))); - - let resize = function(el) { - el.style.height = 'auto'; - el.style.height = (el.scrollHeight + offset) + 'px'; - }; - - if (el.addEventListener) { - el.addEventListener('input', () => resize(el)); - } else if (el.attachEvent) { - el.attachEvent('onkeyup', () => resize(el)); - } -} - -function evilIcon(name) { - return `<div class="icon icon--${name}"><svg class="icon__cnt"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#${name}-icon"></use></svg></div>`; -} - -/* eslint-disable only-ascii/only-ascii */ -const translations = { - 'en': { - 'message.inReplyTo': 'in reply to', - 'message.reply': 'Reply', - 'message.likeThisMessage?': 'Recommend this message?', - 'postForm.pleaseInputMessageText': 'Please input message text', - 'postForm.upload': 'Upload', - 'postForm.newMessage': 'New message...', - 'postForm.imageLink': 'Link to image', - 'postForm.imageFormats': 'JPG/PNG, up to 10 MB', - 'postForm.or': 'or', - 'postForm.tags': 'Tags (space separated)', - 'postForm.submit': 'Send', - 'comment.writeComment': 'Write a comment...', - 'shareDialog.linkToMessage': 'Link to message', - 'shareDialog.messageNumber': 'Message number', - 'shareDialog.share': 'Share', - 'loginDialog.pleaseIntroduceYourself': 'Please introduce yourself', - 'loginDialog.registeredAlready': 'Registered already?', - 'loginDialog.username': 'Username', - 'loginDialog.password': 'Password', - 'loginDialog.facebook': 'Login with Facebook', - 'loginDialog.vk': 'Login with VK', - 'loginDialog.email': 'Registration', - 'error.error': 'Error' - }, - 'ru': { - 'message.inReplyTo': 'в ответ на', - 'message.reply': 'Ответить', - 'message.likeThisMessage?': 'Рекомендовать это сообщение?', - 'postForm.pleaseInputMessageText': 'Пожалуйста, введите текст сообщения', - 'postForm.upload': 'загрузить', - 'postForm.newMessage': 'Новое сообщение...', - 'postForm.imageLink': 'Ссылка на изображение', - 'postForm.imageFormats': 'JPG/PNG, до 10Мб', - 'postForm.or': 'или', - 'postForm.tags': 'Теги (через пробел)', - 'postForm.submit': 'Отправить', - 'comment.writeComment': 'Написать комментарий...', - 'shareDialog.linkToMessage': 'Ссылка на сообщение', - 'shareDialog.messageNumber': 'Номер сообщения', - 'shareDialog.share': 'Поделиться', - 'loginDialog.pleaseIntroduceYourself': 'Пожалуйста, представьтесь', - 'loginDialog.registeredAlready': 'Уже зарегистрированы?', - 'loginDialog.username': 'Имя пользователя', - 'loginDialog.password': 'Пароль', - 'loginDialog.facebook': 'Войти через Facebook', - 'loginDialog.vk': 'Войти через ВКонтакте', - 'loginDialog.email': 'Регистрация', - 'error.error': 'Ошибка' - } -}; -/* eslint-enable only-ascii/only-ascii */ - -function getLang() { - return (window.navigator.languages && window.navigator.languages[0]) - || window.navigator.userLanguage - || window.navigator.language; -} -function i18n(key, lang = undefined) { - const fallbackLang = 'ru'; - lang = lang || getLang().split('-')[0]; - return (translations[lang] && translations[lang][key]) - || translations[fallbackLang][key] - || key; -} - -var es, pageTitle; - -function initES() { - if (!('EventSource' in window)) { - return; - } - let url = '/api/events'; - let hash = document.getElementById('body').getAttribute('data-hash'); - if (hash) { - url += '?hash=' + hash; - } - - es = new EventSource(url); - es.onopen = function() { - console.log('online'); - if (!document.querySelector('#wsthread')) { - var d = document.createElement('div'); - d.id = 'wsthread'; - d.addEventListener('click', nextReply); - document.querySelector('body').appendChild(d); - pageTitle = document.title; - } - }; - es.addEventListener('msg', msg => { - try { - var jsonMsg = JSON.parse(msg.data); - console.log('data: ' + msg.data); - if (jsonMsg.service) { - return; - } - wsIncomingReply(jsonMsg); - } catch (err) { - console.log(err); - } - }); -} - -function wsIncomingReply(msg) { - let content = document.getElementById('content'); - if (!content) { return; } - let pageMID = content.getAttribute('data-mid'); - if (!pageMID || pageMID != msg.mid) { return; } - let msgNum = '/' + msg.rid; - if (msg.replyto > 0) { - msgNum += ` ${i18n('message.inReplyTo')} <a href="#${msg.replyto}">/${msg.replyto}</a>`; - } - let photoDiv = (msg.attach == null) ? '' : ` - <div class="msg-media"><a href="//i.juick.com/p/${msg.mid}-${msg.rid}.${msg.attach}"> - <img src="//i.juick.com/photos-512/${msg.mid}-${msg.rid}.${msg.attach}"/></a> - </div>`; - let msgContHtml = ` - <div class="msg-cont"> - <div class="msg-header"> - <a href="/${msg.user.uname}/">${msg.user.uname}</a>: - <div class="msg-avatar"> - <a href="/${msg.user.uname}/"><img src="//i.juick.com/a/${msg.user.uid}.png" alt="${msg.user.uname}"/></a> - </div> - <div class="msg-ts"> - <a href="/m/${msg.mid}#${msg.rid}" title="${msg.timestamp}GMT">${msg.timestamp}</a> - </div> - </div> - <div class="msg-txt">${format(msg.body, msg.mid, false)}</div>${photoDiv} - <div class="msg-links">${msgNum} · <a class="msg-reply-link" href="#">${i18n('message.reply')}</a></div> - <div class="msg-comment-target msg-comment-hidden"></div> - </div>`; - - let li = document.createElement('li'); - li.setAttribute('class', 'msg reply-new'); - li.setAttribute('id', msg.rid); - li.innerHTML = msgContHtml; - li.addEventListener('click', newReply); - li.addEventListener('mouseover', newReply); - li.querySelector('a.msg-reply-link').addEventListener('click', function(e) { - showCommentForm(msg.mid, msg.rid); - e.preventDefault(); - }); - - embedLinksToX(li.querySelector('.msg-cont'), '.msg-links', '.msg-txt a'); - - document.getElementById('replies').appendChild(li); - - updateRepliesCounter(); -} - -function newReply(e) { - var li = e.target; - li.classList.remove('reply-new'); - li.removeEventListener('click', e); - li.removeEventListener('mouseover', e); - updateRepliesCounter(); -} - -function nextReply() { - var li = document.querySelector('#replies>li.reply-new'); - if (li) { - li.classList.remove('reply-new'); - li.removeEventListener('click', this); - li.children[0].scrollIntoView(); - updateRepliesCounter(); - } -} - -function updateRepliesCounter() { - var replies = document.querySelectorAll('#replies>li.reply-new').length; - var wsthread = document.getElementById('wsthread'); - if (replies) { - wsthread.textContent = replies; - wsthread.style.display = 'block'; - document.title = '[' + replies + '] ' + pageTitle; - } else { - wsthread.style.display = 'none'; - document.title = pageTitle; - } -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -function postformListener(formEl, ev) { - if (ev.ctrlKey && (ev.keyCode == 10 || ev.keyCode == 13)) { - let form = formEl.closest('form'); - if (!form.onsubmit || form.onsubmit()) { - form.querySelector('input[type="submit"]').click(); - } - } -} -function closeDialogListener(ev) { - ev = ev || window.event; - if (ev.keyCode == 27) { - closeDialog(); - } -} - -function newMessage(evt) { - document.querySelectorAll('#newmessage .dialogtxt').forEach(t => { - t.remove(); - }); - if (document.querySelector('#newmessage textarea').value.length == 0 - && document.querySelector('#newmessage .img').value.length == 0 - && !document.querySelector('#newmessage input[type="file"]')) { - document.querySelector('#newmessage').insertAdjacentHTML('afterbegin', `<p class="dialogtxt">${i18n('postForm.pleaseInputMessageText')}</p>`); - evt.preventDefault(); - } -} - -function handleErrors(response) { - if (!response.ok) { - throw Error(response.statusText); - } - return response; -} - -function showCommentForm(mid, rid) { - let reply = document.getElementById(rid); - let formTarget = reply.querySelector('div.msg-cont .msg-comment-target'); - if (formTarget) { - let formHtml = ` - <form> - <input type="hidden" name="mid" value="${mid}"> - <input type="hidden" name="rid" value="${rid}"> - <div class="msg-comment"> - <div class="ta-wrapper"> - <textarea name="body" rows="1" class="reply" placeholder="${i18n('comment.writeComment')}"></textarea> - <div class="attach-photo">${evilIcon('ei-camera')}</div> - </div> - <input type="submit" value="OK"> - </div> - </form>`; - formTarget.insertAdjacentHTML('afterend', formHtml); - formTarget.remove(); - - let form = reply.querySelector('form'); - let submitButton = form.querySelector('input[type="submit"]'); - - let attachButton = form.querySelector('.msg-comment .attach-photo'); - attachButton.addEventListener('click', e => attachCommentPhoto(e.target)); - - let textarea = form.querySelector('.msg-comment textarea'); - textarea.addEventListener('keypress', e => postformListener(e.target, e)); - autosize(textarea); - - let validateMessage = () => { - let len = textarea.value.length; - if (len > 4096) { return 'Message is too long'; } - return ''; - }; - form.addEventListener('submit', e => { - let validationResult = validateMessage(); - if (validationResult) { - e.preventDefault(); - alert(validationResult); - return false; - } - submitButton.disabled = true; - let formData = new FormData(form); - fetch('/api/comment' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), { - method: 'POST', - body: formData, - credentials: 'omit' - }).then(handleErrors) - .then(response => { - if (response.ok) { - response.json().then(result => { - if (result.newMessage) { - window.location.href = new URL(`${mid}#${result.newMessage.rid}`, window.location.href); - } else { - alert(result.text); - } - window.location.reload(true); - }); - } - }).catch(error => { - alert(error.message); - }); - e.preventDefault(); - }); - } - reply.querySelector('.msg-comment textarea').focus(); -} - -function attachInput() { - let inp = document.createElement('input'); - inp.setAttribute('type', 'file'); - inp.setAttribute('name', 'attach'); - inp.setAttribute('accept', 'image/jpeg,image/png'); - inp.style.visibility = 'hidden'; - return inp; -} - -function attachCommentPhoto(div) { - let input = div.querySelector('input'); - if (input) { - input.remove(); - div.classList.remove('attach-photo-active'); - } else { - let newInput = attachInput(); - newInput.addEventListener('change', function() { - div.classList.add('attach-photo-active'); - }); - newInput.click(); - div.appendChild(newInput); - } -} - -function attachMessagePhoto(div) { - var f = div.closest('form'), - finput = f.querySelector('input[type="file"]'); - if (!finput) { - var inp = attachInput(); - inp.style.float = 'left'; - inp.style.width = 0; - inp.style.height = 0; - inp.addEventListener('change', function() { - div.textContent = i18n('postForm.upload') + ' (✓)'; - }); - f.appendChild(inp); - inp.click(); - } else { - finput.remove(); - div.textContent = i18n('postForm.upload'); - } -} - -function showMessageLinksDialog(mid, rid) { - let hlink = window.location.protocol + '//juick.com/' + mid; - let mlink = '#' + mid; - if (rid > 0) { - hlink += '#' + rid; - mlink += '/' + rid; - } - let hlinkenc = encodeURIComponent(hlink); - let html = ` - <div class="dialogshare"> - ${i18n('shareDialog.linkToMessage')}: <div onclick="this.selectText()" class="dialogl">${hlink}</div> - ${i18n('shareDialog.messageNumber')}: <div onclick="this.selectText()" class="dialogl">${mlink}</div> - ${i18n('shareDialog.share')}: - <ul> - <li><a href="https://www.facebook.com/sharer/sharer.php?u=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-facebook')}</a></li> - <li><a href="https://twitter.com/intent/tweet?url=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-twitter')}</a></li> - <li><a href="https://vk.com/share.php?url=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-vk')}</a></li> - </ul> - </div>`; - - openDialog(html); -} - -function showPhotoDialog(fname) { - let width = window.innerWidth; - let height = window.innerHeight; - let minDimension = (width < height) ? width : height; - if (minDimension < 640) { - return true; // no dialog, open the link - } else if (minDimension < 1280) { - openDialog(`<a href="//i.juick.com/p/${fname}"><img src="//i.juick.com/photos-1024/${fname}"/></a>`, true); - return false; - } else { - openDialog(`<a href="//i.juick.com/p/${fname}"><img src="//i.juick.com/p/${fname}"/></a>`, true); - return false; - } -} - -function openPostDialog() { - let newmessageTemplate = ` - <form id="newmessage" action="/post" method="post" enctype="multipart/form-data"> - <textarea name="body" placeholder="${i18n('postForm.newMessage')}"></textarea> - <div> - <input class="img" name="img" placeholder="${i18n('postForm.imageLink')} (${i18n('postForm.imageFormats')})"/> - ${i18n('postForm.or')} <a href="#">${i18n('postForm.upload')}</a><br/> - <input id="tags_input" class="tags" name="tags" placeholder="${i18n('postForm.tags')}"/><br/> - <input type="submit" class="subm" value="${i18n('postForm.submit')}"/> - </div> - </form> - `; - return openDialog(newmessageTemplate); -} - -function openDialog(html, image) { - var dialogHtml = ` - <div id="dialogt"> - <div id="dialogb"></div> - <div id="dialogw"> - <div id="dialog_header"> - <div id="dialogc">${evilIcon('ei-close')}</div> - </div> - ${html} - </div> - </div>`; - let body = document.querySelector('body'); - body.classList.add('dialog-opened'); - body.insertAdjacentHTML('afterbegin', dialogHtml); - if (image) { - let header = document.querySelector('#dialog_header'); - header.classList.add('header_image'); - } - document.addEventListener('keydown', closeDialogListener); - document.querySelector('#dialogb').addEventListener('click', closeDialog); - document.querySelector('#dialogc').addEventListener('click', closeDialog); -} - -function closeDialog() { - let draft = document.querySelector('#newmessage textarea'); - if (draft) { - window.draft = draft.value; - } - document.querySelector('body').classList.remove('dialog-opened'); - document.querySelector('#dialogb').remove(); - document.querySelector('#dialogt').remove(); -} - -function openSocialWindow(a) { - var w = window.open(a.href, 'juickshare', 'width=640,height=400'); - if (window.focus) { w.focus(); } - return false; -} - -function checkUsername() { - var uname = document.querySelector('#username').textContent, - style = document.querySelector('#username').style; - fetch('/api/users?uname=' + uname) - .then(handleErrors) - .then(function() { - style.background = '#FFCCCC'; - }) - .catch(function() { - style.background = '#CCFFCC'; - }); -} - -/******************************************************************************/ - -function openDialogLogin() { - let html = ` - <div class="dialoglogin"> - <p>${i18n('loginDialog.pleaseIntroduceYourself')}:</p> - <a href="mailto:juick@juick.com?subject=LOGIN" id="signemail">${evilIcon('ei-envelope')}${i18n('loginDialog.email')}</a> - <a href="/_fblogin" id="signfb">${evilIcon('ei-sc-facebook')}${i18n('loginDialog.facebook')}</a> - <a href="/_vklogin" id="signvk">${evilIcon('ei-sc-vk')}${i18n('loginDialog.vk')}</a> - <p>${i18n('loginDialog.registeredAlready')}</p> - <form action="/login" method="POST"> - <input class="signinput" type="text" name="username" placeholder="${i18n('loginDialog.username')}"/><br/> - <input class="signinput" type="password" name="password" placeholder="${i18n('loginDialog.password')}"/><br/> - <input class="signsubmit" type="submit" value="OK"/> - </form> - </div>`; - openDialog(html); - return false; -} - -/******************************************************************************/ - -function resultMessage(str) { - var result = document.createElement('p'); - result.textContent = str; - return result; -} - -function likeMessage(e, mid) { - if (confirm(i18n('message.likeThisMessage?'))) { - fetch('/api/like?mid=' + mid - + '&hash=' + document.getElementById('body').getAttribute('data-hash'), { - method: 'POST', - credentials: 'omit' - }) - .then(handleErrors) - .then(function(response) { - if (response.ok) { - e.closest('article').appendChild(resultMessage('OK!')); - } - }) - .catch(function() { - e.closest('article').appendChild(resultMessage(i18n('error.error'))); - }); - } - return false; -} - -function subscribeMessage(e, mid) { - fetch('/api/subscribe?mid=' + mid - + '&hash=' + document.getElementById('body').getAttribute('data-hash'), { - method: 'POST', - credentials: 'omit' - }) - .then(handleErrors) - .then(function(response) { - if (response.ok) { - window.location.reload(true); - } else { - alert('Something went wrong :('); - } - }) - .catch(error => { - alert(error.message); - }); - return false; -} - -/******************************************************************************/ - -function setPopular(e, mid, popular) { - fetch('/api/messages/set_popular?mid=' + mid - + '&popular=' + popular - + '&hash=' + document.getElementById('body').getAttribute('data-hash'), { - credentials: 'same-origin' - }) - .then(handleErrors) - .then(function() { - e.closest('article').append(resultMessage('OK!')); - }); - return false; -} - -function setPrivacy(e, mid) { - fetch('/api/messages/set_privacy?mid=' + mid - + '&hash=' + document.getElementById('body').getAttribute('data-hash'), { - credentials: 'same-origin' - }) - .then(handleErrors) - .then(function() { - e.closest('article').append(resultMessage('OK!')); - }); - return false; -} - -function getTags() { - fetch('/api/tags?hash=' + document.getElementById('body').getAttribute('data-hash'), { - credentials: 'omit' - }) - .then(handleErrors) - .then(response => { - return response.json(); - }) - .then(json => { - let tags = json.map(t => t.tag); - let input = document.getElementById('tags_input'); - }); - return false; -} - -function addTag(tag) { - document.forms['postmsg'].body.value = '*' + tag + ' ' + document.forms['postmsg'].body.value; - return false; -} - -var users = {}; - -function fetchUserUri(dataUri, callback) { - if (users[dataUri]) { - callback(users[dataUri]); - } else { - let data = new FormData(); - data.append('uri', dataUri); - fetch('/u/', { - method: 'POST', - body: data - }).then(handleErrors) - .then(response => { - return response.json(); - }) - .then(json => { - users[dataUri] = json; - callback(json); - }); - } -} - -/******************************************************************************/ - -function ready(fn) { - if (document.readyState != 'loading') { - fn(); - } else { - document.addEventListener('DOMContentLoaded', fn); - } -} - -ready(function() { - document.querySelectorAll('textarea').forEach((ta) => { - autosize(ta); - }); - - var insertPMButtons = function(e) { - e.target.classList.add('narrowpm'); - e.target.parentNode.insertAdjacentHTML('afterend', '<input type="submit" value="OK"/>'); - e.target.removeEventListener('click', insertPMButtons); - e.preventDefault(); - }; - document.querySelectorAll('textarea.replypm').forEach(function(e) { - e.addEventListener('click', insertPMButtons); - e.addEventListener('keypress', function(e) { - postformListener(e.target, e); - }); - }); - document.querySelectorAll('#postmsg textarea').forEach(function(e) { - e.addEventListener('keypress', function(e) { - postformListener(e.target, e); - }); - }); - - var content = document.getElementById('content'); - if (content) { - var pageMID = content.getAttribute('data-mid'); - if (pageMID > 0) { - document.querySelectorAll('li.msg').forEach(li => { - let showReplyFormBtn = li.querySelector('.a-thread-comment'); - if (showReplyFormBtn) { - showReplyFormBtn.addEventListener('click', function(e) { - showCommentForm(pageMID, li.id); - e.preventDefault(); - }); - } - }); - let opMessage = document.querySelector('.msgthread'); - if (opMessage) { - let replyTextarea = opMessage.querySelector('textarea.reply'); - if (replyTextarea) { - replyTextarea.addEventListener('focus', e => showCommentForm(pageMID, 0)); - replyTextarea.addEventListener('keypress', e => postformListener(e.target, e)); - if (!window.location.hash) { - replyTextarea.focus(); - } - } - } - } - } - - var postmsg = document.getElementById('postmsg'); - if (postmsg) { - document.querySelectorAll('a').filter(t => t.href.indexOf('?') >= 0).forEach(t => { - t.addEventListener('click', e => { - let params = new URLSearchParams(t.href.slice(t.href.indexOf('?') + 1)); - if (params.has('tag')) { - addTag(params.get('tag')); - e.preventDefault(); - } - }); - }); - postmsg.addEventListener('submit', e => { - let formData = new FormData(postmsg); - fetch('/api/post' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), { - method: 'POST', - body: formData, - credentials: 'omit' - }).then(handleErrors) - .then(response => { - if (response.ok) { - response.json().then(result => { - if (result.newMessage) { - window.location = new URL(`/m/${result.newMessage.mid}`, window.location.href); - } else { - alert(result.text); - } - }); - } else { - alert('Something went wrong :('); - } - }).catch(error => { - alert(error.message); - }); - e.preventDefault(); - }); - } - document.querySelectorAll('.pmmsg').forEach(pmmsg => { - pmmsg.addEventListener('submit', e => { - let formData = new FormData(pmmsg); - fetch('/api/pm' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), { - method: 'POST', - body: formData, - credentials: 'omit' - }).then(handleErrors) - .then(response => { - if (response.ok) { - response.json().then(result => { - if (result.to) { - window.location = new URL('/pm/sent', window.location.href); - } else { - alert('Something went wrong :('); - } - }); - } else { - alert('Something went wrong :('); - } - }).catch(error => { - alert(error.message); - }); - e.preventDefault(); - }); - }); - - document.querySelectorAll('.msg-menu').forEach(function(el) { - el.addEventListener('click', function(e) { - var reply = e.target.closest('li'); - var rid = reply ? parseInt(reply.id) : 0; - var message = e.target.closest('section'); - var mid = message.getAttribute('data-mid') || e.target.closest('article').getAttribute('data-mid'); - showMessageLinksDialog(mid, rid); - e.preventDefault(); - }); - }); - document.querySelectorAll('.l .a-privacy').forEach(function(e) { - e.addEventListener('click', function(e) { - setPrivacy( - e.target, - e.target.closest('article').getAttribute('data-mid')); - e.preventDefault(); - }); - }); - document.querySelectorAll('.ir a[data-fname], .msg-media a[data-fname]').forEach(function(el) { - el.addEventListener('click', function(e) { - let fname = e.target.closest('[data-fname]').getAttribute('data-fname'); - if (!showPhotoDialog(fname)) { - e.preventDefault(); - } - }); - }); - document.querySelectorAll('.social a').forEach(function(e) { - e.addEventListener('click', function(e) { - openSocialWindow(e.target); - e.preventDefault(); - }); - }); - var username = document.getElementById('username'); - if (username) { - username.addEventListener('blur', function() { - checkUsername(); - }); - } - - document.querySelectorAll('.l .a-like').forEach(function(e) { - e.addEventListener('click', function(e) { - likeMessage( - e.target, - e.target.closest('article').getAttribute('data-mid')); - e.preventDefault(); - }); - }); - document.querySelectorAll('.l .a-sub').forEach(function(e) { - e.addEventListener('click', function(e) { - subscribeMessage( - e.target, - document.getElementById('content').getAttribute('data-mid')); - e.preventDefault(); - }); - }); - document.querySelectorAll('.a-login').forEach(function(el) { - el.addEventListener('click', function(e) { - openDialogLogin(); - e.preventDefault(); - }); - }); - var unfoldall = document.getElementById('unfoldall'); - if (unfoldall) { - unfoldall.addEventListener('click', function(e) { - document.querySelectorAll('#replies>li').forEach(function(e) { - e.style.display = 'block'; - }); - document.querySelectorAll('#replies .msg-comments').forEach(function(e) { - e.style.display = 'none'; - }); - e.preventDefault(); - }); - } - document.querySelectorAll('article').forEach(function(article) { - if (Array.prototype.some.call( - article.querySelectorAll('.msg-tags a'), - function(a) { - return a.textContent === 'NSFW'; - } - )) { - article.classList.add('nsfw'); - } - }); - document.querySelectorAll('[data-uri]').forEach(el => { - let dataUri = el.getAttribute('data-uri'); - if (dataUri) { - setTimeout(() => fetchUserUri(dataUri, user => { - let header = el.closest('.msg-header'); - header.querySelectorAll('.a-username').forEach(a => { - a.setAttribute('href', user.uri); - let img = a.querySelector('img'); - if (img && user.avatar) { - img.setAttribute('src', user.avatar); - img.setAttribute('alt', user.uname); - } - let textNode = a.childNodes[0]; - if (textNode.nodeType === Node.TEXT_NODE && textNode.nodeValue.trim().length > 0) { - let uname = document.createTextNode(user.uname); - a.replaceChild(uname, a.firstChild); - } - }); - }), 100); - } - }); - document.querySelectorAll('[data-user-uri]').forEach(el => { - let dataUri = el.getAttribute('href'); - if (dataUri) { - setTimeout(() => fetchUserUri(dataUri, user => { - let textNode = el.childNodes[0]; - if (textNode.nodeType === Node.TEXT_NODE && textNode.nodeValue.trim().length > 0) { - let uname = document.createTextNode(`@${user.uname}`); - el.replaceChild(uname, el.firstChild); - } - }), 100); - } - }); - initES(); - - embedAll(); - var elSelector = 'header', - elClassHidden = 'header--hidden', - elClassBackground = 'header--background', - throttleTimeout = 500, - element = document.querySelector(elSelector); - - if (element) { - - var dHeight = 0, - wHeight = 0, - wScrollCurrent = 0, - wScrollBefore = 0, - wScrollDiff = 0, - - throttle = function(delay, fn) { - var last, deferTimer; - return function() { - var context = this, args = arguments, now = +new Date; - if (last && now < last + delay) { - clearTimeout(deferTimer); - deferTimer = setTimeout( - function() { - last = now; - fn.apply(context, args); - }, - delay); - } else { - last = now; - fn.apply(context, args); - } - }; - }; - - window.addEventListener('scroll', throttle(throttleTimeout, function() { - dHeight = document.body.offsetHeight; - wHeight = window.innerHeight; - wScrollCurrent = window.pageYOffset; - wScrollDiff = wScrollBefore - wScrollCurrent; - - if (wScrollCurrent <= 0) { - // scrolled to the very top; element sticks to the top - element.classList.remove(elClassHidden); - element.classList.remove(elClassBackground); - } else if (wScrollDiff > 0 && element.classList.contains(elClassHidden)) { - // scrolled up; element slides in - element.classList.remove(elClassHidden); - element.classList.add(elClassBackground); - } else if (wScrollDiff < 0) { - // scrolled down - if (wScrollCurrent + wHeight >= dHeight && element.classList.contains(elClassHidden)) { - // scrolled to the very bottom; element slides in - element.classList.remove(elClassHidden); - element.classList.add(elClassBackground); - } else { - // scrolled down; element slides out - element.classList.add(elClassHidden); - } - } - - wScrollBefore = wScrollCurrent; - })); - } -}); diff --git a/juick-server/src/main/assets/style.css b/juick-server/src/main/assets/style.css deleted file mode 100644 index 02c59aad..00000000 --- a/juick-server/src/main/assets/style.css +++ /dev/null @@ -1,956 +0,0 @@ -/* #region generic */ - -html, -body, -div, -h1, -h2, -ul, -li, -p, -form, -input, -textarea, -pre { - margin: 0; - padding: 0; -} -textarea { - overflow: auto; -} -html, -input, -textarea { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - font-size: 12pt; - -webkit-font-smoothing: subpixel-antialiased; -} -h1, -h2 { - font-weight: normal; -} -ul { - list-style-type: none; -} -a { - color: #069; - text-decoration: none; -} -img, -hr { - border: none; -} -hr { - background: #CCC; - height: 1px; - margin: 10px 0; -} -pre { - background: #1e2028; - color: #41b645; - overflow-x: auto; - padding: 6px 20px; - white-space: pre; -} -pre::selection { - background: #41b645; - color: #1e2028; -} -pre::-moz-selection { - background: #41b645; - color: #1e2028; -} -.u { - text-decoration: underline; -} - -/* #endregion */ - -/* #region overall layout */ - -html { - background: #f8f8f8; - color: #222; -} -#wrapper { - margin: 0 auto; - width: 1000px; - margin-top: 52px; -} -#column { - float: left; - margin-left: 10px; - overflow: hidden; - padding-top: 10px; - width: 240px; -} -#content { - float: right; - margin: 12px 0 0 0; - width: 728px; -} -#minimal_content { - margin: 0 auto; - min-width: 310px; - width: auto; -} -*::selection { - background: #006699; - color: #fff; -} -body > header { - position: fixed; - top: 0; - width: 100%; - z-index: 10; - transition-duration: 0.5s; - transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - transition-property: transform; -} -@supports (backdrop-filter: blur(10px)) { - body > header--background { - background: rgba(255, 255, 255, 0.8); - backdrop-filter: blur(10px); - } -} -#header_wrapper { - margin: 0 auto; - width: 1000px; - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - padding: 4px; -} -.header--background { - box-shadow: 0 0 3px rgba(0, 0, 0, 0.28); - background: #fff; -} -.header--hidden { - transform: translateY(-100%); -} -#footer { - clear: both; - color: #999; - font-size: 10pt; - margin: 40px; - padding: 10px 0; -} - -@media screen and (max-width: 850px) { - body { - text-size-adjust: 100%; - } - body, - #wrapper, - #topwrapper, - #content, - #footer { - float: none; - margin: 0 auto; - min-width: 310px; - width: auto; - } - #wrapper { - margin-top: 50px; - } - body > header { - margin-bottom: 15px; - } - #column { - float: none; - margin: 0 10px; - padding-top: 0; - width: auto; - } -} - -/* #endregion */ - -/* #region header internals */ - -#logo { - height: 36px; - width: 110px; -} -#logo a { - background: url("logo@2x.png") no-repeat; - background-size: cover; - border: 0; - display: block; - height: 36px; - overflow: hidden; - text-indent: 100%; - white-space: nowrap; - width: 110px; -} -#global { - display: flex; -} -#global a { - color: #888; - display: inline-block; - font-size: 13pt; - padding: 14px 6px; -} -#global li { - display: inline-block; -} -#ctitle a { - padding: 14px; -} -#global li:hover, -#ctitle a:hover, -.l a:hover { - background-color: #fff; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); - cursor: pointer; - transition: box-shadow 0.2s ease-in; -} -#search input { - background: #FFF; - border: 1px solid #ccc; - outline: none !important; - padding: 4px; - -webkit-appearance: none; - border-radius: 0; -} - -/* #endregion */ - -/* #region left column internals */ - -.toolbar { - border-top: 1px solid #CCC; -} - -#column ul, -#column p, -#column hr { - margin: 10px 0; -} -#column li > a { - display: block; - height: 100%; - padding: 6px; -} -#column li > a:hover { - background-color: #fff; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); - transition: background-color 0.2s ease-in; -} -#column .margtop { - margin-top: 15px; -} - -#column .tags { - background: #fff; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); - line-height: 140%; - padding: 6px; - text-align: justify; -} -#column .inp { - background: #fff; - border: 1px solid #ddddd5; - outline: none !important; - padding: 4px; - width: 222px; -} -#column .tags h4 { - background: #eee; - border: 1px solid #eee; - color: #888; - display: block; - text-align: center; -} -#ctitle { - font-size: 14pt; -} -#ctitle img { - margin-right: 5px; - vertical-align: middle; - max-width: 48px; - max-height: 48px; -} -#ustats li { - font-size: 10pt; - margin: 3px 0; -} -#column table.iread { - width: 100%; -} -#column table.iread td { - text-align: center; -} -#column table.iread img { - height: 48px; - width: 48px; -} - -/* #endregion */ - -/* #region main content */ -#content > p, -#content > h1, -#content > h2, -#minimal_content > p, -#minimal_content > h1, -#minimal_content > h2 { - margin: 1em 0; -} -.page { - background: #eee; - padding: 6px; - text-align: center; -} - -.page a { - color: #888; -} - -/* #endregion */ - -/* #region article, message internals */ - -article { - background: #fff; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); - line-height: 140%; - margin-bottom: 10px; - padding: 20px; -} -article time { - color: #999; - font-size: 10pt; -} -article p { - clear: left; - margin: 5px 0 15px 0; - word-wrap: break-word; - overflow-wrap: break-word; -} -article .ir { - text-align: center; -} -article .ir a { - cursor: zoom-in; - display: block; -} -article .ir img { - max-width: 100%; -} -article > nav.l, -.msg-cont > nav.l { - border-top: 1px solid #eee; - display: flex; - justify-content: space-around; - font-size: 10pt; -} -article > nav.l a, -.msg-cont > nav.l a { - color: #888; - margin-right: 15px; -} -article .likes { - padding-left: 20px; -} -article .replies { - margin-left: 18px; -} -article .tags { - margin-top: 3px; -} -.msg-tags { - margin-top: 12px; - min-height: 1px; -} -article .tags > a, -.badge, -.msg-tags > a { - background: #eee; - border: 1px solid #eee; - color: #888; - display: inline-block; - font-size: 10pt; - margin-bottom: 5px; - margin-right: 5px; - padding: 0 10px; -} -.l .msg-button { - align-items: center; - display: flex; - flex-basis: 0; - flex-direction: column; - flex-grow: 1; - padding-top: 12px; -} -.l .msg-button-icon { - font-weight: bold; -} -.msgthread { - margin-bottom: 0; -} -.msg-avatar { - float: left; - max-height: 48px; - margin-right: 10px; - max-width: 48px; -} -.msg-avatar img { - max-height: 48px; - vertical-align: top; - max-width: 48px; -} -.msg-cont { - background: #FFF; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); - line-height: 140%; - margin-bottom: 12px; - padding: 20px; - width: 640px; -} -.reply-new .msg-cont { - border-right: 5px solid #0C0; -} -.msg-ts { - font-size: small; - vertical-align: top; -} -.msg-ts, -.msg-ts > a { - color: #999; -} -.msg-txt { - clear: both; - margin: 0 0 12px; - padding-top: 10px; - word-wrap: break-word; - overflow-wrap: break-word; -} -.msg-media { - text-align: center; -} -.msg-links { - color: #999; - font-size: small; - margin: 5px 0 0 0; -} -.msg-comments { - color: #AAA; - font-size: small; - margin-top: 10px; - overflow: hidden; - text-indent: 10px; -} -.ta-wrapper { - border: 1px solid #DDD; - display: flex; - flex-grow: 1; -} -.msg-comment { - display: flex; - width: 100%; - margin-top: 10px; -} -.msg-comment-hidden { - display: none; -} -.msg-comment textarea { - border: 0; - flex-grow: 1; - outline: none !important; - padding: 4px; - resize: vertical; - vertical-align: top; -} -.attach-photo { - cursor: pointer; -} -.attach-photo-active { - color: green; -} -.msg-comment input { - align-self: flex-start; - background: #EEE; - border: 1px solid #CCC; - color: #999; - margin: 0 0 0 6px; - position: -webkit-sticky; - position: sticky; - top: 70px; - vertical-align: top; - width: 50px; -} -.msg-recomms { - color: #AAA; - font-size: small; - margin-top: 10px; - overflow: hidden; - text-indent: 10px; -} -#replies .msg-txt, -#private-messages .msg-txt { - margin: 0; -} -.title2 { - background: #fff; - margin: 20px 0; - padding: 10px 20px; - width: 640px; -} -.title2-right { - float: right; - line-height: 24px; -} -#content .title2 h2 { - font-size: x-large; - margin: 0; -} - -@media screen and (max-width: 850px) { - #header_wrapper { - width: auto; - } - #global { - justify-content: space-around; - flex-grow: 1; - } - #search { - padding: 4px; - } - article { - overflow: auto; - } - article p { - margin: 10px 0 8px 0; - } - .msg, - .msg-cont { - min-width: 280px; - width: auto; - } - .msg-cont { - margin: 8px 0; - } - .msg-media { - overflow: auto; - } - .title2 h2 { - font-size: large; - } - .msg-comment { - flex-direction: column; - } - .msg-comment input { - align-self: flex-end; - margin: 6px 0 0 0; - width: 100px; - } -} - -@media screen and (max-width: 480px) { - #wrapper { - margin-top: 104px; - } - #search { - display: none; - } - #global a { - padding: 14px 2px; - font-size: 11pt; - } - .msg-cont > nav.l, - article > nav.l { - font-size: 9pt; - } - .msg-txt { - padding-top: 5px; - } - .title2 { - font-size: 11pt; - width: auto; - } - #content .title2 h2 { - font-size: 11pt; - } - .title2-right { - line-height: initial; - } -} - -/* #endregion */ - -/* #region user-generated texts */ - -q:before, -q:after { - content: ""; -} -q, -blockquote { - border-left: 3px solid #CCC; - color: #666; - display: block; - margin: 10px 0 10px 10px; - padding-left: 10px; -} - -/* #endregion */ - -/* #region new message form internals */ - -#newmessage { - background: #E5E5E0; - margin-bottom: 20px; - padding: 15px; -} -#newmessage textarea { - border: 1px solid #CCC; - box-sizing: border-box; - margin: 0 0 5px 0; - margin-top: 20px; - max-height: 6em; - min-width: 280px; - padding: 4px; - width: 100%; -} -#newmessage input { - border: 1px solid #CCC; - margin: 5px 0; - padding: 2px 4px; -} -#newmessage .img { - width: 500px; -} -#newmessage .tags { - width: 500px; -} -#newmessage .subm { - background: #EEEEE5; - width: 150px; -} -@media screen and (max-width: 850px) { - #newmessage .img, - #newmessage .tags { - width: 100%; - } -} - -/* #endregion */ - -/* #region user lists */ - -.users { - margin: 10px 0; - width: 100%; - display: flex; - flex-wrap: wrap; -} -.users > span { - overflow: hidden; - padding: 6px 0; - width: 200px; -} -.users img { - height: 32px; - margin-right: 6px; - vertical-align: middle; - width: 32px; -} - -/* #endregion */ - -/* #region signup form */ - -.signup-h1 > img { - margin-right: 10px; - vertical-align: middle; -} -.signup-h1 { - font-size: x-large; - margin: 20px 0 10px 0; -} -.signup-h2 { - font-size: large; - margin: 10px 0 5px 0; -} -.signup-hr { - margin: 20px 0; -} - -/* #endregion */ - -/* #region PM */ - -.newpm { - margin: 20px 60px 30px 60px; -} -.newpm textarea { - resize: vertical; - width: 100%; -} -.newpm-send input { - width: 100px; -} - -/* #endregion */ - -/* #region popup dialog (lightbox) */ - -#dialogb { - background: #222; - height: 100%; - left: 0; - opacity: 0.6; - position: fixed; - top: 0; - width: 100%; - z-index: 10; -} -#dialogt { - height: 100%; - left: 0; - position: fixed; - top: 0; - width: 100%; - z-index: 10; - display: flex; - align-items: center; - justify-content: center; -} -#dialogw { - z-index: 11; - max-width: 96%; - max-height: calc(100% - 100px); - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} -#dialogw a { - display: block; -} -#dialogw img { - max-height: 100%; - max-height: 90vh; - max-width: 100%; -} -#dialog_header { - width: 100%; - height: 44px; - position: fixed; - display: flex; - flex-direction: row-reverse; - align-items: center; -} -.header_image { - background: rgba(0, 0, 0, 0.28); -} -#dialogc { - cursor: pointer; - color: #ccc; - padding-right: 6px; -} -.dialoglogin { - background: #fff; - padding: 25px; - width: 300px; -} -.dialog-opened { - overflow: hidden; -} -#signemail, -#signfb, -#signvk { - display: block; - line-height: 32px; - margin: 10px 0; - text-decoration: none; - width: 100%; -} -#signvk { - margin-bottom: 30px; -} -.dialoglogin form { - margin-top: 7px; -} -.signinput, -.signsubmit { - border: 1px solid #CCC; - margin: 3px 0; - padding: 3px; -} -.signinput { - width: 292px; -} -.signsubmit { - width: 70px; -} -.dialogshare { - background: #fff; - min-width: 300px; - overflow: auto; - padding: 20px; -} -.dialogl { - background: #fff; - border: 1px solid #DDD; - margin: 3px 0 20px; - padding: 5px; -} -.dialogshare li { - float: left; - margin: 5px 10px 0 0; -} -.dialogshare a { - display: block; -} -.dialogtxt { - background: #fff; - padding: 20px; -} - -@media screen and (max-width: 480px) { - .dialog-opened { - position: fixed; - width: 100%; - } -} - -/* #endregion */ - -/* #region misc */ - -#wsthread { - background: #CCC; - bottom: 20px; - cursor: pointer; - display: none; - padding: 5px 10px; - position: fixed; - right: 20px; -} -.sharenew { - display: inline-block; - line-height: 32px; - min-height: 32px; - min-width: 200px; - padding: 0 12px 0 37px; -} -.icon { - margin-top: -2px; - vertical-align: middle; -} -.icon--ei-link { - margin-top: -1px; -} -.icon--ei-comment { - margin-top: -5px; -} -.newmessage { - /* textarea on the /post page */ - border: 1px solid #DDD; - padding: 2px; - resize: vertical; - width: 100%; -} - -/* #endregion */ - -/* #region footer internals */ - -#footer-social { - float: left; -} -#footer-social a { - border: 0; - display: inline-block; -} -#footer-left { - margin-left: 286px; - margin-right: 350px; -} -#footer-right { - float: right; -} - -@media screen and (max-width: 850px) { - #footer { - margin: 0 10px; - } - #footer div { - float: none; - margin: 10px 0; - } -} - -/* #endregion */ - -/* #region settings */ - -fieldset { - border: 1px dotted #ccc; - margin-top: 25px; -} - -/* #endregion */ - -/* #region embeds */ - -.embedContainer { - display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: center; - padding: 0; - margin: 30px -3px 15px -3px; -} -.embedContainer > * { - box-sizing: border-box; - flex-grow: 1; - margin: 3px; - min-width: 49%; -} -.embedContainer > .compact { - flex-grow: 0; -} -.embedContainer .picture img { - display: block; -} -.embedContainer img, -.embedContainer video { - max-width: 100%; - max-height: 80vh; -} -.embedContainer > .audio, -.embedContainer > .youtube { - min-width: 90%; -} -.embedContainer audio { - width: 100%; -} -.embedContainer iframe { - overflow: hidden; - resize: vertical; - display: block; -} - -/* #endregion */ - -/* #region nsfw */ - -article.nsfw .embedContainer img, -article.nsfw .embedContainer video, -article.nsfw .embedContainer iframe, -article.nsfw .ir img { - opacity: 0.1; -} -article.nsfw .embedContainer img:hover, -article.nsfw .embedContainer video:hover, -article.nsfw .embedContainer iframe:hover, -article.nsfw .ir img:hover { - opacity: 1; -} - -/* #endregion */ |