Skip to content

Commit

Permalink
feat: allow ignoring certain headers and their subtrees completely in…
Browse files Browse the repository at this point in the history
… outline

closes #4171
  • Loading branch information
brc-dd committed Sep 1, 2024
1 parent bc7271d commit 3e11b6a
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 52 deletions.
80 changes: 57 additions & 23 deletions __tests__/unit/client/theme-default/composables/outline.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { resolveHeaders } from 'client/theme-default/composables/outline'

const element = {
classList: {
contains: () => false
}
} as unknown as HTMLHeadElement

describe('client/theme-default/composables/outline', () => {
describe('resolveHeader', () => {
test('levels range', () => {
Expand All @@ -9,12 +15,14 @@ describe('client/theme-default/composables/outline', () => {
{
level: 2,
title: 'h2 - 1',
link: '#h2-1'
link: '#h2-1',
element
},
{
level: 3,
title: 'h3 - 1',
link: '#h3-1'
link: '#h3-1',
element
}
],
[2, 3]
Expand All @@ -28,9 +36,12 @@ describe('client/theme-default/composables/outline', () => {
{
level: 3,
title: 'h3 - 1',
link: '#h3-1'
link: '#h3-1',
children: [],
element
}
]
],
element
}
])
})
Expand All @@ -42,12 +53,14 @@ describe('client/theme-default/composables/outline', () => {
{
level: 2,
title: 'h2 - 1',
link: '#h2-1'
link: '#h2-1',
element
},
{
level: 3,
title: 'h3 - 1',
link: '#h3-1'
link: '#h3-1',
element
}
],
2
Expand All @@ -56,7 +69,9 @@ describe('client/theme-default/composables/outline', () => {
{
level: 2,
title: 'h2 - 1',
link: '#h2-1'
link: '#h2-1',
children: [],
element
}
])
})
Expand All @@ -68,42 +83,50 @@ describe('client/theme-default/composables/outline', () => {
{
level: 2,
title: 'h2 - 1',
link: '#h2-1'
link: '#h2-1',
element
},
{
level: 3,
title: 'h3 - 1',
link: '#h3-1'
link: '#h3-1',
element
},
{
level: 4,
title: 'h4 - 1',
link: '#h4-1'
link: '#h4-1',
element
},
{
level: 3,
title: 'h3 - 2',
link: '#h3-2'
link: '#h3-2',
element
},
{
level: 4,
title: 'h4 - 2',
link: '#h4-2'
link: '#h4-2',
element
},
{
level: 2,
title: 'h2 - 2',
link: '#h2-2'
link: '#h2-2',
element
},
{
level: 3,
title: 'h3 - 3',
link: '#h3-3'
link: '#h3-3',
element
},
{
level: 4,
title: 'h4 - 3',
link: '#h4-3'
link: '#h4-3',
element
}
],
'deep'
Expand All @@ -122,9 +145,12 @@ describe('client/theme-default/composables/outline', () => {
{
level: 4,
title: 'h4 - 1',
link: '#h4-1'
link: '#h4-1',
children: [],
element
}
]
],
element
},
{
level: 3,
Expand All @@ -134,11 +160,15 @@ describe('client/theme-default/composables/outline', () => {
{
level: 4,
title: 'h4 - 2',
link: '#h4-2'
link: '#h4-2',
children: [],
element
}
]
],
element
}
]
],
element
},
{
level: 2,
Expand All @@ -153,11 +183,15 @@ describe('client/theme-default/composables/outline', () => {
{
level: 4,
title: 'h4 - 3',
link: '#h4-3'
link: '#h4-3',
children: [],
element
}
]
],
element
}
]
],
element
}
])
})
Expand Down
68 changes: 39 additions & 29 deletions src/client/theme-default/composables/outline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type MenuItem = Omit<Header, 'slug' | 'children'> & {
children?: MenuItem[]
}

export function resolveTitle(theme: DefaultTheme.Config) {
export function resolveTitle(theme: DefaultTheme.Config): string {
return (
(typeof theme.outline === 'object' &&
!Array.isArray(theme.outline) &&
Expand All @@ -23,7 +23,7 @@ export function resolveTitle(theme: DefaultTheme.Config) {
)
}

export function getHeaders(range: DefaultTheme.Config['outline']) {
export function getHeaders(range: DefaultTheme.Config['outline']): MenuItem[] {
const headers = [
...document.querySelectorAll('.VPDoc :where(h1,h2,h3,h4,h5,h6)')
]
Expand Down Expand Up @@ -80,38 +80,13 @@ export function resolveHeaders(
? [2, 6]
: levelsRange

headers = headers.filter((h) => h.level >= high && h.level <= low)
// clear previous caches
resolvedHeaders.length = 0
// update global header list for active link rendering
for (const { element, link } of headers) {
resolvedHeaders.push({ element, link })
}

const ret: MenuItem[] = []
outer: for (let i = 0; i < headers.length; i++) {
const cur = headers[i]
if (i === 0) {
ret.push(cur)
} else {
for (let j = i - 1; j >= 0; j--) {
const prev = headers[j]
if (prev.level < cur.level) {
;(prev.children || (prev.children = [])).push(cur)
continue outer
}
}
ret.push(cur)
}
}

return ret
return buildTree(headers, high, low)
}

export function useActiveAnchor(
container: Ref<HTMLElement>,
marker: Ref<HTMLElement>
) {
): void {
const { isAsideEnabled } = useAside()

const onScroll = throttleAndDebounce(setActiveLink, 100)
Expand Down Expand Up @@ -221,3 +196,38 @@ function getAbsoluteTop(element: HTMLElement): number {
}
return offsetTop
}

function buildTree(data: MenuItem[], min: number, max: number): MenuItem[] {
resolvedHeaders.length = 0

const result: MenuItem[] = []
const stack: (MenuItem | { level: number; shouldIgnore: true })[] = []

data.forEach((item) => {
const node = { ...item, children: [] }
let parent = stack[stack.length - 1]

while (parent && parent.level >= node.level) {
stack.pop()
parent = stack[stack.length - 1]
}

if (
node.element.classList.contains('ignore-header') ||
(parent && 'shouldIgnore' in parent)
) {
stack.push({ level: node.level, shouldIgnore: true })
return
}

if (node.level > max || node.level < min) return
resolvedHeaders.push({ element: node.element, link: node.link })

if (parent) parent.children!.push(node)
else result.push(node)

stack.push(node)
})

return result
}

0 comments on commit 3e11b6a

Please sign in to comment.