mirror of https://github.com/vuejs/vitepress
parent
a6bfdd41fa
commit
061ad3ff32
@ -0,0 +1,91 @@
|
|||||||
|
import { useRoute, useSiteData } from 'vitepress'
|
||||||
|
import { FunctionalComponent, h, VNode } from 'vue'
|
||||||
|
import { Header } from '../../../../types/shared'
|
||||||
|
import { joinUrl, isActive } from '../utils'
|
||||||
|
import { ResolvedSidebarItem } from './SideBar'
|
||||||
|
|
||||||
|
interface HeaderWithChildren extends Header {
|
||||||
|
children?: Header[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SideBarItem: FunctionalComponent<{
|
||||||
|
item: ResolvedSidebarItem
|
||||||
|
}> = (props) => {
|
||||||
|
const {
|
||||||
|
item: { link: relLink, text, children }
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const siteData = useSiteData()
|
||||||
|
|
||||||
|
const link = resolveLink(siteData.value.base, relLink || '')
|
||||||
|
const active = isActive(route, link)
|
||||||
|
const headers = route.data.headers
|
||||||
|
const childItems = createChildren(active, children, headers)
|
||||||
|
|
||||||
|
return h('li', { class: 'sidebar-item' }, [
|
||||||
|
h(
|
||||||
|
link ? 'a' : 'p',
|
||||||
|
{
|
||||||
|
class: { 'sidebar-link': true, active },
|
||||||
|
href: link
|
||||||
|
},
|
||||||
|
text
|
||||||
|
),
|
||||||
|
childItems
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveLink(base: string, path: string): string | undefined {
|
||||||
|
return path
|
||||||
|
? // keep relative hash to the same page
|
||||||
|
path.startsWith('#')
|
||||||
|
? path
|
||||||
|
: joinUrl(base, path)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function createChildren(
|
||||||
|
active: boolean,
|
||||||
|
children?: ResolvedSidebarItem[],
|
||||||
|
headers?: Header[]
|
||||||
|
): VNode | null {
|
||||||
|
if (children && children.length > 0) {
|
||||||
|
return h(
|
||||||
|
'ul',
|
||||||
|
{ class: 'sidebar-items' },
|
||||||
|
children.map((c) => {
|
||||||
|
return h(SideBarItem, { item: c })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return active && headers
|
||||||
|
? createChildren(false, resolveHeaders(headers))
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveHeaders(headers: Header[]): ResolvedSidebarItem[] {
|
||||||
|
return mapHeaders(groupHeaders(headers))
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupHeaders(headers: Header[]): HeaderWithChildren[] {
|
||||||
|
headers = headers.map((h) => Object.assign({}, h))
|
||||||
|
let lastH2: HeaderWithChildren
|
||||||
|
headers.forEach((h) => {
|
||||||
|
if (h.level === 2) {
|
||||||
|
lastH2 = h
|
||||||
|
} else if (lastH2) {
|
||||||
|
;(lastH2.children || (lastH2.children = [])).push(h)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return headers.filter((h) => h.level === 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapHeaders(headers: HeaderWithChildren[]): ResolvedSidebarItem[] {
|
||||||
|
return headers.map((header) => ({
|
||||||
|
text: header.title,
|
||||||
|
link: `#${header.slug}`,
|
||||||
|
children: header.children ? mapHeaders(header.children) : undefined
|
||||||
|
}))
|
||||||
|
}
|
Loading…
Reference in new issue