您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows preview of the linked questions/answers on hover
当前为
// ==UserScript== // @name SE Preview on hover // @description Shows preview of the linked questions/answers on hover // @version 0.3.9 // @author wOxxOm // @namespace wOxxOm.scripts // @license MIT License // @match *://*.stackoverflow.com/* // @match *://*.superuser.com/* // @match *://*.serverfault.com/* // @match *://*.askubuntu.com/* // @match *://*.stackapps.com/* // @match *://*.mathoverflow.net/* // @match *://*.stackexchange.com/* // @include /https?:\/\/www\.?google(\.com?)?(\.\w\w)?\/(webhp|q|.*?[?#]q=|search).*/ // @require https://greatest.deepsurf.us/scripts/12228/code/setMutationHandler.js // @require https://greatest.deepsurf.us/scripts/27531/code/LZString-2xspeedup.js // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect stackoverflow.com // @connect superuser.com // @connect serverfault.com // @connect askubuntu.com // @connect stackapps.com // @connect mathoverflow.net // @connect stackexchange.com // @connect cdn.sstatic.net // @run-at document-end // @noframes // ==/UserScript== /* jshint lastsemic:true, multistr:true, laxbreak:true, -W030, -W041, -W084 */ const PREVIEW_DELAY = 200; const CACHE_DURATION = 1 * 60 * 1000; // 1 minute for the recently active posts, scales up logarithmically const COLORS = { question: { backRGB: '80, 133, 195', fore: '#265184', }, answer: { backRGB: '112, 195, 80', fore: '#3f7722', foreInv: 'white', }, deleted: { backRGB: '181, 103, 103', fore: 'rgb(181, 103, 103)', foreInv: 'white', }, closed: { backRGB: '255, 206, 93', fore: 'rgb(194, 136, 0)', foreInv: 'white', }, }; let xhr; let preview = { frame: null, link: null, hover: {x:0, y:0}, timer: 0, stylesOverride: '', }; const lockScroll = {}; const rxPreviewable = getURLregexForMatchedSites(); const thisPageUrls = getPageBaseUrls(location.href); initStyles(); initPolyfills(); setMutationHandler('a', onLinkAdded, {processExisting: true}); setTimeout(cleanupCache, 10000); /**************************************************************/ function onLinkAdded(links) { for (let i = 0, link; (link = links[i++]); ) { if (isLinkPreviewable(link)) { link.removeAttribute('title'); $on('mouseover', link, onLinkHovered); } } } function onLinkHovered(e) { if (hasKeyModifier(e)) return; preview.link = this; $on('mousemove', this, onLinkMouseMove); $on('mouseout', this, abortPreview); $on('mousedown', this, abortPreview); restartPreviewTimer(this); } function onLinkMouseMove(e) { let stoppedMoving = Math.abs(preview.hover.x - e.clientX) < 2 && Math.abs(preview.hover.y - e.clientY) < 2; if (!stoppedMoving) return; preview.hover.x = e.clientX; preview.hover.y = e.clientY; restartPreviewTimer(this); } function restartPreviewTimer(link) { clearTimeout(preview.timer); preview.timer = setTimeout(() => { preview.timer = 0; $off('mousemove', link, onLinkMouseMove); if (link.matches(':hover')) downloadPreview(link.href); }, PREVIEW_DELAY); } function abortPreview(e) { releaseLinkListeners(this); preview.timer = setTimeout(link => { if (link == preview.link && preview.frame && !preview.frame.matches(':hover')) preview.frame.contentWindow.postMessage('SEpreview-hidden', '*'); }, PREVIEW_DELAY * 3, this); if (xhr) xhr.abort(); } function releaseLinkListeners(link = preview.link) { $off('mousemove', link, onLinkMouseMove); $off('mouseout', link, abortPreview); $off('mousedown', link, abortPreview); clearTimeout(preview.timer); } function fadeOut(element, transition) { return new Promise(resolve => { if (transition) { element.style.transition = typeof transition == 'number' ? `opacity ${transition}s ease-in-out` : transition; setTimeout(doFadeOut); } else doFadeOut(); function doFadeOut() { element.style.opacity = '0'; $on('transitionend', element, function done() { $off('transitionend', element, done); if (element.style.opacity == '0') element.style.display = 'none'; resolve(); }); } }); } function fadeIn(element) { element.style.opacity = '0'; element.style.display = 'block'; setTimeout(() => element.style.opacity = '1'); } function downloadPreview(url) { const cached = readCache(url); if (cached) { if (preview.frame) preview.frame.style.transitionDuration = '0.1s'; showPreview(cached); } else { if (preview.frame) preview.frame.style.transitionDuration = ''; xhr = GM_xmlhttpRequest({ method: 'GET', url: httpsUrl(url), onload: r => { const html = r.responseText; const lastActivity = +showPreview({finalUrl: r.finalUrl, html}); if (!lastActivity) return; const inactiveDays = Math.max(0, (Date.now() - lastActivity) / (24 * 3600 * 1000)); const cacheDuration = CACHE_DURATION * Math.pow(Math.log(inactiveDays + 1) + 1, 2); setTimeout(writeCache, 1000, {url, finalUrl: r.finalUrl, html, cacheDuration}); }, }); } } function initPreview() { preview.frame = document.createElement('iframe'); preview.frame.id = 'SEpreview'; document.body.appendChild(preview.frame); lockScroll.attach = e => { if (lockScroll.pos) return; lockScroll.pos = {x: scrollX, y: scrollY}; $on('scroll', document, lockScroll.run); $on('mouseover', document, lockScroll.detach); }; lockScroll.run = e => scrollTo(lockScroll.pos.x, lockScroll.pos.y); lockScroll.detach = e => { if (!lockScroll.pos) return; lockScroll.pos = null; $off('mouseover', document, lockScroll.detach); $off('scroll', document, lockScroll.run); }; } function showPreview({finalUrl, html, doc}) { doc = doc || new DOMParser().parseFromString(html, 'text/html'); if (!doc || !doc.head) return error('no HEAD in the document received for', finalUrl); if (!$('base', doc)) doc.head.insertAdjacentHTML('afterbegin', `<base href="${finalUrl}">`); const answerIdMatch = finalUrl.match(/questions\/\d+\/[^\/]+\/(\d+)/); const isQuestion = !answerIdMatch; const postId = answerIdMatch ? '#answer-' + answerIdMatch[1] : '#question'; const post = $(postId + ' .post-text', doc); if (!post) return error('No parsable post found', doc); const isDeleted = !!post.closest('.deleted-answer'); const title = $('meta[property="og:title"]', doc).content; const status = isQuestion && !$('.question-status', post) ? $('.question-status', doc) : null; const isClosed = $('.question-originals-of-duplicate, .close-as-off-topic-status-list, .close-status-suffix', doc); const comments = $(`${postId} .comments`, doc); const commentsHidden = +$('tbody', comments).dataset.remainingCommentsCount; const commentsShowLink = commentsHidden && $(`${postId} .js-show-link.comments-link`, doc); const finalUrlOfQuestion = getCacheableUrl(finalUrl); const lastActivity = tryCatch(() => new Date($('.lastactivity-link', doc).title).getTime()) || Date.now(); markPreviewableLinks(doc); $$remove('script', doc); if (!preview.frame) initPreview(); let pvDoc, pvWin; preview.frame.style.display = ''; preview.frame.setAttribute('SEpreview-type', isDeleted ? 'deleted' : isQuestion ? (isClosed ? 'closed' : 'question') : 'answer'); onFrameReady(preview.frame).then( () => { pvDoc = preview.frame.contentDocument; pvWin = preview.frame.contentWindow; initPolyfills(pvWin); }) .then(addStyles) .then(render) .then(show); return lastActivity; function markPreviewableLinks(container) { for (let link of $$('a:not(.SEpreviewable)', container)) { if (rxPreviewable.test(link.href)) { link.removeAttribute('title'); link.classList.add('SEpreviewable'); } } } function addStyles() { const SEpreviewStyles = $replaceOrCreate({ id: 'SEpreviewStyles', tag: 'style', parent: pvDoc.head, className: 'SEpreview-reuse', innerHTML: preview.stylesOverride, }); $replaceOrCreate($$('style', doc).map(e => ({ id: 'SEpreview' + e.innerHTML.replace(/\W+/g, '').length, tag: 'style', before: SEpreviewStyles, className: 'SEpreview-reuse', innerHTML: e.innerHTML, }))); return onStyleSheetsReady( $replaceOrCreate($$('link[rel="stylesheet"]', doc).map(e => ({ id: e.href.replace(/\W+/g, ''), tag: 'link', before: SEpreviewStyles, className: 'SEpreview-reuse', href: e.href, rel: 'stylesheet', }))) ); } function render() { pvDoc.body.setAttribute('SEpreview-type', preview.frame.getAttribute('SEpreview-type')); $replaceOrCreate([{ // title id: 'SEpreview-title', tag: 'a', parent: pvDoc.body, className: 'SEpreviewable', href: finalUrlOfQuestion, textContent: title, }, { // close button id: 'SEpreview-close', parent: pvDoc.body, title: 'Or press Esc key while the preview is focused (also when just shown)', }, { // vote count, date, views# id: 'SEpreview-meta', parent: pvDoc.body, innerHTML: [ $text('.vote-count-post', post.closest('table')).replace(/(-?)(\d+)/, (s, sign, v) => s == '0' ? '' : `<b>${s}</b> vote${+v > 1 ? 's' : ''}, `), isQuestion ? $$('#qinfo tr', doc) .map(row => $$('.label-key', row).map($text).join(' ')) .join(', ').replace(/^((.+?) (.+?), .+?), .+? \3$/, '$1') : [...$$('.user-action-time', post.closest('.answer'))] .reverse().map($text).join(', ') ].join('') }, { // content wrapper id: 'SEpreview-body', parent: pvDoc.body, className: isDeleted ? 'deleted-answer' : '', children: [status, post.parentElement, comments, commentsShowLink], }]); // delinkify/remove non-functional items in post-menu $$remove('.short-link, .flag-post-link', pvDoc); $$('.post-menu a:not(.edit-post)', pvDoc).forEach(a => { if (a.children.length) a.outerHTML = `<span>${a.innerHTML}</span>`; else a.remove(); }); // add a timeline link $('.post-menu', pvDoc).insertAdjacentHTML('beforeend', '<span class="lsep">|</span>' + `<a href="/posts/${new URL(finalUrl).pathname.match(/\d+/)[0]}/timeline">timeline</a>`); $$remove('.post-menu .lsep + .lsep', pvDoc); // prettify code blocks const codeBlocks = $$('pre code', pvDoc); if (codeBlocks.length) { codeBlocks.forEach(e => e.parentElement.classList.add('prettyprint')); if (!pvWin.StackExchange) { pvWin.StackExchange = {}; let script = $scriptIn(pvDoc.head); script.text = 'StackExchange = {}'; script = $scriptIn(pvDoc.head); script.src = 'https://cdn.sstatic.net/Js/prettify-full.en.js'; script.setAttribute('onload', 'prettyPrint()'); } else $scriptIn(pvDoc.body).text = 'prettyPrint()'; } // render bottom shelf const answers = $$('.answer', doc); if (answers.length > (isQuestion ? 0 : 1)) { $replaceOrCreate({ id: 'SEpreview-answers', parent: pvDoc.body, innerHTML: answers.map(renderShelfAnswer).join(' '), }); } else $$remove('#SEpreview-answers', pvDoc); // cleanup leftovers from previously displayed post and foreign elements not injected by us $$('style, link, body script, html > *:not(head):not(body)', pvDoc).forEach(e => { if (e.classList.contains('SEpreview-reuse')) e.classList.remove('SEpreview-reuse'); else e.remove(); }); } function renderShelfAnswer(e) { const shortUrl = $('.short-link', e).href.replace(/(\d+)\/\d+/, '$1'); const extraClasses = (e.matches(postId) ? ' SEpreviewed' : '') + (e.matches('.deleted-answer') ? ' deleted-answer' : '') + ($('.vote-accepted-on', e) ? ' SEpreview-accepted' : ''); const author = $('.post-signature:last-child', e); const title = $text('.user-details a', author) + ' (rep ' + $text('.reputation-score', author) + ')\n' + $text('.user-action-time', author); const gravatar = $('img, .anonymous-gravatar, .community-wiki', author); return ( `<a href="${shortUrl}" title="${title}" class="SEpreviewable${extraClasses}">` + $text('.vote-count-post', e).replace(/^0$/, ' ') + ' ' + (!gravatar ? '' : gravatar.src ? `<img src="${gravatar.src}">` : gravatar.outerHTML) + '</a>'); } function show() { pvDoc.onmouseover = lockScroll.attach; pvDoc.onclick = onClick; pvDoc.onkeydown = e => !hasKeyModifier(e) && e.keyCode == 27 ? hide() : null; pvWin.onmessage = e => e.data == 'SEpreview-hidden' ? hide({fade: true}) : null; $$('.user-info a img', pvDoc).forEach(e => e.onmouseover = loadUserDetails); $('#SEpreview-body', pvDoc).scrollTop = 0; preview.frame.style.opacity = '1'; preview.frame.focus(); } function hide({fade = false} = {}) { releaseLinkListeners(); releasePreviewListeners(); const maybeZap = () => preview.frame.style.opacity == '0' && $removeChildren(pvDoc.body); if (fade) fadeOut(preview.frame).then(maybeZap); else { preview.frame.style.opacity = '0'; preview.frame.style.display = 'none'; maybeZap(); } } function releasePreviewListeners(e) { pvWin.onmessage = null; pvDoc.onmouseover = null; pvDoc.onclick = null; pvDoc.onkeydown = null; } function onClick(e) { if (e.target.id == 'SEpreview-close') return hide(); const link = e.target.closest('a'); if (!link) return; if (link.matches('.js-show-link.comments-link')) { fadeOut(link, 0.5); loadComments(); return e.preventDefault(); } if (e.button || hasKeyModifier(e) || !link.matches('.SEpreviewable')) return (link.target = '_blank'); e.preventDefault(); if (link.id == 'SEpreview-title') showPreview({doc, finalUrl: finalUrlOfQuestion}); else if (link.matches('#SEpreview-answers a')) showPreview({doc, finalUrl: finalUrlOfQuestion + '/' + link.pathname.match(/\/(\d+)/)[1]}); else downloadPreview(link.href); } function loadComments() { GM_xmlhttpRequest({ method: 'GET', url: new URL(finalUrl).origin + '/posts/' + comments.id.match(/\d+/)[0] + '/comments', onload: r => { let tbody = $(`#${comments.id} tbody`, pvDoc); let oldIds = new Set([...tbody.rows].map(e => e.id)); tbody.innerHTML = r.responseText; tbody.closest('.comments').style.display = 'block'; for (let tr of tbody.rows) if (!oldIds.has(tr.id)) tr.classList.add('new-comment-highlight'); markPreviewableLinks(tbody); }, }); } function loadUserDetails(e, ready) { if (ready !== true) return setTimeout(loadUserDetails, PREVIEW_DELAY, e, true); $$('#user-menu', pvDoc).forEach(e => e.id = ''); const userId = e.target.closest('a').pathname.match(/\d+/)[0]; const existing = $(`.SEpreview-user[data-id="${userId}"]`, pvDoc); if (existing) { existing.id = 'user-menu'; fadeIn(existing); return; } GM_xmlhttpRequest({ method: 'GET', url: new URL(finalUrl).origin + '/users/user-info/' + userId, onload: r => { let userMenu = $replaceOrCreate({ id: 'user-menu', dataset: {id: userId}, parent: e.target.closest('.user-info'), className: 'SEpreview-user', innerHTML: r.responseText, }); userMenu.onmouseout = e => e.target == userMenu ? fadeOut(userMenu) : null; userMenu.onmouseover = e => e.target == userMenu ? (userMenu.style.opacity = '1') : null; fadeIn(userMenu); }, }); } } function getCacheableUrl(url) { // strips queries and hashes and anything after the main part https://site/questions/####/title/ return url .replace(/(\/q(?:uestions)?\/\d+\/[^\/]+).*/, '$1') .replace(/(\/a(?:nswers)?\/\d+).*/, '$1') .replace(/[?#].*$/, ''); } function readCache(url) { keyUrl = getCacheableUrl(url); const meta = (localStorage[keyUrl] || '').split('\t'); const expired = +meta[0] < Date.now(); const finalUrl = meta[1] || url; const keyFinalUrl = meta[1] ? getCacheableUrl(finalUrl) : keyUrl; return !expired && { finalUrl, html: LZString.decompressFromUTF16(localStorage[keyFinalUrl + '\thtml']), }; } function writeCache({url, finalUrl, html, cacheDuration = CACHE_DURATION, cleanupRetry}) { // keyUrl=expires // redirected keyUrl=expires+finalUrl, and an additional entry keyFinalUrl=expires is created // keyFinalUrl\thtml=html cacheDuration = Math.max(CACHE_DURATION, Math.min(0xDEADBEEF, Math.floor(cacheDuration))); finalUrl = finalUrl.replace(/[?#].*/, ''); const keyUrl = getCacheableUrl(url); const keyFinalUrl = getCacheableUrl(finalUrl); const expires = Date.now() + cacheDuration; const lz = LZString.compressToUTF16(html); if (!tryCatch(() => localStorage[keyFinalUrl + '\thtml'] = lz)) { if (cleanupRetry) return error('localStorage write error'); cleanupCache({aggressive: true}); setIimeout(writeCache, 0, {url, finalUrl, html, cacheDuration, cleanupRetry: true}); } localStorage[keyFinalUrl] = expires; if (keyUrl != keyFinalUrl) localStorage[keyUrl] = expires + '\t' + finalUrl; setTimeout(() => { [keyUrl, keyFinalUrl, keyFinalUrl + '\thtml'].forEach(e => localStorage.removeItem(e)); }, cacheDuration + 1000); } function cleanupCache({aggressive = false} = {}) { Object.keys(localStorage).forEach(k => { if (k.match(/^https?:\/\/[^\t]+$/)) { let meta = (localStorage[k] || '').split('\t'); if (+meta[0] > Date.now() && !aggressive) return; if (meta[1]) localStorage.removeItem(meta[1]); localStorage.removeItem(`${meta[1] || k}\thtml`); localStorage.removeItem(k); } }); } function onFrameReady(frame) { if (frame.contentDocument.readyState == 'complete') return Promise.resolve(); else return new Promise(resolve => { $on('load', frame, function onLoad() { $off('load', frame, onLoad); resolve(); }); }); } function onStyleSheetsReady(linkElements) { let retryCount = 0; return new Promise(function retry(resolve) { if (linkElements.every(e => e.sheet && e.sheet.href == e.href)) resolve(); else if (retryCount++ > 10) resolve(); else setTimeout(retry, 0, resolve); }); } function getURLregexForMatchedSites() { return new RegExp('https?://(\\w*\\.)*(' + GM_info.script.matches.map(m => m.match(/^.*?\/\/\W*(\w.*?)\//)[1].replace(/\./g, '\\.') ).join('|') + ')/(questions|q|a|posts\/comments)/\\d+'); } function isLinkPreviewable(link) { if (!rxPreviewable.test(link.href) || link.matches('.short-link')) return false; const inPreview = preview.frame && link.ownerDocument == preview.frame.contentDocument; const pageUrls = inPreview ? getPageBaseUrls(preview.link.href) : thisPageUrls; const url = httpsUrl(link.href); return url.indexOf(pageUrls.base) && url.indexOf(pageUrls.short); } function getPageBaseUrls(url) { const base = httpsUrl((url.match(rxPreviewable) || [])[0]); return base ? { base, short: base.replace('/questions/', '/q/'), } : {}; } function httpsUrl(url) { return (url || '').replace(/^http:/, 'https:'); } function $(selector, node = document) { return node.querySelector(selector); } function $$(selector, node = document) { return node.querySelectorAll(selector); } function $text(selector, node = document) { const e = typeof selector == 'string' ? node.querySelector(selector) : selector; return e ? e.textContent.trim() : ''; } function $$remove(selector, node = document) { node.querySelectorAll(selector).forEach(e => e.remove()); } function $appendChildren(newParent, elements) { const doc = newParent.ownerDocument; const fragment = doc.createDocumentFragment(); for (let e of elements) if (e) fragment.appendChild(e.ownerDocument == doc ? e : doc.importNode(e, true)); newParent.appendChild(fragment); } function $removeChildren(el) { if (el.children.length) el.innerHTML = ''; // the fastest as per https://jsperf.com/innerhtml-vs-removechild/256 } function $replaceOrCreate(options) { if (typeof options.map == 'function') return options.map($replaceOrCreate); const doc = (options.parent || options.before).ownerDocument; const el = doc.getElementById(options.id) || doc.createElement(options.tag || 'div'); for (let key of Object.keys(options)) { const value = options[key]; switch (key) { case 'tag': case 'parent': case 'before': break; case 'dataset': for (let dataAttr of Object.keys(value)) if (el.dataset[dataAttr] != value[dataAttr]) el.dataset[dataAttr] = value[dataAttr]; break; case 'children': $removeChildren(el); $appendChildren(el, options[key]); break; default: if (key in el && el[key] != value) el[key] = value; } } if (!el.parentElement) (options.parent || options.before.parentElement).insertBefore(el, options.before); return el; } function $scriptIn(element) { return element.appendChild(element.ownerDocument.createElement('script')); } function $on(eventName, ...args) { // eventName, selector, node, callback, options // eventName, selector, callback, options // eventName, node, callback, options // eventName, callback, options const selector = typeof args[0] == 'string' ? args[0] : null; const node = args[0].nodeType ? args[0] : args[1].nodeType ? args[1] : document; const callback = args[typeof args[0] == 'function' ? 0 : typeof args[1] == 'function' ? 1 : 2]; const options = args[args.length - 1] != callback ? args[args.length - 1] : undefined; const method = this == 'removeEventListener' ? this : 'addEventListener'; (selector ? node.querySelector(selector) : node)[method](eventName, callback, options); } function $off(eventName, ...args) { $on.apply('removeEventListener', arguments); } function hasKeyModifier(e) { return e.ctrlKey || e.altKey || e.shiftKey || e.metaKey; } function log(...args) { console.log(GM_info.script.name, ...args); } function error(...args) { console.error(GM_info.script.name, ...args); } function tryCatch(fn) { try { return fn() } catch(e) {} } function initPolyfills(context = window) { for (let method of ['forEach', 'filter', 'map', 'every', context.Symbol.iterator]) if (!context.NodeList.prototype[method]) context.NodeList.prototype[method] = context.Array.prototype[method]; } function initStyles() { GM_addStyle(` #SEpreview { all: unset; box-sizing: content-box; width: 720px; /* 660px + 30px + 30px */ height: 33%; min-height: 400px; position: fixed; opacity: 0; transition: opacity .25s cubic-bezier(.88,.02,.92,.66); right: 0; bottom: 0; padding: 0; margin: 0; background: white; box-shadow: 0 0 100px rgba(0,0,0,0.5); z-index: 999999; border-width: 8px; border-style: solid; } ` + Object.keys(COLORS).map(s => ` #SEpreview[SEpreview-type="${s}"] { border-color: rgb(${COLORS[s].backRGB}); } `).join('') ); preview.stylesOverride = ` body, html { min-width: unset!important; box-shadow: none!important; padding: 0!important; margin: 0!important; } html, body { background: unset!important;; } body { display: flex; flex-direction: column; height: 100vh; } #SEpreview-body a.SEpreviewable { text-decoration: underline !important; } #SEpreview-title { all: unset; display: block; padding: 20px 30px; font-weight: bold; font-size: 18px; line-height: 1.2; cursor: pointer; } #SEpreview-title:hover { text-decoration: underline; } #SEpreview-meta { position: absolute; top: .5ex; left: 30px; opacity: 0.5; } #SEpreview-title:hover + #SEpreview-meta { opacity: 1.0; } #SEpreview-close { position: absolute; top: 0; right: 0; flex: none; cursor: pointer; padding: .5ex 1ex; } #SEpreview-close:after { content: "x"; } #SEpreview-close:active { background-color: rgba(0,0,0,.1); } #SEpreview-close:hover { background-color: rgba(0,0,0,.05); } #SEpreview-body { padding: 30px!important; overflow: auto; flex-grow: 2; } #SEpreview-body > .question-status { margin: -30px -30px 30px; padding-left: 30px; } #SEpreview-body .question-originals-of-duplicate { margin: -30px -30px 30px; padding: 15px 30px; } #SEpreview-body > .question-status h2 { font-weight: normal; } #SEpreview-answers { all: unset; display: block; padding: 10px 10px 10px 30px; font-weight: bold; line-height: 1.0; border-top: 4px solid rgba(${COLORS.answer.backRGB}, 0.37); background-color: rgba(${COLORS.answer.backRGB}, 0.37); color: ${COLORS.answer.fore}; word-break: break-word; } #SEpreview-answers:before { content: "Answers:"; margin-right: 1ex; font-size: 20px; line-height: 48px; } #SEpreview-answers a { color: ${COLORS.answer.fore}; text-decoration: none; font-size: 11px; font-family: monospace; width: 32px; display: inline-block; vertical-align: top; margin: 0 1ex 1ex 0; } #SEpreview-answers img { width: 32px; height: 32px; } .SEpreview-accepted { position: relative; } .SEpreview-accepted:after { content: "✔"; position: absolute; display: block; top: 1.3ex; right: -0.7ex; font-size: 32px; color: #4bff2c; text-shadow: 1px 2px 2px rgba(0,0,0,0.5); } #SEpreview-answers a.deleted-answer { color: ${COLORS.deleted.fore}; background: transparent; opacity: 0.25; } #SEpreview-answers a.deleted-answer:hover { opacity: 1.0; } #SEpreview-answers a:hover:not(.SEpreviewed) { text-decoration: underline; } #SEpreview-answers a.SEpreviewed { background-color: ${COLORS.answer.fore}; color: ${COLORS.answer.foreInv}; position: relative; } #SEpreview-answers a.SEpreviewed:after { display: block; content: " "; position: absolute; left: -4px; top: -4px; right: -4px; bottom: -4px; border: 4px solid ${COLORS.answer.fore}; } .comment-edit, .delete-tag, .comment-actions td:last-child { display: none; } .comments { border-top: none; } .comments tr:last-child td { border-bottom: none; } .comments .new-comment-highlight { -webkit-animation: highlight 9s cubic-bezier(0,.8,.37,.88); -moz-animation: highlight 9s cubic-bezier(0,.8,.37,.88); animation: highlight 9s cubic-bezier(0,.8,.37,.88); } .post-menu > span { opacity: .35; } .user-info { position: relative; } #user-menu { position: absolute; } .SEpreview-user { position: absolute; right: -1em; top: -2em; transition: opacity .25s ease-in-out; opacity: 0; display: none; } @-webkit-keyframes highlight { from {background-color: #ffcf78} to {background-color: none} } ` + Object.keys(COLORS).map(s => ` body[SEpreview-type="${s}"] #SEpreview-title { background-color: rgba(${COLORS[s].backRGB}, 0.37); color: ${COLORS[s].fore}; } body[SEpreview-type="${s}"] #SEpreview-body::-webkit-scrollbar { background-color: rgba(${COLORS[s].backRGB}, 0.1); } body[SEpreview-type="${s}"] #SEpreview-body::-webkit-scrollbar-thumb { background-color: rgba(${COLORS[s].backRGB}, 0.2); } body[SEpreview-type="${s}"] #SEpreview-body::-webkit-scrollbar-thumb:hover { background-color: rgba(${COLORS[s].backRGB}, 0.3); } body[SEpreview-type="${s}"] #SEpreview-body::-webkit-scrollbar-thumb:active { background-color: rgba(${COLORS[s].backRGB}, 0.75); } `).join('') + ['deleted', 'closed'].map(s => ` body[SEpreview-type="${s}"] #SEpreview-answers { border-top-color: rgba(${COLORS[s].backRGB}, 0.37); background-color: rgba(${COLORS[s].backRGB}, 0.37); color: ${COLORS[s].fore}; } body[SEpreview-type="${s}"] #SEpreview-answers a.SEpreviewed { background-color: ${COLORS[s].fore}; color: ${COLORS[s].foreInv}; } body[SEpreview-type="${s}"] #SEpreview-answers a.SEpreviewed:after { border-color: ${COLORS[s].fore}; } `).join(''); }