notion TOC sider & go to top

display a fixed sider on the top-right of notion page which has a table of content block inside

当前为 2022-06-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name notion TOC sider & go to top
  3. // @namespace https://www.notion.so/
  4. // @version 0.0.1
  5. // @description display a fixed sider on the top-right of notion page which has a table of content block inside
  6. // @author nan chen
  7. // @match *://www.notion.so/*
  8. // @icon https://www.google.com/s2/favicons?domain=notion.so
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12. (function () {})(
  13. window.addEventListener('load', function () {
  14. var tocEle = document.querySelector(
  15. '.notion-table_of_contents-block'
  16. );
  17. var headings = [];
  18. var parseLevel = function (outerHtml) {
  19. if (outerHtml.includes('margin-left: 24px')) {
  20. return 2;
  21. }
  22. if (outerHtml.includes('margin-left: 48px')) {
  23. return 3;
  24. }
  25. return 1;
  26. };
  27.  
  28. tocEle.childNodes[0].childNodes.forEach(function (n) {
  29. if (n.nodeType === 1) {
  30. var an = n.querySelector('a');
  31. headings.push({
  32. title: n.innerText,
  33. level: parseLevel(n.outerHTML),
  34. href: an.href,
  35. });
  36. }
  37. });
  38.  
  39. var parent = document.querySelector('#notion-app');
  40. var menu = document.createElement('aside');
  41. var isExpanded = true;
  42. parent.appendChild(menu);
  43.  
  44. menu.style.minWidth = '100px';
  45. menu.style.minWidth = '120px';
  46. menu.style.position = 'fixed';
  47. menu.style.top = '55px';
  48. menu.style.right = '10px';
  49. menu.style.zIndex = 100000;
  50. menu.style.boxShadow =
  51. 'rgb(15 15 15 / 5%) 0px 0px 0px 1px, rgb(15 15 15 / 10%) 0px 3px 6px, rgb(15 15 15 / 20%) 0px 9px 24px';
  52. var menuList = document.createElement('div');
  53. menuList.style.maxWidth = '160px';
  54. menuList.style.backgroundColor = '#fff';
  55. menuList.style.padding = '10px';
  56.  
  57. menu.appendChild(menuList);
  58. var closeButtonWrapper = document.createElement('div');
  59. var closeButton = document.createElement('div');
  60. closeButtonWrapper.style.borderRadius = '12px';
  61. closeButtonWrapper.style.backgroundColor = '#fff';
  62. closeButtonWrapper.style.width = '24px';
  63. closeButtonWrapper.style.height = '24px';
  64. closeButtonWrapper.style.cursor = 'pointer';
  65. closeButtonWrapper.style.zIndex = 100000;
  66. closeButtonWrapper.style.position = 'absolute';
  67. closeButtonWrapper.style.top = '30px';
  68. closeButtonWrapper.style.right = '10px';
  69.  
  70. closeButton.style.width = '10px';
  71. closeButton.style.height = '10px';
  72. closeButton.style.borderLeft = '1px solid black';
  73. closeButton.style.borderBottom = '1px solid black';
  74. closeButton.style.transform = 'rotate(-45deg)';
  75. closeButton.style.position = 'absolute';
  76. closeButton.style.top = '10px';
  77. closeButton.style.left = '7px';
  78. parent.appendChild(closeButtonWrapper);
  79. closeButtonWrapper.appendChild(closeButton);
  80.  
  81. setTimeout(function () {
  82. closeButton.addEventListener('click', function () {
  83. if (!isExpanded) {
  84. closeButton.style.transform = 'rotate(-45deg)';
  85. menu.style.display = 'block';
  86. } else {
  87. closeButton.style.transform = 'rotate(135deg)';
  88. menu.style.display = 'none';
  89. }
  90.  
  91. isExpanded = !isExpanded;
  92. });
  93. });
  94.  
  95. var lists = headings.map(function (h) {
  96. var anchor = document.createElement('a');
  97. anchor.innerText = h.title;
  98. anchor.style.fontSize = '10px';
  99. anchor.href = h.href;
  100. anchor.style.cursor = 'pointer';
  101. anchor.style.display = 'block';
  102. anchor.style.textOverflow = 'ellipsis';
  103. anchor.style.whiteSpace = 'nowrap';
  104. anchor.style.overflow = 'hidden';
  105. anchor.style.color = 'rgb(141,141,141)';
  106.  
  107. switch (h.level) {
  108. case 1:
  109. break;
  110. case 2:
  111. anchor.style.marginLeft = '16px';
  112. break;
  113. case 3:
  114. anchor.style.marginLeft = '24px';
  115. break;
  116. default:
  117. break;
  118. }
  119. return anchor;
  120. });
  121. lists.forEach(function (l) {
  122. menuList.appendChild(l);
  123. });
  124.  
  125. /**** to top ******/
  126. var topAnchor = document.createElement('a');
  127. topAnchor.name = 'top';
  128.  
  129. parent.prepend(topAnchor);
  130. var toTop = document.createElement('div');
  131. toTop.className = 'to-top';
  132. toTop.innerHTML = `<a id="go-to-top" href="#top" target="_Self"></a><svg
  133. class="to-top-button"
  134. role="button"
  135. viewBox="0 0 1024 1024"
  136. xmlns="http://www.w3.org/2000/svg"
  137. style="cursor: pointer;
  138. position: fixed;
  139. bottom: 5rem;
  140. right: 2rem;
  141. width: 2rem;
  142. color: rgb(235, 235, 235);
  143. background-color: #fff;
  144. border-radius: 50%;
  145. overflow: hidden;
  146. z-index: 1;
  147. fill: currentcolor;"
  148. >
  149. <path
  150. d="M512 0C229.517 0 0 229.517 0 512s227.752 512 512 512c282.483 0 512-227.752 512-512C1024 229.517 794.483
  151. 0 512 0zM351.338 271.89h305.434c14.125 0 26.483 12.358 26.483 26.482s-12.358 26.483-26.483
  152. 26.483H351.338c-14.124 0-26.483-12.358-26.483-26.483 0-15.89 12.359-26.482 26.483-26.482z
  153. m331.917 303.669c-12.358 12.358-33.545 12.358-45.903 0L531.42 471.393v270.124c0 14.124-12.359
  154. 26.483-26.483 26.483s-26.483-12.359-26.483-26.483v-271.89l-105.93 104.166c-12.36 12.359-33.546 12.359-45.904
  155. 0-12.359-12.359-12.359-31.78 0-45.903l155.365-151.835c7.062-7.062 14.124-8.827 22.952-8.827s15.89 3.53 22.952
  156. 8.827L683.255 527.89c12.359 15.89 12.359 35.31 0 47.669z"
  157. fill="currentColor"
  158. ></path>
  159. </svg>`;
  160. parent.appendChild(toTop);
  161. var toTopButton = document.querySelector('.to-top-button');
  162. document.addEventListener('scroll', scrollFunction);
  163. function scrollFunction() {
  164. console.log('scrolling');
  165. if (
  166. document.body.scrollTop > 20 ||
  167. document.documentElement.scrollTop > 20
  168. ) {
  169. toTopButton.style.display = 'block';
  170. } else {
  171. toTopButton.style.display = 'none';
  172. }
  173. }
  174.  
  175. toTopButton.addEventListener('click', function (e) {
  176. document.querySelector('#go-to-top').click();
  177. });
  178. })
  179. );