Legible Hacker News

Hacker News Legible Like Newspaper

目前为 2024-03-20 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Legible Hacker News
  3. // @namespace http://tampermonkey.net/
  4. // @version 1
  5. // @description Hacker News Legible Like Newspaper
  6. // @author CK Keller (fork)
  7. // @author Martin Gladdish (original)
  8. // @match https://news.ycombinator.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=ycombinator.com
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. const tampermonkeyScript = function() {
  14. 'use strict';
  15.  
  16. document.head.insertAdjacentHTML("beforeend", `<style>
  17. :root {
  18. --colour-hn-orange: #ff6600;
  19. --colour-hn-orange-pale: rgba(255, 102, 0, 0.05);
  20. --gutter: 0.5rem;
  21. --border-radius: 3px;
  22. }
  23.  
  24. /* Reset font everywhere */
  25. html, body, td, .title, .comment, .default {
  26. font-family: 'Verdana', 'Arial', sans-serif;
  27. font-size: 1.2rem;
  28. }
  29.  
  30. html, body {
  31. margin-top: 0;
  32. margin-left: 0;
  33. }
  34.  
  35. body {
  36. padding: 5;
  37. margin: 5;
  38. }
  39.  
  40. body, td, .title, .pagetop, .comment {
  41. font-size: 1.0rem;
  42. }
  43.  
  44. .votelinks, html[op='news'] .title {
  45. vertical-align: inherit;
  46. }
  47.  
  48. .comment-tree .votelinks,
  49. html[op='threads'] .votelinks,
  50. html[op='newcomments'] .votelinks{
  51. vertical-align: top;
  52. font-size: 0.7rem;
  53. }
  54.  
  55. span.titleline {
  56. font-size: 1.1rem;
  57. margin-top: var(--gutter);
  58. margin-bottom: var(--gutter);
  59. display: block;
  60. }
  61. title.titleline {
  62. font-size: 1.3rem;
  63.  
  64. }
  65.  
  66. html[op='item'] span.titleline {
  67. font-size: 1.0rem;
  68. padding: 5;
  69. }
  70.  
  71. .rank {
  72. display: none
  73. margin-left: 100px;
  74. font-size: 1.1rem;
  75.  
  76. }
  77.  
  78.  
  79. html[op='news'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  80. html[op='newest'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  81. html[op='ask'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  82. html[op='newcomments'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  83. html[op='shownew'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  84. html[op='submitted'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(1),
  85. html[op='favorites'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(2),
  86. html[op='front'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(2),
  87. html[op='show'] #hnmain > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > table:nth-child(2) {
  88. margin-left: 150px;
  89. }
  90.  
  91.  
  92. .sitebit.comhead {
  93. margin-left: 8;
  94. font-size: 0.8rem;
  95.  
  96. }
  97.  
  98. .subtext, .subline {
  99. font-size: 0.9rem;
  100.  
  101. }
  102.  
  103. #hnmain {
  104. width: 100%;
  105. background-color: white;
  106. }
  107.  
  108. /* Menu bar */
  109.  
  110. #hnmain > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(1) {
  111. padding: 50;
  112. }
  113. #hnmain > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(1) > table:nth-child(1) > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(1) {
  114. padding-right: var(--gutter) !important;
  115. }
  116.  
  117.  
  118. .comment, .toptext {
  119. max-width: 40em;
  120. font-size: .9rem;
  121. }
  122. .comment {
  123. padding-left: 50;
  124. }
  125.  
  126. .toptext, a, a:visited {
  127. color: black;
  128. }
  129. a:hover {
  130. text-decoration: underline;
  131. }
  132.  
  133.  
  134. input {
  135. padding: var(--gutter);
  136. }
  137. input, textarea {
  138. background-color: white;
  139. border: 2px solid var(--colour-hn-orange);
  140. border-radius: var(--border-radius);
  141.  
  142. }
  143. input[type='button'] {
  144. cursor: pointer;
  145. }
  146.  
  147.  
  148. /* Custom styles added via javascript */
  149.  
  150. .downvoted {
  151. background-color: rgb(245, 245, 245);
  152. border-radius: var(--border-radius);
  153. padding: 6px;
  154. }
  155. .downvoted .commtext {
  156. color: black;
  157. font-size: smaller;
  158. }
  159.  
  160. .quote {
  161. border-left: 3px solid var(--colour-hn-orange);
  162. padding: 6px 6px 6px 9px;
  163. font-style: italic;
  164. background-color: var(--colour-hn-orange-pale);
  165. border-radius: var(--border-radius);
  166. }
  167.  
  168. .hidden {
  169. display: none;
  170. }
  171.  
  172. .showComment a, .hideComment, .hideComment:link, .hideComment:visited {
  173. color: var(--colour-hn-orange);
  174. text-decoration: underline;
  175. }
  176. .hideComment {
  177. margin-left: var(--gutter);
  178. }
  179.  
  180. </style>`);
  181.  
  182. const comments = document.querySelectorAll('.commtext');
  183. comments.forEach(e => {
  184. if (!e.classList.contains('c00')) {
  185. e.parentElement.classList.add('downvoted');
  186. }
  187. });
  188.  
  189. let node = null;
  190. let nodes = [];
  191. const ps = document.evaluate("//p[starts-with(., '>')]", document.body)
  192. while (node = ps.iterateNext()) {
  193. nodes.push(node);
  194. }
  195. const spans = document.evaluate("//span[starts-with(., '>')]", document.body)
  196. while (node = spans.iterateNext()) {
  197. nodes.push(node);
  198. }
  199. nodes.forEach((n) => {
  200. const textNode = Array.from(n.childNodes).find((n) => n.nodeType === Node.TEXT_NODE);
  201. if (textNode) {
  202. const p = document.createElement('p');
  203. p.classList.add('quote');
  204. p.innerText = textNode.data.replace(">", "");
  205. n.firstChild.replaceWith(p);
  206. } else {
  207. n.classList.add('quote');
  208. n.innerText = n.innerText.replace(">", "");
  209. }
  210. });
  211.  
  212. const addComment = document.querySelector("html[op='item'] .fatitem tr:last-of-type");
  213. if (addComment) {
  214. addComment.classList.add('hidden');
  215. const showComment = document.createElement('tr');
  216. showComment.innerHTML = `
  217. <td colspan='2'></td>
  218. <td>
  219. <a href='#'>show comment box</a>
  220. </td>
  221. `;
  222. showComment.classList.add('showComment');
  223. showComment.querySelector('a').addEventListener('click', (e) => {
  224. showComment.classList.toggle('hidden');
  225. addComment.classList.toggle('hidden');
  226. });
  227. addComment.parentNode.insertBefore(showComment, addComment);
  228.  
  229. const hideComment = document.createElement('a');
  230. hideComment.setAttribute('href', '#');
  231. hideComment.innerText = 'hide comment box';
  232. hideComment.classList.add('hideComment');
  233. hideComment.addEventListener('click', (e) => {
  234. showComment.classList.toggle('hidden');
  235. addComment.classList.toggle('hidden');
  236. });
  237.  
  238. const commentForm = document.querySelector("form[action='comment']");
  239. commentForm.append(hideComment);
  240. }
  241. }
  242.  
  243. tampermonkeyScript();