您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
add rainbow indent guides, favicons, profile icons and more to hacker news
// ==UserScript== // @name Hacker News Enhanced // @namespace http://tampermonkey.net/ // @version 1.1.2 // @description add rainbow indent guides, favicons, profile icons and more to hacker news // @author Lynnesbian // @homepage https://git.bune.city/lynnesbian/hn-enhanced // @match https://news.ycombinator.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=ycombinator.com // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jdenticon.js#sha256=faa3d839565eed77d74b677f86d218977685f6f9515e2c3c86943802ca8c4a27 // @grant GM_addStyle // @grant GM_addElement // @sandbox DOM // @license Apache-2.0 // ==/UserScript== (function() { 'use strict'; // h/t https://stackoverflow.com/a/54935305 const COLOURS = new Array(3).fill(["grey", "red", "orange", "#fc0", "green", "blue", "purple"]).flat(); const WIDTH_FACTOR = 6; let stylesheet = ` table.comment-tree, table.comment-tree table { border-collapse: collapse; } table.comment-tree { margin-top: -10px; } table.comment-tree td { padding: 0; } table.comment-tree td:not(.ind) { padding: 0 2px; } td.ind > img { display: none; } .comment { margin-bottom: 4px; } /* gap between comments */ .comtr table:has(td.ind[indent="0"]) { margin-top: 10px; } a:link.hnuser, a:visited.hnuser { color: #333; } .jdenticon-holder { display: inline-block; vertical-align: middle; margin-left: -3px; margin-top: -1px; background: #f6f6ef; } .jdenticon-holder.comments { margin-right: 1px; } .pagetop .jdenticon-holder { margin-right: 3px; margin-bottom: -1px; } .title-favicon { vertical-align: bottom; margin-right: 4px; margin-bottom: 1px; } @media only screen and (min-width: 300px) and (max-width: 750px) { .title-favicon { vertical-align: top; margin-top: 2px; } } `; let tree = document.getElementsByClassName("comment-tree"); const in_comments = tree.length !== 0; // are we on the comments page? (/item?id=xyz) const icon_size = in_comments ? 20 : 16; if (in_comments) { // remove top margin from first comment tree[0].getElementsByTagName("table")[0].style.marginTop = "0px"; // generate rainbow indent guides for (let indent = 0; indent < COLOURS.length; indent++) { // for each level of indent stylesheet += `td.ind[indent="${indent}"] { width: ${(indent + 1) * WIDTH_FACTOR}px; `; let gradient = "linear-gradient(to right, " for (let colour_depth = 0; colour_depth <= indent; colour_depth++) { // for each colour, up to and including the current indent level let colour = COLOURS[colour_depth]; let start = colour_depth * WIDTH_FACTOR; let end = start + 2; gradient += `transparent ${start}px, ${colour} ${start}px, ${colour} ${end}px, transparent ${end}px, ` } gradient += "transparent 100%);" stylesheet += `background-image: ${gradient}}\n`; } } else { // front page logic // make scores bold for (let score of document.getElementsByClassName("score")) { score.innerHTML = `<strong>${score.innerText.split(" ")[0]}</strong> points`; } } // add favicons for (let title of document.getElementsByClassName("titleline")) { let domain = title.getElementsByClassName("sitestr"); if (domain.length === 0) { domain = "news.ycombinator.com"; } else { domain = domain[0].innerText.split('/')[0]; } let icon = GM_addElement("img", { src: `https://icons.duckduckgo.com/ip3/${domain}.ico`, height: "14", width: "14", }); icon.className = "title-favicon"; title.prepend(icon); } // add additional links to news items let subtexts = document.getElementsByClassName("subtext"); for (let subtext of subtexts) { // warning: :( try { // because this fails for the "XYZ is hiring" ads const story_url = subtext .parentElement .previousElementSibling .getElementsByClassName("titleline")[0] .getElementsByTagName("a")[0] .href; let subline = subtext.children[0]; let links = document.createElement("span"); links.append(" | "); let archive = document.createElement("a"); archive.href = `https://web.archive.org/web/2/${story_url}`; archive.innerText = "archive"; links.append(archive); links.append(" | "); let reddit = document.createElement("a"); reddit.href = `https://www.reddit.com/search/?q=url:%22${story_url}%22`; reddit.innerText = "reddit"; links.append(reddit); if (in_comments) { subline.getElementsByClassName("hnpast")[0].after(links); } else { subline.getElementsByClassName("hider")[0].after(links); } } catch (error) { // :3 } } GM_addStyle(stylesheet); // set up jdenticon icons let user_elements = Array.from(document.getElementsByClassName("hnuser")); let usernames = new Set(user_elements.map((user) => user.innerText)); for (let username of usernames) { let elements = user_elements.filter((user) => user.innerText == username); for (let element of elements) { // add to <a> let icon = document.createElement("span"); icon.className = in_comments ? "jdenticon-holder comments" : "jdenticon-holder"; element.innerHTML = ""; icon.innerHTML = jdenticon.toSvg(username, icon_size); element.appendChild(icon); element.innerHTML += username; } } // add your icon! let pagetop = document.getElementsByClassName("pagetop")[1]; let me = document.getElementById("me"); if (me !== null) { const username = me.innerText; let icon = document.createElement("span"); icon.className = "jdenticon-holder"; icon.innerHTML = jdenticon.toSvg(username, 16); pagetop.prepend(icon); } // add link to footer let yclinks = document.getElementsByClassName("yclinks")[0]; yclinks.append(" | "); let enhanced = document.createElement("a"); enhanced.href = "https://git.bune.city/lynnesbian/hn-enhanced"; enhanced.innerText = "HN Enhanced"; yclinks.append(enhanced); })(); jdenticon();