你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式
(我已經安裝了使用者樣式管理器,讓我安裝!)
// ==UserScript==
// @name Enhanced Hacker News UI
// @namespace http://tampermonkey.net/
// @version 2.1
// @description Enhance Hacker News with better visual hierarchy and typography
// @author mcnaveen <https://github.com/mcnaveen>
// @match https://news.ycombinator.com/*
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function() {
'use strict';
GM_addStyle(`
/* Center layout with max width */
body {
max-width: 1000px !important;
margin: 0 auto !important;
padding: 0 20px !important;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
}
/* Main table centering */
body > center {
width: 100% !important;
}
body > center > table {
width: 100% !important;
max-width: 1000px !important;
margin: 0 auto !important;
}
/* Dark mode toggle button */
#dark-mode-toggle {
position: fixed;
top: 10px;
right: 10px;
background: #ff6600;
color: white;
border: none;
padding: 10px 15px;
border-radius: 6px;
cursor: pointer;
z-index: 1000;
font-size: 14px;
font-weight: 500;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
#dark-mode-toggle:hover {
background: #e55a00;
}
/* Improved dark mode - softer colors */
body.dark-mode {
background-color: #0d1117 !important;
color: #c9d1d9 !important;
}
body.dark-mode table {
background-color: #0d1117 !important;
}
body.dark-mode .pagetop {
background-color: #161b22 !important;
border-bottom: 1px solid #30363d !important;
}
body.dark-mode .storylink {
color: #58a6ff !important;
font-weight: 700 !important;
}
body.dark-mode .storylink:visited {
color: #bc8cff !important;
}
body.dark-mode .storylink:hover {
color: #79c0ff !important;
}
body.dark-mode .hnuser {
color: #7ee787 !important;
}
body.dark-mode .comment {
color: #c9d1d9 !important;
}
body.dark-mode .subtext {
color: #8b949e !important;
}
body.dark-mode .subtext a {
color: #8b949e !important;
}
body.dark-mode .subtext a:hover {
color: #c9d1d9 !important;
}
body.dark-mode .score {
color: #7ee787 !important;
}
body.dark-mode .hnmore a {
color: #58a6ff !important;
}
/* ENHANCED VISUAL HIERARCHY */
/* Story titles - MUCH BIGGER */
.storylink {
font-size: 32px !important;
line-height: 1.4 !important;
font-weight: 700 !important;
text-decoration: none !important;
display: block !important;
margin-bottom: 8px !important;
color: #1a1a1a !important;
}
.storylink:hover {
text-decoration: underline !important;
color: #ff6600 !important;
}
.storylink:visited {
color: #666 !important;
}
/* Metadata - MUCH SMALLER */
.subtext {
font-size: 11px !important;
line-height: 1.3 !important;
margin-top: 4px !important;
margin-bottom: 20px !important;
color: #828282 !important;
font-weight: 400 !important;
}
.subtext a {
font-weight: 500 !important;
color: #828282 !important;
text-decoration: none !important;
}
.subtext a:hover {
color: #ff6600 !important;
text-decoration: underline !important;
}
/* Score styling - smaller and subtle */
.score {
font-weight: 600 !important;
font-size: 11px !important;
color: #ff6600 !important;
}
/* Username styling */
.hnuser {
font-weight: 500 !important;
color: #666 !important;
}
/* Better spacing for stories */
.athing {
margin-bottom: 24px !important;
padding: 0 !important;
border-bottom: 1px solid #f0f0f0 !important;
padding-bottom: 16px !important;
}
body.dark-mode .athing {
border-bottom-color: #30363d !important;
}
/* Story rank number */
.rank {
font-size: 11px !important;
color: #999 !important;
font-weight: 500 !important;
width: 30px !important;
padding-right: 8px !important;
}
/* Better comment font size */
.comment {
font-size: 15px !important;
line-height: 1.6 !important;
}
/* Navigation improvements */
.pagetop {
padding: 12px 0 !important;
font-size: 14px !important;
position: sticky !important;
top: 0 !important;
z-index: 100 !important;
background: #f6f6ef !important;
margin-bottom: 20px !important;
border-bottom: 1px solid #e6e6e6 !important;
}
.pagetop a {
font-weight: 500 !important;
margin-right: 12px !important;
}
/* Domain highlighting - smaller and more subtle */
.domain-highlight {
background: rgba(255, 102, 0, 0.08);
color: #ff6600;
padding: 2px 5px;
border-radius: 3px;
font-size: 10px;
font-weight: 600;
margin-left: 6px;
border: 1px solid rgba(255, 102, 0, 0.15);
text-transform: uppercase;
letter-spacing: 0.5px;
}
body.dark-mode .domain-highlight {
background: rgba(255, 102, 0, 0.15);
color: #ff9500;
border-color: rgba(255, 102, 0, 0.3);
}
/* Improved vote arrows */
.votelinks {
padding-right: 8px !important;
}
.votelinks a {
opacity: 0.7;
transition: opacity 0.2s, transform 0.2s;
}
.votelinks a:hover {
opacity: 1;
transform: scale(1.1);
}
/* Better comment threading */
.comment-thread {
border-left: 3px solid #e1e4e8;
margin-left: 15px;
padding-left: 15px;
}
body.dark-mode .comment-thread {
border-left-color: #30363d;
}
/* Reading time indicator - very small */
.reading-time {
font-size: 10px;
color: #999;
margin-left: 6px;
font-weight: 600;
background: rgba(0,0,0,0.04);
padding: 1px 4px;
border-radius: 2px;
text-transform: uppercase;
letter-spacing: 0.3px;
}
body.dark-mode .reading-time {
color: #8b949e;
background: rgba(255,255,255,0.05);
}
/* More link styling */
.hnmore {
text-align: center !important;
padding: 20px 0 !important;
}
.hnmore a {
font-size: 16px !important;
font-weight: 500 !important;
padding: 10px 20px !important;
background: #ff6600 !important;
color: white !important;
text-decoration: none !important;
border-radius: 6px !important;
transition: background 0.2s !important;
}
.hnmore a:hover {
background: #e55a00 !important;
}
body.dark-mode .hnmore a {
background: #ff6600 !important;
}
body.dark-mode .hnmore a:hover {
background: #ff7700 !important;
}
/* Responsive adjustments */
@media (max-width: 768px) {
body {
padding: 0 15px !important;
}
.storylink {
font-size: 20px !important;
}
.subtext {
font-size: 10px !important;
}
.rank {
font-size: 10px !important;
}
}
@media (max-width: 480px) {
.storylink {
font-size: 18px !important;
}
}
.title {
font-size: 16px !important;
padding: 10px 0;
}
/* Fix for title containers */
.titleline {
margin-bottom: 6px !important;
}
/* Adjust spacing between elements */
.athing .rank,
.athing .votelinks,
.athing .titleline {
vertical-align: top !important;
}
`);
// Dark mode functionality
function initDarkMode() {
const darkModeToggle = document.createElement('button');
darkModeToggle.id = 'dark-mode-toggle';
darkModeToggle.textContent = '🌙 Dark';
document.body.appendChild(darkModeToggle);
// Load saved preference
const isDark = localStorage.getItem('hn-dark-mode') === 'true';
if (isDark) {
document.body.classList.add('dark-mode');
darkModeToggle.textContent = '☀️ Light';
}
darkModeToggle.addEventListener('click', function() {
document.body.classList.toggle('dark-mode');
const isDarkMode = document.body.classList.contains('dark-mode');
darkModeToggle.textContent = isDarkMode ? '☀️ Light' : '🌙 Dark';
localStorage.setItem('hn-dark-mode', isDarkMode);
});
}
// Add domain highlighting
function highlightDomains() {
const links = document.querySelectorAll('.storylink');
links.forEach(link => {
if (link.href && !link.querySelector('.domain-highlight')) {
const url = new URL(link.href);
const domain = url.hostname.replace('www.', '');
// Add domain badge for external links
if (!domain.includes('ycombinator.com') && !domain.includes('news.ycombinator.com')) {
const domainSpan = document.createElement('span');
domainSpan.className = 'domain-highlight';
domainSpan.textContent = domain;
link.parentNode.appendChild(domainSpan);
}
}
});
}
// Add reading time estimates
function addReadingTime() {
const storyRows = document.querySelectorAll('.subtext');
storyRows.forEach(row => {
if (!row.querySelector('.reading-time')) {
const commentsLink = row.querySelector('a[href*="item?id="]');
if (commentsLink && commentsLink.textContent.includes('comment')) {
const commentsText = commentsLink.textContent;
const commentsMatch = commentsText.match(/(\d+)\s+comment/);
if (commentsMatch) {
const commentCount = parseInt(commentsMatch[1]);
const readingTime = Math.max(1, Math.round(commentCount / 8));
const timeSpan = document.createElement('span');
timeSpan.className = 'reading-time';
timeSpan.textContent = `${readingTime}min`;
commentsLink.parentNode.appendChild(timeSpan);
}
}
}
});
}
// Improve comment threading
function enhanceCommentThreading() {
const comments = document.querySelectorAll('.comment');
comments.forEach(comment => {
if (!comment.classList.contains('comment-thread')) {
const indent = comment.querySelector('img[src="s.gif"]');
if (indent && indent.width > 0) {
comment.classList.add('comment-thread');
}
}
});
}
// Keyboard shortcuts
function addKeyboardShortcuts() {
document.addEventListener('keydown', function(e) {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
switch(e.key) {
case 'j':
e.preventDefault();
navigateStory('next');
break;
case 'k':
e.preventDefault();
navigateStory('prev');
break;
case 'o':
e.preventDefault();
openCurrentStory();
break;
case 'c':
e.preventDefault();
openCurrentComments();
break;
case 'd':
e.preventDefault();
document.getElementById('dark-mode-toggle').click();
break;
}
});
}
let currentStoryIndex = 0;
function navigateStory(direction) {
const stories = document.querySelectorAll('.athing');
if (stories.length === 0) return;
stories.forEach(story => story.style.backgroundColor = '');
if (direction === 'next') {
currentStoryIndex = (currentStoryIndex + 1) % stories.length;
} else {
currentStoryIndex = (currentStoryIndex - 1 + stories.length) % stories.length;
}
const currentStory = stories[currentStoryIndex];
currentStory.style.backgroundColor = 'rgba(255, 102, 0, 0.05)';
currentStory.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
function openCurrentStory() {
const stories = document.querySelectorAll('.athing');
if (stories[currentStoryIndex]) {
const link = stories[currentStoryIndex].querySelector('.storylink');
if (link) {
window.open(link.href, '_blank');
}
}
}
function openCurrentComments() {
const stories = document.querySelectorAll('.athing');
if (stories[currentStoryIndex]) {
const nextRow = stories[currentStoryIndex].nextElementSibling;
if (nextRow) {
const commentsLink = nextRow.querySelector('a[href*="item?id="]');
if (commentsLink && commentsLink.textContent.includes('comment')) {
window.open(commentsLink.href, '_blank');
}
}
}
}
// Initialize all enhancements
function init() {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
return;
}
initDarkMode();
highlightDomains();
addReadingTime();
enhanceCommentThreading();
addKeyboardShortcuts();
// Re-run enhancements for dynamic content
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length > 0) {
setTimeout(() => {
highlightDomains();
addReadingTime();
enhanceCommentThreading();
}, 100);
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
init();
})();