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
export { useSiteData } from './composables/siteData'
export { usePageData } from './composables/pageData'
export { useRouter, useRoute } from './router'
export { useRouter, useRoute, Router, Route } from './router'
// components
export { Content } from './components/Content'

@ -1,6 +1,7 @@
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 { isActive } from '../utils'
import { DefaultTheme } from '../config'
import { useActiveSidebarLinks } from '../composables/activeSidebarLink'
@ -10,14 +11,16 @@ const SideBarItem: FunctionalComponent<{
const {
item: { link, text, children }
} = props
return h('li', [
h('a', { href: link }, text),
children
? h(
'ul',
children.map((c) => h(SideBarItem, { item: c }))
)
: null
const route = useRoute()
const pageData = usePageData()
const active = isActive(route, link)
const headers = pageData.value.headers
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[]
interface ResolvedSidebarItem {
@ -104,7 +111,7 @@ function resolveArraySidebar(
config: DefaultTheme.SideBarItem[],
depth: number
): ResolvedSidebar {
return []
return config
}
function resolveMultiSidebar(
@ -114,3 +121,59 @@ function resolveMultiSidebar(
): ResolvedSidebar {
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>
<div class="sidebar">
<ul>
<SideBarItem v-for="item of items" :item="item"></SideBarItem>
</ul>
</div>
<ul class="sidebar">
<SideBarItem v-for="item of items" :item="item" />
</ul>
</template>
<script src="./SideBar"></script>
<style>
.sidebar ul {
.sidebar,
.sidebar-items {
list-style-type: none;
line-height: 2;
padding: 0;
margin: 0;
}
.sidebar a {
display: inline-block;
color: var(--text-color);
padding-left: 1.5rem;
.sidebar-items .sidebar-items {
padding-left: 1rem;
}
.sidebar a:hover {
color: var(--accent-color);
.sidebar-items .sidebar-items .sidebar-link {
border-left: 0;
}
.sidebar a.active {
color: var(--accent-color);
.sidebar-items .sidebar-items .sidebar-link.active {
font-weight: 500;
}
.sidebar > ul > li > a.active {
padding-left: 1.25rem;
border-left: .25rem solid var(--accent-color);
.sidebar-items .sidebar-link {
padding: .35rem 1rem .35rem 2rem;
line-height: 1.4;
font-size: 0.9em;
font-weight: 400;
}
.sidebar ul ul {
font-size: 0.9em;
padding-left: 1rem;
.sidebar-link {
display: block;
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>

@ -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) {
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: {
path: resolver.fileToRequest(file),
pageData
},
timestamp: Date.now()
}
})
// reload the content component

Loading…
Cancel
Save