From aaa9cd9274dcfead57caca6a39a3566c6395c31c Mon Sep 17 00:00:00 2001 From: wait4xx Date: Mon, 2 Nov 2026 18:40:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(typography):=20=E5=85=A8=E7=AB=99=E4=B8=89?= =?UTF-8?q?=E5=B1=82=E6=8E=92=E7=89=88=E2=80=94=E2=80=94=E5=AF=8C=E6=96=87?= =?UTF-8?q?=E6=9C=AC/=E9=A1=B5=E9=9D=A2=E7=BA=A7=E8=A6=86=E7=9B=96/?= =?UTF-8?q?=E8=89=BA=E6=9C=AF=E5=AD=97=E4=BD=93=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 层 1 所有页面文案改富文本:site-content 新增 renderRich(md,{inline}) 复用既有全管线(raw→内容净化→class 白名单→链接卡片);接入 home.tagline/subtitle、opensource.blurb、about.intro、blocks prose; 新增 .rich 容器作用域并与 .prose-body 合并(77 处选择器覆盖四类容器) 坑:renderRich 输出

塞进

会被浏览器拆散 → 行内场景用 {inline:true} 剥外层

- 层 2 页面级排版覆盖:三单例加 typography{font?,accent?,scale?},读取器 pageTypography() 走白名单(10 字族 / 18 色类,scale 夹 0.8–1.25,清单外 忽略);页面容器挂 .page-typo + CSS 变量 --page-font/--page-accent/ --page-scale,不动全站 tokens;后台三页加「页面排版覆盖」下拉 - 层 3 艺术字体:新增 font-art-kuaile(快乐体专用类,字距微调),白名单与 可视化面板同步;站酷高端黑/阿里妈妈东方大楷/演示悠然小楷因无 npm 包或 嵌入条款风险进候补清单 - 默认值清理:about.yaml 的 typography 测试值(整页汇文)清为注释示例—— 整页换字族会带来 694KB 字体成本,默认留空=全站默认排版 验证: 构建 48 页 exit 0;E2E 37/37;三页 page-typo 挂载与变量实测、四页 (图库/书架/文章/装备)隔离为 0、font-art-kuaile 生效、about 清空后 无覆盖 Spec: none (排版三层,先于 5g 的任务;T3/T4 另行交付) Co-authored-by: GLM-5.3 --- content/site/about.yaml | 9 ++- docs/写作指南.md | 26 +++++++++ public/admin/typography-classes.js | 1 + src/content.config.ts | 23 ++++++++ src/lib/rehype-class-whitelist.ts | 1 + src/pages/en/index.astro | 8 ++- src/pages/en/opensource.astro | 9 ++- src/pages/index.astro | 8 ++- src/pages/opensource.astro | 10 +++- src/styles/global.css | 89 +++++++++++++++++------------- 10 files changed, 136 insertions(+), 48 deletions(-) diff --git a/content/site/about.yaml b/content/site/about.yaml index 1f317e6..0e07f45 100644 --- a/content/site/about.yaml +++ b/content/site/about.yaml @@ -82,6 +82,9 @@ intro: This is the public workbench of my three tracks: **books** that left notes, **code** that reaches the project wall, and **shutters** I pressed that land in the gallery. # 页面级排版覆盖(层 2) -typography: - font: font-huiwen - accent: c-red +# 页面级排版覆盖(后台「关于页 → 页面排版覆盖」可改): +# 整页换字族会带来字体体积成本(如 font-huiwen 整页 ≈694KB),默认留空=全站默认排版 +# typography: +# font: font-huiwen # 字族:font-serif/font-sans/font-kai/font-huiwen/font-kuaile… +# accent: c-red # 强调色类:c-blue/c-red/…(外壳仍灰阶) +# scale: 1.05 # 字号缩放 0.8–1.25 diff --git a/docs/写作指南.md b/docs/写作指南.md index dd9f734..545af22 100644 --- a/docs/写作指南.md +++ b/docs/写作指南.md @@ -185,6 +185,32 @@ https://astro.build/ 后台编辑器里:**选中文字 → Insert 菜单 → 「排版(字体/颜色)」→ 面板里点一个类**,文字即被 `` 包住;点已套用的片段可改类,Backspace 可整体删除。 面板里的两类与上表一一对应(字体 8 / 颜色 9),类清单单一事实源在 `public/admin/typography-classes.js`。 +## 三层排版架构(全站,不只文章正文) + +**层 1 · 页面文案富文本**:后台「页面文案」里的 tagline / subtitle / blurb / blurb_after / intro / 关于页 blocks 的 prose 块,全部走同一条富文本管线(markdown + raw + 内容净化 + class 白名单 + 链接卡片)。可以直接写: + +```yaml +tagline: + zh: '写作者 · 读者 · 快门按压者,拥抱开源。' +``` + +渲染入口唯一:`src/lib/site-content.ts` 的 `renderRich()`(行内场景传 `{ inline: true }` 自动剥外层 `

`,否则 `

` 套 `

` 会被浏览器拆散)。 +**不开放**:导航/页脚/按钮等硬编码界面外壳——那是 UI 不是内容。 + +**层 2 · 页面级排版覆盖**:每个页面单例(`content/site/*.yaml`)可加: + +```yaml +typography: + font: font-kai # 本页正文默认字体类(可选) + accent: c-blue # 本页强调色类(可选) + scale: 1.1 # 字号缩放 0.8–1.25(可选) +``` + +实现是在该页内容容器上挂 `.page-typo` + CSS 变量(`--page-font / --page-accent / --page-scale`),**不写全站 tokens**——其它页面零影响(已在图库/书架/文章/装备页验证隔离)。白名单外的类名会被忽略。 +后台入口:「页面文案 → 各自页面 → 页面排版覆盖」。 + +**层 3 · 艺术字体**:`font-art-kuaile`(站酷快乐体,艺术字专用类)。⚠️ **仅用于标题/短句**:艺术字字形大,CJK 切片体积高(实测用到页 +163KB),长段使用会显著抬高单页字体成本。 + ## 发布提醒 - push main → webhook 自动构建发布(约 10 秒) diff --git a/public/admin/typography-classes.js b/public/admin/typography-classes.js index 53f4388..5e91788 100644 --- a/public/admin/typography-classes.js +++ b/public/admin/typography-classes.js @@ -18,6 +18,7 @@ window.TYPOGRAPHY_CLASSES = { { cls: 'font-fangsong', label: '仿宋族', family: 'FangSong, STFangsong, serif', kind: '系统回退' }, { cls: 'font-huiwen', label: '汇文明朝体', family: '"WF-Hwmc", serif', kind: '自托管' }, { cls: 'font-kuaile', label: '站酷快乐体', family: '"ZCOOL KuaiLe", serif', kind: '自托管' }, + { cls: 'font-art-kuaile', label: '快乐体(艺术·仅标题)', family: '"ZCOOL KuaiLe", serif', kind: '艺术字' }, ], color: [ { cls: 'ink-1', label: '最重(标题级)', swatch: '#111113' }, diff --git a/src/content.config.ts b/src/content.config.ts index 7784a7d..28b222f 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -205,6 +205,29 @@ export const collections = { .optional(), }), }), + // 主题旋钮(样式即数据 · 层 4):只放 9 组白名单旋钮,钳制与单调性在 src/lib/theme.ts + siteTheme: defineCollection({ + loader: glob({ pattern: 'theme.yaml', base: './content/site' }), + schema: z.object({ + accent_light: z.string().optional(), + accent_dark: z.string().optional(), + radius_img: z.number().optional(), + text_h1: z.number().optional(), + text_h2: z.number().optional(), + text_h3: z.number().optional(), + prose_size_reading: z.number().optional(), + prose_size_tech: z.number().optional(), + leading_reading: z.number().optional(), + leading_tech: z.number().optional(), + space_3: z.number().optional(), + space_4: z.number().optional(), + space_5: z.number().optional(), + space_6: z.number().optional(), + flow_p: z.number().optional(), + flow_h2_post: z.number().optional(), + dur: z.number().optional(), + }), + }), siteAbout: defineCollection({ loader: glob({ pattern: 'about.yaml', base: './content/site' }), // intro = 多段 markdown 正文(二级回退:blocks 为空时才用) diff --git a/src/lib/rehype-class-whitelist.ts b/src/lib/rehype-class-whitelist.ts index 7d2ef41..354cbec 100644 --- a/src/lib/rehype-class-whitelist.ts +++ b/src/lib/rehype-class-whitelist.ts @@ -46,6 +46,7 @@ const ALLOWED = new Set([ 'font-fangsong', 'font-huiwen', 'font-kuaile', + 'font-art-kuaile', // 文学排版 'drop-cap', 'quote-line', diff --git a/src/pages/en/index.astro b/src/pages/en/index.astro index 26fcbd3..363f89e 100644 --- a/src/pages/en/index.astro +++ b/src/pages/en/index.astro @@ -8,7 +8,7 @@ import PostList from '../../components/PostList.astro'; import ProjectWall from '../../components/geek/ProjectWall.astro'; import Heatmap from '../../components/geek/Heatmap.astro'; import { t } from '../../i18n/ui'; -import { homeConfig, homeTagline, renderMarkdown } from '../../lib/site-content'; +import { homeConfig, homeTagline, pageTypography, renderMarkdown, renderRich } from '../../lib/site-content'; import SocialLinks from '../../components/SocialLinks.astro'; // 首页可配项(后台主页设置):副标题/影像张数/区块开关/每轨条数,字段级回落 @@ -24,11 +24,14 @@ const enTitle = Object.fromEntries( const photos = (await getCollection('photos')).slice(0, Math.max(1, cfg.latestPhotos)); // 身份语与 zh 版同源(content/site/home.yaml 的 en 字段),缺值回落默认 const tagline = await homeTagline('en'); +const taglineHtml = await renderRich(tagline, { inline: true }); +const typo = await pageTypography('siteHome', 'home'); --- +

-

{tagline}

+

{subtitleHtml &&

} @@ -66,6 +69,7 @@ const tagline = await homeTagline('en'); }} />} {cfg.sections.projects && } +