diff --git a/.vitepress/config.mts b/.vitepress/config.mts index 75e57bc..2e1112b 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -9,7 +9,7 @@ import { generateSidebar } from './sidebar.mts' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') export default defineConfig({ - title: 'DAO DE JING', + title: '道德经', description: '传统文化典籍资料库', lang: 'zh-CN', srcDir: '.', diff --git a/.vitepress/pwa.mts b/.vitepress/pwa.mts index 2f8d99a..5997086 100644 --- a/.vitepress/pwa.mts +++ b/.vitepress/pwa.mts @@ -27,6 +27,12 @@ export function createPwaPlugin() { start_url: '/', categories: ['books', 'education'], icons: [ + { + src: '/apple-touch-icon.png', + sizes: '180x180', + type: 'image/png', + purpose: 'any', + }, { src: '/icon-192.png', sizes: '192x192', diff --git a/.vitepress/theme/custom.css b/.vitepress/theme/custom.css index 33b4712..d67a086 100644 --- a/.vitepress/theme/custom.css +++ b/.vitepress/theme/custom.css @@ -3,15 +3,25 @@ 'Noto Sans SC', 'Source Han Sans SC', sans-serif; } +html { + overflow-x: clip; +} + /* 旧版 markdown 里的 在手机上过大 */ -.vp-doc font { +.vp-doc font, +.vp-md-font { + display: block; + max-width: 100%; font-size: inherit !important; + overflow-wrap: anywhere; } .vp-doc { line-height: 1.85; letter-spacing: 0.02em; word-break: break-word; + overflow-wrap: anywhere; + max-width: 100%; } .vp-doc h1 { @@ -32,13 +42,20 @@ .vp-doc p { margin: 1em 0; + overflow-wrap: anywhere; } /* 道德经等用缩进写的“伪代码块”,改成正文排版 */ -.vp-doc pre { - white-space: pre-wrap; +.vp-doc pre, +.vp-doc pre code { + white-space: pre-wrap !important; word-break: break-word; + overflow-wrap: anywhere; +} + +.vp-doc pre { overflow-x: auto; + max-width: 100%; font-family: var(--vp-font-family-base); font-size: 1rem; line-height: 1.9; @@ -51,11 +68,13 @@ .vp-doc :not(pre) > code { font-size: 0.92em; word-break: break-word; + overflow-wrap: anywhere; } .vp-doc img { display: block; max-width: 100% !important; + width: auto !important; height: auto !important; margin: 1em auto; border-radius: 8px; @@ -66,6 +85,7 @@ overflow-x: auto; -webkit-overflow-scrolling: touch; font-size: 0.92rem; + max-width: 100%; } .vp-doc blockquote { @@ -91,6 +111,16 @@ padding-top: 0; } + .VPDoc .container, + .VPDoc .content, + .VPDoc .content-container, + .vp-doc, + .vp-md-font { + min-width: 0; + max-width: 100%; + box-sizing: border-box; + } + .VPDoc .container { padding: 0 14px; } @@ -100,7 +130,7 @@ } .vp-doc { - padding: 12px 0 88px; + padding: 8px 0 88px; font-size: 17px; } @@ -109,8 +139,9 @@ } /* 手机隐藏右侧大纲,避免挤压正文 */ - .VPDoc .aside { - display: none; + .VPDoc .aside, + .VPDoc .aside-container { + display: none !important; } .VPDoc.has-aside .content-container { diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts index 0c99811..eda76b3 100644 --- a/.vitepress/theme/index.ts +++ b/.vitepress/theme/index.ts @@ -1,5 +1,5 @@ import DefaultTheme from 'vitepress/theme' -import { h } from 'vue' +import { h, defineComponent } from 'vue' import InstallApp from './InstallApp.vue' import './custom.css' @@ -9,8 +9,19 @@ if (typeof window !== 'undefined') { }) } +/** 旧 markdown 的 标签改为 div,避免手机端布局溢出 */ +const MdFont = defineComponent({ + name: 'MdFont', + setup(_, { slots }) { + return () => h('div', { class: 'vp-md-font' }, slots.default?.()) + }, +}) + export default { extends: DefaultTheme, + enhanceApp({ app }) { + app.component('font', MdFont) + }, Layout: () => { return h(DefaultTheme.Layout, null, { 'layout-bottom': () => h(InstallApp), diff --git a/assets/site/favicon.svg b/assets/site/favicon.svg index 9ab23b2..f378fb4 100644 --- a/assets/site/favicon.svg +++ b/assets/site/favicon.svg @@ -1,11 +1,11 @@ - + - - + + - S + diff --git a/scripts/generate-icons.mjs b/scripts/generate-icons.mjs index 81f1830..2d9b900 100644 --- a/scripts/generate-icons.mjs +++ b/scripts/generate-icons.mjs @@ -7,14 +7,22 @@ import toIco from 'to-ico' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') const siteDir = path.join(root, 'assets', 'site') const sourcePng = path.join(siteDir, 'apple-touch-icon.png') +const sourceSvg = path.join(siteDir, 'favicon.svg') -if (!fs.existsSync(sourcePng)) { - console.warn('[generate-icons] 跳过:未找到 apple-touch-icon.png') +function resolveSource() { + if (fs.existsSync(sourcePng)) return sourcePng + if (fs.existsSync(sourceSvg)) return sourceSvg + return null +} + +const source = resolveSource() +if (!source) { + console.warn('[generate-icons] 跳过:未找到 apple-touch-icon.png 或 favicon.svg') process.exit(0) } async function resizePng(size) { - return sharp(sourcePng).resize(size, size).png().toBuffer() + return sharp(source, { density: 300 }).resize(size, size).png().toBuffer() } const icoSizes = [16, 32, 48, 64, 128, 256] @@ -26,4 +34,4 @@ fs.writeFileSync(path.join(siteDir, 'icon-192.png'), await resizePng(192)) fs.writeFileSync(path.join(siteDir, 'icon-512.png'), await resizePng(512)) fs.writeFileSync(path.join(siteDir, 'favicon.png'), await resizePng(512)) -console.log('[generate-icons] 已生成 favicon.ico、icon-192.png、icon-512.png') +console.log(`[generate-icons] 已从 ${path.basename(source)} 生成 favicon.ico、icon-192.png、icon-512.png`) diff --git a/server/index.js b/server/index.js index 86323ac..c47d23c 100644 --- a/server/index.js +++ b/server/index.js @@ -162,6 +162,15 @@ app.get('/api/me', authGuard, (req, res) => { app.use(authGuard) +function sendDistFile(res, relativePath, contentType) { + const filePath = path.join(distPath, relativePath) + if (!fs.existsSync(filePath)) { + return res.status(404).end('Not Found') + } + if (contentType) res.type(contentType) + return res.sendFile(filePath) +} + if (!fs.existsSync(distPath)) { console.error( '未找到构建产物 .vitepress/dist,请先运行: npm run build', @@ -169,10 +178,19 @@ if (!fs.existsSync(distPath)) { process.exit(1) } +app.get('/site.webmanifest', (req, res) => { + sendDistFile(res, 'site.webmanifest', 'application/manifest+json') +}) + app.use( express.static(distPath, { index: false, fallthrough: true, + setHeaders(res, filePath) { + if (filePath.endsWith('.webmanifest')) { + res.setHeader('Content-Type', 'application/manifest+json') + } + }, }), )