🏠 Home 

myhackernews

Apply a dark theme to Hacker News, modify navigation links, and add a custom menu with highlighted active links

// ==UserScript==
// @name         myhackernews
// @namespace    https://github.com/jeanlucaslima/myhackernews/
// @version      3.1.1
// @description  Apply a dark theme to Hacker News, modify navigation links, and add a custom menu with highlighted active links
// @license      MIT
// @copyright    jeanlucaslima
// @author       jeanlucaslima
// @homepageURL  https://github.com/jeanlucaslima/myhackernews/
// @supportURL   https://github.com/jeanlucaslima/myhackernews/issues
// @match        https://news.ycombinator.com/*
// @grant        none
// ==/UserScript==
(function() {
'use strict';
// Theme definitions
const themes = {
darkNavy: {
dark: true,
'--background-color': '#1a202c',
'--table-background-color': '#2d3848',
'--text-color': '#dddddd',
'--link-color': '#9facbe',
'--pagetop-background-color': '#2d3848',
'--pagetop-text-color': '#9facbe',
'--hnname-color': '#bb86fc',
'--title-link-color': '#ededed',
'--title-link-visited-color': '#7fe0d4',
'--subtext-link-color': '#c8d2dc',
'--itemlist-even-bg-color': '#1c1c1c',
'--itemlist-odd-bg-color': '#121212',
'--c00-color': '#c8d2dc',
'--active-link-color': '#ff4500'
},
blackTheme: {
dark: true,
'--background-color': '#1f1f1f',
'--table-background-color': '#1f1f1f',
'--text-color': '#e0e0e0',
'--link-color': '#828282',
'--pagetop-background-color': '#1f1f1f',
'--pagetop-text-color': '#828282',
'--hnname-color': '#bb86fc',
'--title-link-color': '#ededed',
'--title-link-visited-color': '#868686',
'--subtext-link-color': '#03dac6',
'--itemlist-even-bg-color': '#1c1c1c',
'--itemlist-odd-bg-color': '#121212',
'--c00-color': '#ededed',
'--active-link-color': '#ff6600'
}
};
// Function to generate CSS rules from theme object
function generateCSS(theme) {
return `
:root {
color-scheme: ${theme.dark ? 'dark' : 'light'};
}
body, tbody {
background-color: ${theme['--background-color']};
color: ${theme['--text-color']};
}
a {
color: ${theme['--link-color']};
}
a:link {
color: ${theme['--link-color']};
}
.pagetop {
background-color: ${theme['--pagetop-background-color']};
padding: 0;
color: ${theme['--pagetop-text-color']};
}
.pagetop a {
color: ${theme['--pagetop-text-color']};
}
.pagetop a:visited {
color: ${theme['--pagetop-text-color']};
}
.hnname a {
color: ${theme['--hnname-color']};
}
td {
background-color: ${theme['--table-background-color']};
}
td.title a {
color: ${theme['--title-link-color']};
}
td.title a:visited {
color: ${theme['--title-link-visited-color']};
}
.subtext a {
color: ${theme['--subtext-link-color']};
}
.itemlist tr:nth-child(even) td {
background-color: ${theme['--itemlist-even-bg-color']};
}
.itemlist tr:nth-child(odd) td {
background-color: ${theme['--itemlist-odd-bg-color']};
}
table {
background-color: ${theme['--table-background-color']} !important;
}
.c00, .c00 a:link { color: ${theme['--c00-color']}; }
.menu a.active {
color: ${theme['--active-link-color']};
font-weight: bold;
}
`;
}
// Function to apply the theme
function applyTheme(themeName) {
const theme = themes[themeName];
const style = document.createElement('style');
style.textContent = generateCSS(theme);
document.head.appendChild(style);
}
// Function to create and append new link
function createLink(container, text, href) {
const link = document.createElement('a');
link.href = href;
link.textContent = text;
// we use link.pathname to not mix with the queries when adding active status
if (link.pathname === window.location.pathname) {
link.classList.add('active');
}
if (container.childNodes.length === 1) {
container.appendChild(document.createTextNode(' '));
}
if (container.childNodes.length > 2) {
container.appendChild(document.createTextNode(' | '));
}
container.appendChild(link);
}
// Function to build the menu
function buildMenu(container, userId) {
createLink(container, 'Hacker News', '/');
createLink(container, 'active', '/active');
createLink(container, 'best', '/best');
createLink(container, 'threads', `/threads?id=${userId}`);
createLink(container, 'ask', '/ask');
createLink(container, 'show', '/show');
createLink(container, 'past', '/front');
createLink(container, 'submit', '/submit');
}
// Function to modify the navigation links
function modifyNav() {
const pagetop = document.querySelector('.pagetop');
if (pagetop) {
// Find the user id for the threads link before clearing pagetop
const userLink = pagetop.querySelector('a[href^="threads?id="]');
const userId = userLink ? userLink.getAttribute('href').split('=')[1] : '';
pagetop.innerHTML = ''; // Clear existing links
pagetop.classList.add('menu');
buildMenu(pagetop, userId);
}
}
// Function to add the theme switcher
function addThemeSwitcher() {
const switcherSpan = document.createElement('span');
const bottomContainer = document.querySelector('.yclinks');
switcherSpan.className = 'theme_switcher';
switcherSpan.style.display = 'block';
switcherSpan.style.marginTop = '10px';
const select = document.createElement('select');
select.innerHTML = `
<option value="darkNavy">Deep Navy</option>
<option value="blackTheme">Black</option>
`;
select.value = localStorage.getItem('hn-theme') || 'darkNavy';
select.addEventListener('change', () => {
const selectedTheme = select.value;
localStorage.setItem('hn-theme', selectedTheme);
applyTheme(selectedTheme);
});
switcherSpan.appendChild(document.createTextNode('Theme: '));
switcherSpan.appendChild(select);
bottomContainer.appendChild(switcherSpan);
}
// Apply the saved theme on load
const savedTheme = localStorage.getItem('hn-theme') || 'darkNavy';
console.log(savedTheme);
applyTheme(savedTheme);
// Modify navigation and add theme switcher
modifyNav();
addThemeSwitcher();
})();