Files
dekun a8907d6cc0 Improve mobile reading layout and typography
Make classic text chapters easier to read on phones with responsive styles, collapsed sidebar groups, and less intrusive install prompts on doc pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 17:57:57 +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: true,
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: true,
items,
})
}
return { '/': groups }
}