Files
DAO_DE_JING/.vitepress/sidebar.mts
T
dekun 68d816b3f3 Add VitePress site with local login and deployment docs
Enable static site build on port 12100 with Express session auth, auto sidebar, and DEPLOY.md for Ubuntu/NPS setup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 16:12:35 +08:00

113 lines
2.9 KiB
TypeScript

import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const EXCLUDE_DIRS = new Set([
'node_modules',
'.vitepress',
'server',
'assets',
'images',
'.git',
'金瓶梅',
'黄帝内经',
'健康学习到150岁 - 人体系统调优不完全指南',
'梅花',
])
type SidebarItem = {
text: string
link?: string
collapsed?: boolean
items?: SidebarItem[]
}
function naturalCompare(a: string, b: string) {
return a.localeCompare(b, 'zh-CN', { numeric: true, sensitivity: 'base' })
}
function titleFromFilename(name: string) {
const base = name.replace(/\.md$/i, '')
if (/^readme$/i.test(base)) return '导读'
return base
}
function toLink(relativePath: string) {
const normalized = relativePath.replace(/\\/g, '/').replace(/\.md$/i, '')
if (normalized.endsWith('/README')) {
return `/${normalized.slice(0, -'/README'.length)}/`
}
return `/${normalized}`
}
function collectItems(dir: string, relativeDir: string): SidebarItem[] {
const entries = fs.readdirSync(dir, { withFileTypes: true })
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
const subdirs = entries.filter((entry) => entry.isDirectory())
const items: SidebarItem[] = files
.sort((a, b) => naturalCompare(a.name, b.name))
.map((file) => ({
text: titleFromFilename(file.name),
link: toLink(path.join(relativeDir, file.name)),
}))
for (const subdir of subdirs.sort((a, b) => naturalCompare(a.name, b.name))) {
const subRelative = path.join(relativeDir, subdir.name)
const subItems = collectItems(path.join(dir, subdir.name), subRelative)
if (subItems.length === 0) continue
items.push({
text: subdir.name,
collapsed: true,
items: subItems,
})
}
return items
}
export function generateSidebar(): Record<string, SidebarItem[]> {
const groups: SidebarItem[] = []
const rootFiles = fs
.readdirSync(root, { withFileTypes: true })
.filter(
(entry) =>
entry.isFile() &&
entry.name.endsWith('.md') &&
entry.name !== 'README.md' &&
entry.name !== 'index.md',
)
.sort((a, b) => naturalCompare(a.name, b.name))
if (rootFiles.length > 0) {
groups.push({
text: '典籍',
collapsed: false,
items: rootFiles.map((file) => ({
text: titleFromFilename(file.name),
link: toLink(file.name),
})),
})
}
const dirs = fs
.readdirSync(root, { withFileTypes: true })
.filter((entry) => entry.isDirectory() && !EXCLUDE_DIRS.has(entry.name))
.sort((a, b) => naturalCompare(a.name, b.name))
for (const dir of dirs) {
const items = collectItems(path.join(root, dir.name), dir.name)
if (items.length === 0) continue
groups.push({
text: dir.name,
collapsed: false,
items,
})
}
return { '/': groups }
}