github outline - github.com

Github outline 懸浮視窗

目前為 2019-12-12 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name github outline - github.com
  3. // @namespace Violentmonkey Scripts
  4. // @match https://github.com/*
  5. // @grant none
  6. // @version 1.02
  7. // @author TianyiLi-e0991100238@gmail.com
  8. // @description Get Readme file outline at github
  9. // @description:zh-TW Github outline 懸浮視窗
  10. // ==/UserScript==
  11. if (document.querySelector('#readme article')) {
  12. const canvas = document.createElement('div')
  13. canvas.style = `
  14. position: fixed;
  15. top: 10vh;
  16. right: 8vw;
  17. width: 300px;
  18. border-radius: 5px;
  19. background: white;
  20. border: solid 1px #e0e0e0;
  21. overflow-y: auto;
  22. max-height: 60vh;
  23. `
  24. const markdownDOM = document.querySelector('#readme article')
  25. function recursiveNodeReader(node) {
  26. let nodes = [...node.querySelectorAll('h1, h2, h3, h4, h5')]
  27. let n = nodes.shift()
  28. let result = []
  29. do {
  30. if (['h1', 'h2', 'h3', 'h4', 'h5'].includes(n.tagName.toLowerCase())) {
  31. result.push({
  32. text: n.textContent,
  33. level:
  34. ['h1', 'h2', 'h3', 'h4', 'h5'].indexOf(n.tagName.toLowerCase()) + 1,
  35. link: n.querySelector('a').href,
  36. })
  37. }
  38. } while ((n = nodes.shift()))
  39. return result
  40. }
  41.  
  42. function renderDOM(domTree) {
  43. return domTree
  44. .map(
  45. node =>
  46. `<a style="display:block" href="${node.link}" level="${node.level}">${
  47. node.level > 1 ? '&nbsp;'.repeat(node.level - 2) + '└' : '─'
  48. }${node.text}</a>`
  49. )
  50. .join('')
  51. }
  52. const body = document.createElement('div')
  53. const header = document.createElement('div')
  54. header.textContent = 'Outline'
  55. header.style = `
  56. padding: .5rem .7rem;
  57. font-size: 2rem;
  58. position: sticky;
  59. top: 0px;
  60. background: white;
  61. `
  62.  
  63. body.style = `
  64. padding: .2rem .3rem;
  65. `
  66.  
  67. body.addEventListener('mousedown', e => e.stopPropagation(), {
  68. capture: true,
  69. })
  70. body.addEventListener('click', e => e.stopPropagation(), { capture: true })
  71. let isMove = false
  72. let position = {
  73. x: 0,
  74. y: 0,
  75. }
  76. let target = null
  77. function eleMove(e) {
  78. if (!isMove) return
  79. target.style.top = e.clientY - position.y + 'px'
  80. target.style.left = e.clientX - position.x + 'px'
  81. target.style.right = ''
  82. }
  83. canvas.addEventListener(
  84. 'mousedown',
  85. function(e) {
  86. isMove = true
  87. position.x = e.offsetX
  88. position.y = e.offsetY
  89. target = this
  90. window.addEventListener('mousemove', eleMove, true)
  91. }
  92. )
  93. canvas.addEventListener(
  94. 'mouseup',
  95. () => {
  96. isMove = false
  97. window.removeEventListener('mousemove', eleMove, true)
  98. }
  99. )
  100.  
  101. body.innerHTML = renderDOM(recursiveNodeReader(markdownDOM))
  102. canvas.appendChild(header)
  103. canvas.appendChild(body)
  104.  
  105. document.body.appendChild(canvas)
  106. }