├── .gitignore ├── LICENSE ├── README.md ├── background.js ├── content.js ├── manifest.json ├── pack.sh ├── pictures └── screenshot.png └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | --------------------- 3 | 4 | Copyright (c) 2022 Johann Bach 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | of the Software, and to permit persons to whom the Software is furnished to do 11 | so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hacker-News-Highlighter 2 | 3 | Chrome Extension to enhance your Hacker News experience: On each reload of the front page, newly added headlines are clearly highlighted. Articles with a high number of comments are easily spotted with comment counts emphasized. Additionally, article and comment links now open in new windows, ensuring seamless browsing without losing your place. 4 | 5 | ![Screenshot](pictures/screenshot.png) 6 | 7 | 8 | #### Install from Chrome Web Store: 9 | https://chromewebstore.google.com/detail/hacker-news-highlighter/nmaemcgldingcfpokpkpchomnjcnachl 10 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | globalThis.browser ??= chrome; 2 | browser.runtime.onInstalled.addListener(() => { 3 | browser.storage.local.set({ seenArticles: [] }); 4 | }); 5 | function updateSeenArticles(tab) { 6 | if (tab && tab.url && tab.url.endsWith("news.ycombinator.com/news")) { 7 | browser.scripting.executeScript( 8 | { 9 | target: { tabId: tab.id }, 10 | func: storeCurrentArticles 11 | } 12 | ); 13 | } 14 | } 15 | browser.tabs.onActivated.addListener(activeInfo => { 16 | browser.tabs.get(activeInfo.tabId, tab => { 17 | updateSeenArticles(tab); 18 | }); 19 | }); 20 | browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { 21 | if (changeInfo.status === 'complete') { 22 | updateSeenArticles(tab); 23 | } 24 | }); 25 | function storeCurrentArticles() { 26 | const articleIds = Array.from(document.querySelectorAll('.athing')).map(article => article.id); 27 | browser.storage.local.set({ seenArticles: articleIds }); 28 | } 29 | -------------------------------------------------------------------------------- /content.js: -------------------------------------------------------------------------------- 1 | globalThis.browser ??= chrome; 2 | 3 | (function() { 4 | const HIGHLIGHT_CLASS = 'highlight-new-article'; 5 | browser.storage.local.get('seenArticles', data => { 6 | const seenArticles = data.seenArticles || []; 7 | const currentArticles = Array.from(document.querySelectorAll('.athing')); 8 | currentArticles.forEach(article => { 9 | const articleId = article.id; 10 | if (!seenArticles.includes(articleId)) { 11 | article.classList.add(HIGHLIGHT_CLASS); 12 | } 13 | const nextRow = article.nextElementSibling; 14 | if (nextRow) { 15 | const subtextElement = nextRow.querySelector('td.subtext'); 16 | if (subtextElement) { 17 | if (subtextElement && subtextElement.innerText.includes('comment')) { 18 | const commentElement = Array.from(subtextElement.querySelectorAll('a')) 19 | .find(a => a.innerText.includes('comment')); 20 | const commentText = commentElement.innerText; 21 | const match = commentText.match(/(\d+)\s*comments?/); 22 | if (match) { 23 | const commentCount = parseInt(match[1], 10); 24 | let commentColor = ''; 25 | if (commentCount > 50) { 26 | let transparency = 0.0 + commentCount * 0.3 / 200.0; 27 | commentColor = 'rgba(255,0,0, ' + transparency + ')'; 28 | if (commentColor) { 29 | commentElement.style.backgroundColor = commentColor; 30 | if (commentCount > 200) { 31 | commentElement.style.color = 'white'; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | }); 40 | const currentArticleIds = currentArticles.map(article => article.id); 41 | browser.storage.local.set({ seenArticles: currentArticleIds }); 42 | }); 43 | 44 | // Make all links open in a new tab 45 | const allLinks = document.querySelectorAll('a'); 46 | allLinks.forEach(link => { 47 | link.setAttribute('target', '_blank'); 48 | }); 49 | 50 | })(); 51 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Hacker News Highlighter", 4 | "version": "1.1", 5 | "description": "Highlight new articles on Hacker News since the last visit and highly commented articles.", 6 | "permissions": [ 7 | "storage", 8 | "activeTab", 9 | "scripting" 10 | ], 11 | "background": { 12 | "scripts": ["background.js"], 13 | "service_worker": "background.js" 14 | }, 15 | "content_scripts": [ 16 | { 17 | "matches": ["https://news.ycombinator.com/news"], 18 | "js": ["content.js"], 19 | "css": ["styles.css"] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /pack.sh: -------------------------------------------------------------------------------- 1 | zip -r hackernewshighlighter.zip * -x "pictures/*" "pictures" -x "pack.sh" -x "README.md" 2 | -------------------------------------------------------------------------------- /pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bachmitre/hacker-news-highlighter/ff96892423332c15b68a776e404a6c0cff4847c5/pictures/screenshot.png -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .highlight-new-article { 2 | background-color: #ffffd4; /* Light yellow background */ 3 | } 4 | --------------------------------------------------------------------------------