diff --git a/src/client/theme-default/components/SideBar.ts b/src/client/theme-default/components/SideBar.ts index 4edb86f7d585..54dbfa67cff8 100644 --- a/src/client/theme-default/components/SideBar.ts +++ b/src/client/theme-default/components/SideBar.ts @@ -1,7 +1,7 @@ import { useSiteData, usePageData, useRoute } from 'vitepress' import { computed, h, FunctionalComponent, VNode } from 'vue' import { Header } from '../../../../types/shared' -import { isActive } from '../utils' +import { isActive, getPathDirName } from '../utils' import { DefaultTheme } from '../config' import { useActiveSidebarLinks } from '../composables/activeSidebarLink' @@ -62,7 +62,12 @@ export default { } else if (themeSidebar === false) { return [] } else if (typeof themeSidebar === 'object') { - return resolveMultiSidebar(themeSidebar, route.path, sidebarDepth) + return resolveMultiSidebar( + themeSidebar, + route.path, + headers, + sidebarDepth + ) } } }) @@ -86,6 +91,10 @@ interface ResolvedSidebarItem { function resolveAutoSidebar(headers: Header[], depth: number): ResolvedSidebar { const ret: ResolvedSidebar = [] + if (headers === undefined) { + return [] + } + let lastH2: ResolvedSidebarItem | undefined = undefined headers.forEach(({ level, title, slug }) => { if (level - 1 > depth) { @@ -117,8 +126,19 @@ function resolveArraySidebar( function resolveMultiSidebar( config: DefaultTheme.MultiSideBarConfig, path: string, + headers: Header[], depth: number ): ResolvedSidebar { + const item = config[getPathDirName(path)] + + if (Array.isArray(item)) { + return resolveArraySidebar(item, depth) + } + + if (item === 'auto') { + return resolveAutoSidebar(headers, depth) + } + return [] } diff --git a/src/client/theme-default/utils.ts b/src/client/theme-default/utils.ts index a743905817cd..25d6580a8371 100644 --- a/src/client/theme-default/utils.ts +++ b/src/client/theme-default/utils.ts @@ -26,3 +26,22 @@ export function isActive(route: Route, path?: string): boolean { export function normalize(path: string): string { return decodeURI(path).replace(hashRE, '').replace(extRE, '') } + +/** + * get the path without filename (the last segment). for example, if the given + * path is `/guide/getting-started.html`, this method will return `/guide/`. + * Always with a trailing slash. + */ +export function getPathDirName(path: string): string { + const segments = path.split('/') + + if (segments[segments.length - 1]) { + segments.pop() + } + + return ensureEndingSlash(segments.join('/')) +} + +export function ensureEndingSlash(path: string): string { + return /(\.html|\/)$/.test(path) ? path : `${path}/` +}