SidebarLink.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <script>
  2. import { isActive, hashRE, groupHeaders } from '../util'
  3. export default {
  4. functional: true,
  5. props: ['item', 'sidebarDepth'],
  6. render (h,
  7. {
  8. parent: {
  9. $page,
  10. $site,
  11. $route,
  12. $themeConfig,
  13. $themeLocaleConfig
  14. },
  15. props: {
  16. item,
  17. sidebarDepth
  18. }
  19. }) {
  20. // use custom active class matching logic
  21. // due to edge case of paths ending with / + hash
  22. const selfActive = isActive($route, item.path)
  23. // for sidebar: auto pages, a hash link should be active if one of its child
  24. // matches
  25. const active = item.type === 'auto'
  26. ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
  27. : selfActive
  28. const link = item.type === 'external'
  29. ? renderExternal(h, item.path, item.title || item.path)
  30. : renderLink(h, item.path, item.title || item.path, active)
  31. const maxDepth = [
  32. $page.frontmatter.sidebarDepth,
  33. sidebarDepth,
  34. $themeLocaleConfig.sidebarDepth,
  35. $themeConfig.sidebarDepth,
  36. 1
  37. ].find(depth => depth !== undefined)
  38. const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
  39. || $themeConfig.displayAllHeaders
  40. if (item.type === 'auto') {
  41. return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
  42. } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
  43. const children = groupHeaders(item.headers)
  44. return [link, renderChildren(h, children, item.path, $route, maxDepth)]
  45. } else {
  46. return link
  47. }
  48. }
  49. }
  50. function renderLink (h, to, text, active, level) {
  51. const component = {
  52. props: {
  53. to,
  54. activeClass: '',
  55. exactActiveClass: ''
  56. },
  57. class: {
  58. active,
  59. 'sidebar-link': true
  60. }
  61. }
  62. if (level > 2) {
  63. component.style = {
  64. 'padding-left': level + 'rem'
  65. }
  66. }
  67. return h('router-link', component, text)
  68. }
  69. function renderChildren (h, children, path, route, maxDepth, depth = 1) {
  70. if (!children || depth > maxDepth) return null
  71. return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
  72. const active = isActive(route, path + '#' + c.slug)
  73. return h('li', { class: 'sidebar-sub-header' }, [
  74. renderLink(h, path + '#' + c.slug, c.title, active, c.level - 1),
  75. renderChildren(h, c.children, path, route, maxDepth, depth + 1)
  76. ])
  77. }))
  78. }
  79. function renderExternal (h, to, text) {
  80. return h('a', {
  81. attrs: {
  82. href: to,
  83. target: '_blank',
  84. rel: 'noopener noreferrer'
  85. },
  86. class: {
  87. 'sidebar-link': true
  88. }
  89. }, [text, h('OutboundLink')])
  90. }
  91. </script>
  92. <style lang="stylus">
  93. .sidebar .sidebar-sub-headers
  94. padding-left 1rem
  95. font-size 0.95em
  96. a.sidebar-link
  97. font-size 1em
  98. font-weight 400
  99. display inline-block
  100. color $textColor
  101. border-left 0.25rem solid transparent
  102. padding 0.35rem 1rem 0.35rem 1.25rem
  103. line-height 1.4
  104. width: 100%
  105. box-sizing: border-box
  106. &:hover
  107. color $accentColor
  108. &.active
  109. font-weight 600
  110. color $accentColor
  111. border-left-color $accentColor
  112. .sidebar-group &
  113. padding-left 2rem
  114. .sidebar-sub-headers &
  115. padding-top 0.25rem
  116. padding-bottom 0.25rem
  117. border-left none
  118. &.active
  119. font-weight 500
  120. </style>