feat(theme): support multi-level sidebar (#851)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/1055/head
YiZhi 3 years ago committed by GitHub
parent 72950337bc
commit d1a2c76f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,37 +1,47 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { DefaultTheme } from 'vitepress/theme' import type { DefaultTheme } from 'vitepress/theme'
import { inject } from 'vue' import { computed, inject } from 'vue'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { isActive } from '../support/utils' import { isActive } from '../support/utils'
import VPLink from './VPLink.vue' import VPLink from './VPLink.vue'
defineProps<{ withDefaults(defineProps<{ item: DefaultTheme.SidebarItem; depth?: number }>(), { depth: 1 })
item: DefaultTheme.SidebarItem
}>()
const { page } = useData()
const { page, frontmatter } = useData()
const maxDepth = computed<number>(() => frontmatter.value.sidebarDepth || Infinity)
const closeSideBar = inject('close-sidebar') as () => void const closeSideBar = inject('close-sidebar') as () => void
</script> </script>
<template> <template>
<VPLink <VPLink
:class="{ active: isActive(page.relativePath, item.link) }" class="link"
:class="{ active: isActive(page.relativePath, item.link), offset: depth > 1 }"
:href="item.link" :href="item.link"
@click="closeSideBar" @click="closeSideBar"
> >
<span class="link-text">{{ item.text }}</span> <span class="link-text" :class="{ light: depth > 1 }">{{ item.text }}</span>
<template
v-if="'items' in item && depth < maxDepth"
v-for="child in item.items"
:key="child.link"
>
<VPSidebarLink :item="child" :depth="depth + 1" />
</template>
</VPLink> </VPLink>
</template> </template>
<style scoped> <style scoped>
.link { .link {
display: block; display: block;
padding: 4px 0; margin: 4px 0;
color: var(--vp-c-text-2); color: var(--vp-c-text-2);
transition: color 0.5s; transition: color 0.5s;
} }
.link.offset {
padding-left: 16px;
}
.link:hover { .link:hover {
color: var(--vp-c-text-1); color: var(--vp-c-text-1);
} }
@ -51,4 +61,9 @@ const closeSideBar = inject('close-sidebar') as () => void
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
} }
.link-text.light {
font-size: 13px;
font-weight: 400;
}
</style> </style>

@ -32,11 +32,17 @@ export function getFlatSideBarLinks(
): DefaultTheme.SidebarItem[] { ): DefaultTheme.SidebarItem[] {
const links: DefaultTheme.SidebarItem[] = [] const links: DefaultTheme.SidebarItem[] = []
for (const group of sidebar) { function recursivelyExtractLinks(items: DefaultTheme.SidebarItem[]) {
for (const link of group.items) { for (const item of items) {
links.push(link) item.link && links.push(item)
if ('items' in item) {
recursivelyExtractLinks(item.items)
}
} }
} }
for (const group of sidebar) {
recursivelyExtractLinks(group.items)
}
return links return links
} }

@ -139,10 +139,9 @@ export namespace DefaultTheme {
collapsed?: boolean collapsed?: boolean
} }
export interface SidebarItem { export type SidebarItem =
text: string | { text: string; link: string }
link: string | { text: string; link?: string; items: SidebarItem[] }
}
// edit link ----------------------------------------------------------------- // edit link -----------------------------------------------------------------

Loading…
Cancel
Save