use-toc.ts 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { computed } from 'vue'
  2. import { useData } from 'vitepress'
  3. import type { PageData } from 'vitepress'
  4. type EnhanceArrayElement<T, P> = T extends Array<infer U> ? (U & P)[] : never
  5. type Headers = EnhanceArrayElement<
  6. PageData['headers'],
  7. {
  8. children?: Headers
  9. }
  10. >
  11. export const useToc = () => {
  12. const { page } = useData()
  13. return computed(() => resolveHeaders(page.value.headers))
  14. }
  15. export const resolveHeaders = (headers: PageData['headers']) => {
  16. return mapHeaders(groupHeaders(headers))
  17. }
  18. export function groupHeaders(headers: PageData['headers']) {
  19. headers = headers.map((h) => Object.assign({}, h))
  20. let lastH2
  21. headers.forEach((h) => {
  22. if (h.level === 2) {
  23. lastH2 = h
  24. } else if (lastH2) {
  25. ;(lastH2.children || (lastH2.children = [])).push(h)
  26. }
  27. })
  28. return headers.filter((h) => h.level === 2)
  29. }
  30. export function mapHeaders(headers: Headers) {
  31. return headers.map((header) => ({
  32. text: header.title,
  33. link: `#${header.slug}`,
  34. children: header.children ? mapHeaders(header.children) : undefined,
  35. }))
  36. }