mirror of https://github.com/vuejs/vitepress
parent
1be0a0b0a1
commit
3d2f7e27de
@ -0,0 +1,33 @@
|
|||||||
|
// TODO dropdowns
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useSiteData, useRoute } from 'vitepress'
|
||||||
|
import { withBase } from '../utils'
|
||||||
|
|
||||||
|
const normalizePath = (path: string): string => {
|
||||||
|
path = path
|
||||||
|
.replace(/#.*$/, '')
|
||||||
|
.replace(/\?.*$/, '')
|
||||||
|
.replace(/\.html$/, '')
|
||||||
|
if (path.endsWith('/')) {
|
||||||
|
path += 'index'
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const route = useRoute()
|
||||||
|
const isActiveLink = (link: string): boolean => {
|
||||||
|
return normalizePath(withBase(link)) === normalizePath(route.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
withBase,
|
||||||
|
isActiveLink,
|
||||||
|
// use computed in dev for hot reload
|
||||||
|
navData: __DEV__
|
||||||
|
? computed(() => useSiteData().value.themeConfig.nav)
|
||||||
|
: useSiteData().value.themeConfig.nav
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
import { useSiteData, usePageData, useRoute } from 'vitepress'
|
||||||
|
import { computed, h, FunctionalComponent } from 'vue'
|
||||||
|
import { Header } from '../../../../types/shared'
|
||||||
|
import { DefaultTheme } from '../config'
|
||||||
|
|
||||||
|
const SideBarItem: FunctionalComponent<{
|
||||||
|
item: ResolvedSidebarItem
|
||||||
|
}> = (props) => {
|
||||||
|
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
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SideBarItem
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const pageData = usePageData()
|
||||||
|
const siteData = useSiteData()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const resolveSidebar = () => {
|
||||||
|
const {
|
||||||
|
headers,
|
||||||
|
frontmatter: { sidebar, sidebarDepth = 2 }
|
||||||
|
} = pageData.value
|
||||||
|
|
||||||
|
if (sidebar === 'auto') {
|
||||||
|
// auto, render headers of current page
|
||||||
|
return resolveAutoSidebar(headers, sidebarDepth)
|
||||||
|
} else if (Array.isArray(sidebar)) {
|
||||||
|
// in-page array config
|
||||||
|
return resolveArraySidebar(sidebar, sidebarDepth)
|
||||||
|
} else if (sidebar === false) {
|
||||||
|
return []
|
||||||
|
} else {
|
||||||
|
// no explicit page sidebar config
|
||||||
|
// check global theme config
|
||||||
|
const { sidebar: themeSidebar } = siteData.value.themeConfig
|
||||||
|
if (themeSidebar === 'auto') {
|
||||||
|
return resolveAutoSidebar(headers, sidebarDepth)
|
||||||
|
} else if (Array.isArray(themeSidebar)) {
|
||||||
|
return resolveArraySidebar(themeSidebar, sidebarDepth)
|
||||||
|
} else if (themeSidebar === false) {
|
||||||
|
return []
|
||||||
|
} else if (typeof themeSidebar === 'object') {
|
||||||
|
return resolveMultiSidebar(themeSidebar, route.path, sidebarDepth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: __DEV__ ? computed(resolveSidebar) : resolveSidebar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolvedSidebar = ResolvedSidebarItem[]
|
||||||
|
|
||||||
|
interface ResolvedSidebarItem {
|
||||||
|
text: string
|
||||||
|
link?: string
|
||||||
|
isGroup?: boolean
|
||||||
|
children?: ResolvedSidebarItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveAutoSidebar(headers: Header[], depth: number): ResolvedSidebar {
|
||||||
|
const ret: ResolvedSidebar = []
|
||||||
|
|
||||||
|
let lastH2: ResolvedSidebarItem | undefined = undefined
|
||||||
|
headers.forEach(({ level, title, slug }) => {
|
||||||
|
if (level - 1 > depth) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const item: ResolvedSidebarItem = {
|
||||||
|
text: title,
|
||||||
|
link: `#${slug}`
|
||||||
|
}
|
||||||
|
if (level === 2) {
|
||||||
|
lastH2 = item
|
||||||
|
ret.push(item)
|
||||||
|
} else if (lastH2) {
|
||||||
|
;(lastH2.children || (lastH2.children = [])).push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveArraySidebar(
|
||||||
|
config: DefaultTheme.SideBarItem[],
|
||||||
|
depth: number
|
||||||
|
): ResolvedSidebar {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveMultiSidebar(
|
||||||
|
config: DefaultTheme.MultiSideBarConfig,
|
||||||
|
path: string,
|
||||||
|
depth: number
|
||||||
|
): ResolvedSidebar {
|
||||||
|
return []
|
||||||
|
}
|
@ -1,5 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="sidebar">
|
<div class="sidebar">
|
||||||
<li>sidebar</li>
|
<ul>
|
||||||
|
<SideBarItem v-for="item of items" :item="item"></SideBarItem>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script src="./SideBar"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar ul {
|
||||||
|
list-style-type: none;
|
||||||
|
line-height: 2;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar a:hover {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar ul ul {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
.custom-block .custom-block-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: -0.4rem;
|
||||||
|
}
|
||||||
|
.custom-block.tip,
|
||||||
|
.custom-block.warning,
|
||||||
|
.custom-block.danger {
|
||||||
|
padding: 0.1rem 1.5rem;
|
||||||
|
border-left-width: 0.5rem;
|
||||||
|
border-left-style: solid;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
.custom-block.tip {
|
||||||
|
background-color: #f3f5f7;
|
||||||
|
border-color: #42b983;
|
||||||
|
}
|
||||||
|
.custom-block.warning {
|
||||||
|
background-color: rgba(255, 229, 100, 0.3);
|
||||||
|
border-color: #e7c000;
|
||||||
|
color: #6b5900;
|
||||||
|
}
|
||||||
|
.custom-block.warning .custom-block-title {
|
||||||
|
color: #b29400;
|
||||||
|
}
|
||||||
|
.custom-block.warning a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
.custom-block.danger {
|
||||||
|
background-color: #ffe6e6;
|
||||||
|
border-color: #c00;
|
||||||
|
color: #4d0000;
|
||||||
|
}
|
||||||
|
.custom-block.danger .custom-block-title {
|
||||||
|
color: #900;
|
||||||
|
}
|
||||||
|
.custom-block.danger a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
.custom-block.details {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 1.6em 0;
|
||||||
|
padding: 1.6em;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
.custom-block.details h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.custom-block.details figure:last-child,
|
||||||
|
.custom-block.details p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
.custom-block.details summary {
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
Loading…
Reference in new issue