Skip to content

Commit b0edb89

Browse files
committed
chore: dasdasd
1 parent d57278e commit b0edb89

1 file changed

Lines changed: 83 additions & 1 deletion

File tree

blog-archived/app/pages/articles/[...slug].vue

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ function parseMeta(entry: Record<string, any>) {
2626
return {}
2727
}
2828
29+
interface TocLink {
30+
id: string
31+
depth: number
32+
text: string
33+
children?: TocLink[]
34+
}
35+
2936
function gatherNodeText(node: any): string {
3037
if (!node || typeof node !== 'object') {
3138
return ''
@@ -61,6 +68,75 @@ function extractFirstParagraphText(body: any): string | undefined {
6168
return undefined
6269
}
6370
71+
function buildTocLinksFromBody(body: MarkdownRoot | undefined | null): TocLink[] {
72+
const children = Array.isArray(body?.children) ? body!.children : []
73+
const links: TocLink[] = []
74+
const stack: Array<{ depth: number, link: TocLink }> = []
75+
76+
for (const node of children) {
77+
if (!node || typeof node !== 'object') {
78+
continue
79+
}
80+
const tag = typeof (node as any).tag === 'string' ? (node as any).tag : null
81+
if (!tag || !tag.startsWith('h')) {
82+
continue
83+
}
84+
85+
const depth = Number.parseInt(tag.slice(1), 10)
86+
if (!Number.isFinite(depth) || depth < 2) {
87+
continue
88+
}
89+
90+
const id = typeof (node as any).props?.id === 'string' ? (node as any).props.id : null
91+
if (!id) {
92+
continue
93+
}
94+
95+
const text = gatherNodeText(node).trim()
96+
if (!text) {
97+
continue
98+
}
99+
100+
const link: TocLink = {
101+
id,
102+
depth,
103+
text,
104+
children: [],
105+
}
106+
107+
while (stack.length > 0 && stack[stack.length - 1]!.depth >= depth) {
108+
stack.pop()
109+
}
110+
111+
if (stack.length === 0) {
112+
links.push(link)
113+
}
114+
else {
115+
const parent = stack[stack.length - 1]!.link
116+
if (!parent.children) {
117+
parent.children = []
118+
}
119+
parent.children.push(link)
120+
}
121+
122+
stack.push({ depth, link })
123+
}
124+
125+
function normalize(nodes: TocLink[]): TocLink[] {
126+
return nodes.map((node) => {
127+
if (node.children && node.children.length === 0) {
128+
delete node.children
129+
}
130+
else if (node.children) {
131+
node.children = normalize(node.children)
132+
}
133+
return node
134+
})
135+
}
136+
137+
return normalize(links)
138+
}
139+
64140
const { data: article } = await useAsyncData(`article:${contentPath}`, async () => {
65141
const entry = await queryCollection('articles')
66142
.path(contentPath)
@@ -119,7 +195,13 @@ const { data: adjacent } = await useAsyncData(`article-nav:${contentPath}`, asyn
119195
}
120196
})
121197
122-
const tocLinks = computed(() => article.value?.body?.toc?.links ?? [])
198+
const tocLinks = computed<TocLink[]>(() => {
199+
const rawLinks = article.value?.body?.toc?.links
200+
if (Array.isArray(rawLinks) && rawLinks.length > 0) {
201+
return rawLinks as TocLink[]
202+
}
203+
return buildTocLinksFromBody(article.value?.body)
204+
})
123205
const hasToc = computed(() => tocLinks.value.length > 0)
124206
const isTocOpen = ref(false)
125207
const previousArticle = computed(() => adjacent.value?.prev ?? null)

0 commit comments

Comments
 (0)