GitHub README TOC

Add table of contents(TOC) for README in GitHub.

  1. // ==UserScript==
  2. // @name GitHub README TOC
  3. // @namespace https://greatest.deepsurf.us/en/scripts/464732-github-readme-toc
  4. // @version 0.3.3
  5. // @author pacexy <pacexy@gmail.com>
  6. // @description Add table of contents(TOC) for README in GitHub.
  7. // @license MIT
  8. // @icon https://github.com/favicon.ico
  9. // @homepage https://github.com/pacexy/github-readme-toc#readme
  10. // @homepageURL https://github.com/pacexy/github-readme-toc#readme
  11. // @source https://github.com/pacexy/github-readme-toc
  12. // @supportURL https://github.com/pacexy/github-readme-toc/issues
  13. // @match https://github.com/**
  14. // @require https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js
  15. // @require https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.production.min.js
  16. // ==/UserScript==
  17.  
  18. (o=>{const t=document.createElement("style");t.dataset.source="vite-plugin-monkey",t.textContent=o,document.head.append(t)})(" #github-readme-toc{position:sticky;z-index:30;top:0px!important;padding-top:24px;margin-top:24px;border-top:1px solid var(--color-border-muted);display:flex;flex-direction:column;max-height:100vh}#github-readme-toc ul{list-style:none;overflow:auto;padding-right:8px;padding-bottom:8px}#github-readme-toc ul>li{margin-bottom:8px}#github-readme-toc a{color:var(--color-fg-default)}#github-readme-toc a:hover{color:var(--color-accent-fg);text-decoration:none} ");
  19.  
  20. (function (require$$0, require$$0$1) {
  21. 'use strict';
  22.  
  23. var jsxRuntimeExports = {};
  24. var jsxRuntime = {
  25. get exports() {
  26. return jsxRuntimeExports;
  27. },
  28. set exports(v) {
  29. jsxRuntimeExports = v;
  30. }
  31. };
  32. var reactJsxRuntime_production_min = {};
  33. /**
  34. * @license React
  35. * react-jsx-runtime.production.min.js
  36. *
  37. * Copyright (c) Facebook, Inc. and its affiliates.
  38. *
  39. * This source code is licensed under the MIT license found in the
  40. * LICENSE file in the root directory of this source tree.
  41. */
  42. var f = require$$0, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m$1 = Object.prototype.hasOwnProperty, n = f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, p = { key: true, ref: true, __self: true, __source: true };
  43. function q(c, a, g) {
  44. var b, d = {}, e = null, h = null;
  45. void 0 !== g && (e = "" + g);
  46. void 0 !== a.key && (e = "" + a.key);
  47. void 0 !== a.ref && (h = a.ref);
  48. for (b in a)
  49. m$1.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);
  50. if (c && c.defaultProps)
  51. for (b in a = c.defaultProps, a)
  52. void 0 === d[b] && (d[b] = a[b]);
  53. return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current };
  54. }
  55. reactJsxRuntime_production_min.Fragment = l;
  56. reactJsxRuntime_production_min.jsx = q;
  57. reactJsxRuntime_production_min.jsxs = q;
  58. (function(module) {
  59. {
  60. module.exports = reactJsxRuntime_production_min;
  61. }
  62. })(jsxRuntime);
  63. var client = {};
  64. var m = require$$0$1;
  65. {
  66. client.createRoot = m.createRoot;
  67. client.hydrateRoot = m.hydrateRoot;
  68. }
  69. const name = "github-readme-toc";
  70. function assert$1(el) {
  71. if (!el) {
  72. throw new Error("Element not exists");
  73. }
  74. }
  75. function ensureElements() {
  76. var _a;
  77. const container = (_a = document.querySelector(".BorderGrid")) == null ? void 0 : _a.parentElement;
  78. const headings = document.querySelectorAll("article.markdown-body .markdown-heading");
  79. assert$1(container);
  80. assert$1(headings);
  81. return { container, headings };
  82. }
  83. function assert(x) {
  84. if (!x) {
  85. throw new Error("Assertion failed");
  86. }
  87. }
  88. function getToc() {
  89. return [...ensureElements().headings].map((heading) => {
  90. var _a;
  91. const h = heading.firstElementChild;
  92. assert(h);
  93. const depth = Number(h.tagName.slice(1));
  94. const anchor = heading.querySelector("a");
  95. return {
  96. depth,
  97. text: (_a = heading.textContent) == null ? void 0 : _a.trim(),
  98. url: anchor == null ? void 0 : anchor.href
  99. };
  100. });
  101. }
  102. const Toc = ({ toc }) => {
  103. return /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { children: toc.map((h, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { style: { paddingLeft: (h.depth - 1) * 16 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: h.url, children: h.text }) }, i)) });
  104. };
  105. function App() {
  106. const toc = getToc();
  107. return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
  108. /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "h4 mb-3", children: "Table of Contents" }),
  109. /* @__PURE__ */ jsxRuntimeExports.jsx(Toc, { toc })
  110. ] });
  111. }
  112. async function render() {
  113. let root = document.querySelector(`#${name}`);
  114. if (root) {
  115. return;
  116. }
  117. const container = ensureElements().container;
  118. root = document.createElement("div");
  119. root.id = name;
  120. container.append(root);
  121. client.createRoot(root).render(
  122. /* @__PURE__ */ jsxRuntimeExports.jsx(require$$0.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}) })
  123. );
  124. }
  125. function run() {
  126. render().then(() => {
  127. }).catch((error) => {
  128. });
  129. }
  130. ["pjax:end", "turbo:render"].forEach((e) => {
  131. document.addEventListener(e, () => {
  132. run();
  133. });
  134. });
  135. run();
  136.  
  137. })(React, ReactDOM);