返回 slidev
useTocTree.ts
根目录 / packages / client / composables / useTocTree.ts
1 import type { SlideRoute, TocItem } from '@slidev/types'
2 import type { ComputedRef, Ref } from 'vue'
3 import { computed } from 'vue'
4 import { getSlidePath } from '../logic/slides'
5
6 function addToTree(tree: TocItem[], route: SlideRoute, level = 1) {
7 const titleLevel = route.meta.slide.level ?? level
8 if (titleLevel && titleLevel > level && tree.length > 0) {
9 addToTree(tree[tree.length - 1].children, route, level + 1)
10 }
11 else {
12 tree.push({
13 no: route.no,
14 children: [],
15 level,
16 titleLevel,
17 path: getSlidePath(route.meta.slide?.frontmatter?.routeAlias ?? route.no, false),
18 hideInToc: Boolean(route.meta?.slide?.frontmatter?.hideInToc),
19 title: route.meta?.slide?.title,
20 })
21 }
22 }
23
24 function getTreeWithActiveStatuses(
25 tree: TocItem[],
26 currentRoute?: SlideRoute,
27 hasActiveParent = false,
28 parent?: TocItem,
29 currentSlideNo?: Ref<number>,
30 ): TocItem[] {
31 return tree.map((item: TocItem) => {
32 const clone = {
33 ...item,
34 active: item.no === currentSlideNo?.value,
35 hasActiveParent,
36 }
37 if (clone.children.length > 0) {
38 clone.children = getTreeWithActiveStatuses(
39 clone.children,
40 currentRoute,
41 clone.active || clone.hasActiveParent,
42 clone,
43 currentSlideNo,
44 )
45 }
46 if (parent && (clone.active || clone.activeParent))
47 parent.activeParent = true
48 return clone
49 })
50 }
51
52 function filterTree(tree: TocItem[], level = 1): TocItem[] {
53 return tree
54 .filter((item: TocItem) => !item.hideInToc)
55 .map((item: TocItem) => ({
56 ...item,
57 children: filterTree(item.children, level + 1),
58 }))
59 }
60
61 export function useTocTree(
62 slides: Ref<SlideRoute[]>,
63 currentSlideNo: Ref<number>,
64 currentSlideRoute: Ref<SlideRoute>,
65 ): ComputedRef<TocItem[]> {
66 const rawTree = computed(() => slides.value
67 .filter((route: SlideRoute) => route.meta?.slide?.title)
68 .reduce((acc: TocItem[], route: SlideRoute) => {
69 addToTree(acc, route)
70 return acc
71 }, []))
72
73 const treeWithActiveStatuses = computed(() => getTreeWithActiveStatuses(
74 rawTree.value,
75 currentSlideRoute.value,
76 undefined,
77 undefined,
78 currentSlideNo,
79 ))
80
81 return computed(() => filterTree(treeWithActiveStatuses.value))
82 }
83
83 lines TYPESCRIPT