feat: add array sidebar support (#35)

pull/44/head
Kia King Ishii 5 years ago committed by GitHub
parent da8df19cbe
commit 4a8388e113
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,7 +7,7 @@ export * from './theme'
// composables // composables
export { useSiteData } from './composables/siteData' export { useSiteData } from './composables/siteData'
export { usePageData } from './composables/pageData' export { usePageData } from './composables/pageData'
export { useRouter, useRoute } from './router' export { useRouter, useRoute, Router, Route } from './router'
// components // components
export { Content } from './components/Content' export { Content } from './components/Content'

@ -1,6 +1,7 @@
import { useSiteData, usePageData, useRoute } from 'vitepress' import { useSiteData, usePageData, useRoute } from 'vitepress'
import { computed, h, FunctionalComponent } from 'vue' import { computed, h, FunctionalComponent, VNode } from 'vue'
import { Header } from '../../../../types/shared' import { Header } from '../../../../types/shared'
import { isActive } from '../utils'
import { DefaultTheme } from '../config' import { DefaultTheme } from '../config'
import { useActiveSidebarLinks } from '../composables/activeSidebarLink' import { useActiveSidebarLinks } from '../composables/activeSidebarLink'
@ -10,14 +11,16 @@ const SideBarItem: FunctionalComponent<{
const { const {
item: { link, text, children } item: { link, text, children }
} = props } = props
return h('li', [
h('a', { href: link }, text), const route = useRoute()
children const pageData = usePageData()
? h(
'ul', const active = isActive(route, link)
children.map((c) => h(SideBarItem, { item: c })) const headers = pageData.value.headers
)
: null return h('li', { class: 'sidebar-item' }, [
createLink(active, text, link),
createChildren(active, children, headers)
]) ])
} }
@ -67,6 +70,10 @@ export default {
} }
} }
interface HeaderWithChildren extends Header {
children?: Header[]
}
type ResolvedSidebar = ResolvedSidebarItem[] type ResolvedSidebar = ResolvedSidebarItem[]
interface ResolvedSidebarItem { interface ResolvedSidebarItem {
@ -104,7 +111,7 @@ function resolveArraySidebar(
config: DefaultTheme.SideBarItem[], config: DefaultTheme.SideBarItem[],
depth: number depth: number
): ResolvedSidebar { ): ResolvedSidebar {
return [] return config
} }
function resolveMultiSidebar( function resolveMultiSidebar(
@ -114,3 +121,59 @@ function resolveMultiSidebar(
): ResolvedSidebar { ): ResolvedSidebar {
return [] return []
} }
function createLink(active: boolean, text: string, link?: string): VNode {
const tag = link ? 'a' : 'p'
const component = {
class: { 'sidebar-link': true, active },
href: link
}
return h(tag, component, text)
}
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
}))
}

@ -1,43 +1,61 @@
<template> <template>
<div class="sidebar"> <ul class="sidebar">
<ul> <SideBarItem v-for="item of items" :item="item" />
<SideBarItem v-for="item of items" :item="item"></SideBarItem>
</ul> </ul>
</div>
</template> </template>
<script src="./SideBar"></script> <script src="./SideBar"></script>
<style> <style>
.sidebar ul { .sidebar,
.sidebar-items {
list-style-type: none; list-style-type: none;
line-height: 2; line-height: 2;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.sidebar a { .sidebar-items .sidebar-items {
display: inline-block; padding-left: 1rem;
color: var(--text-color);
padding-left: 1.5rem;
} }
.sidebar a:hover { .sidebar-items .sidebar-items .sidebar-link {
color: var(--accent-color); border-left: 0;
} }
.sidebar a.active { .sidebar-items .sidebar-items .sidebar-link.active {
color: var(--accent-color);
font-weight: 500; font-weight: 500;
} }
.sidebar > ul > li > a.active { .sidebar-items .sidebar-link {
padding-left: 1.25rem; padding: .35rem 1rem .35rem 2rem;
border-left: .25rem solid var(--accent-color); line-height: 1.4;
font-size: 0.9em;
font-weight: 400;
} }
.sidebar ul ul { .sidebar-link {
font-size: 0.9em; display: block;
padding-left: 1rem; margin: 0;
border-left: .25rem solid transparent;
padding: .35rem 1.5rem .35rem 1.25rem;
line-height: 1.7;
font-size: 1em;
font-weight: 600;
color: var(--text-color);
}
a.sidebar-link {
transition: color .15s ease;
}
a.sidebar-link:hover {
color: var(--accent-color);
}
a.sidebar-link.active {
border-left-color: var(--accent-color);
font-weight: 600;
color: var(--accent-color);
} }
</style> </style>

@ -1,5 +1,23 @@
import { useSiteData } from 'vitepress' import { useSiteData, Route } from 'vitepress'
export const hashRE = /#.*$/
export const extRE = /\.(md|html)$/
export function withBase(path: string) { export function withBase(path: string) {
return (useSiteData().value.base + path).replace(/\/+/g, '/') return (useSiteData().value.base + path).replace(/\/+/g, '/')
} }
export function isActive(route: Route, path?: string): boolean {
if (path === undefined) {
return false
}
const routePath = normalize(route.path)
const pagePath = normalize(path)
return routePath === pagePath
}
export function normalize(path: string): string {
return decodeURI(path).replace(hashRE, '').replace(extRE, '')
}

@ -43,8 +43,7 @@ function createVitePressPlugin({
customData: { customData: {
path: resolver.fileToRequest(file), path: resolver.fileToRequest(file),
pageData pageData
}, }
timestamp: Date.now()
}) })
// reload the content component // reload the content component

Loading…
Cancel
Save