Skip to content

Commit

Permalink
feat: add array sidebar support (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
kiaking authored Jul 2, 2020
1 parent da8df19 commit 4a8388e
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/client/app/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
83 changes: 73 additions & 10 deletions src/client/theme-default/components/SideBar.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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)
])
}

Expand Down Expand Up @@ -67,6 +70,10 @@ export default {
}
}

interface HeaderWithChildren extends Header {
children?: Header[]
}

type ResolvedSidebar = ResolvedSidebarItem[]

interface ResolvedSidebarItem {
Expand Down Expand Up @@ -104,7 +111,7 @@ function resolveArraySidebar(
config: DefaultTheme.SideBarItem[],
depth: number
): ResolvedSidebar {
return []
return config
}

function resolveMultiSidebar(
Expand All @@ -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
}))
}
58 changes: 38 additions & 20 deletions src/client/theme-default/components/SideBar.vue
Original file line number Diff line number Diff line change
@@ -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>
20 changes: 19 additions & 1 deletion src/client/theme-default/utils.ts
Original file line number Diff line number Diff line change
@@ -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, '')
}
3 changes: 1 addition & 2 deletions src/node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ function createVitePressPlugin({
customData: {
path: resolver.fileToRequest(file),
pageData
},
timestamp: Date.now()
}
})

// reload the content component
Expand Down

0 comments on commit 4a8388e

Please sign in to comment.