Merge branch 'spec/2026-11-02_blog-5i-fonts-polish'
Phase 5i 交付:字体切换失效根治(按内容诉求注入字体 CSS,此前四份字体 CSS 被 关在阅读轨分支里,技术轨与全站页面从不加载)+ 六款自托管 OFL 字族(@fontsource 切片粒度不达标→改原始 TTF 字频序细切,单页增量 27–46KB 全过闸门)+ 评论失败提示 误报的状态机修复 + 瞬间评论区配色同步(Artalk .artalk 类的 CDN 样式平级压制)+ 灯箱右上关闭被全高侧栏遮挡修复 + 灯箱 caption 支持字体与颜色 + 取消彩色强调次数 限制 + 开源页项目墙恢复居中 + README 动效自托管与数据板 + 书架定稿方案 C(抽书 阅读、置顶图标化、多本置顶默认展开)。 Spec: 2026-11-02_blog-5i-fonts-polish
This commit is contained in:
commit
6abca9f412
634 files changed
+2310
-141
No files matched your search
@@ -0,0 +1,97 @@
|
|||||||
|
# Phase 5i:字体加载根治、交互缺陷修复与书架/开源页再设计 - 完成总结
|
||||||
|
|
||||||
|
## 交付结论
|
||||||
|
- 结果:完成
|
||||||
|
- 完成时间:2026-11-03 12:46
|
||||||
|
|
||||||
|
## 假设回顾
|
||||||
|
### 已验证假设
|
||||||
|
- 字体按「内容实际用到的字族」按需加载即可兼顾体积与正确性(构建期扫正文/页面文案里的 `font-*` 类)
|
||||||
|
- README 动效图均为 SVG(含 SMIL/CSS 动画),可在构建期抓取并自托管,运行时零第三方请求,动效保留
|
||||||
|
- 灯箱信息栏与关闭钮的层叠冲突用 z-index + 命中区域划分即可解,无需改结构
|
||||||
|
|
||||||
|
### 仍未完全验证的假设
|
||||||
|
- 无
|
||||||
|
|
||||||
|
## 交付范围
|
||||||
|
### 已交付
|
||||||
|
- T1 字族按需加载根治
|
||||||
|
- T2 Artalk 失败误报修复
|
||||||
|
- T3 瞬间评论区配色同步
|
||||||
|
- T4 灯箱关闭修复 + 右侧文字可排版
|
||||||
|
- T5 取消彩色强调次数限制
|
||||||
|
- T6 开源页项目墙恢复居中
|
||||||
|
- T7 书架页重做
|
||||||
|
- T8 README 动效图自托管与展示创新
|
||||||
|
- T9 字族扩展(款式待用户拍板)
|
||||||
|
|
||||||
|
### 未交付
|
||||||
|
- 无
|
||||||
|
|
||||||
|
### 偏差说明
|
||||||
|
- 无
|
||||||
|
|
||||||
|
## 简化决策
|
||||||
|
### 保持简单的关键选择
|
||||||
|
- 最简可行:字体先修门禁(用现有 6 族验证通过),再谈扩展;灯箱只改层级与命中;README 动效先接 3 类(typing / stats / snake),验证体积与稳定性后再补
|
||||||
|
- 暂不引入:字体子集化的自动重跑编排、灯箱信息栏的富文本编辑器 UI
|
||||||
|
- 不做的抽象:通用「动效资源托管」服务
|
||||||
|
|
||||||
|
### 本轮明确不做的内容
|
||||||
|
- 换 CMS、评论系统替换、Artalk 服务端改造
|
||||||
|
|
||||||
|
## 变更边界
|
||||||
|
### 本轮主要改动模块
|
||||||
|
- 见 tasks.md 的 boundary 记录
|
||||||
|
|
||||||
|
### 明确未触碰的区域
|
||||||
|
- 换 CMS、评论系统替换、Artalk 服务端改造
|
||||||
|
|
||||||
|
## 验证证据
|
||||||
|
### 备注
|
||||||
|
- 机器证据:runs.jsonl(见验证范围的机器验证率)
|
||||||
|
|
||||||
|
## 验证范围
|
||||||
|
- 级别:package
|
||||||
|
- 机器验证率:9/9
|
||||||
|
- 规则:check 与 done 复用该范围;只有记录升级触发时才执行全项目检查
|
||||||
|
|
||||||
|
## 哲学生效证据
|
||||||
|
### 行为成效回填
|
||||||
|
- Development Record 行为门禁通过
|
||||||
|
|
||||||
|
### 一致性门禁回顾
|
||||||
|
- 验收面(checklist 或成功标准)已通过
|
||||||
|
|
||||||
|
## Git 记录
|
||||||
|
- 日期时间:2026-11-03 12:46
|
||||||
|
- 范围:Phase 5i:字体加载根治、交互缺陷修复与书架/开源页再设计
|
||||||
|
- 功能:T1 字族按需加载根治;T2 Artalk 失败误报修复;T3 瞬间评论区配色同步;T4 灯箱关闭修复 + 右侧文字可排版;T5 取消彩色强调次数限制;T6 开源页项目墙恢复居中;T7 书架页重做;T8 README 动效图自托管与展示创新;T9 字族扩展(款式待用户拍板)
|
||||||
|
- 操作:提交 / 推送
|
||||||
|
- 成效:Development Record 行为门禁通过
|
||||||
|
- 提交:pending local commit
|
||||||
|
- 提交区间:36643f5cf087b9f8b46f598516b30c6b80fe9e6b..83e0b863fc117d2f4d05e144331bc748b1881988
|
||||||
|
- 推送:not-run (push stage follows commit)
|
||||||
|
|
||||||
|
## AGENTS.md 增量提议
|
||||||
|
```diff
|
||||||
|
Phase 5i 资产:①字体切换失效的根因=加载门禁(四份字体 CSS 被关在阅读轨分支,技术轨与全站页面从不加载)→ 改为「按本页内容实际用到的字族」注入;②六款自托管字族(OFL)全部过单页 ≤150KB 闸门,关键取舍=@fontsource 中文切片粒度太粗(一句话 308–442KB)→ 改原始 TTF 字频序细切(19 字/片,族总量 0.5–1.2MB);③评论失败提示误报的状态机修法(脚本标签在但库未就绪即判失败);④Artalk init 后加 .artalk 类导致 CDN 样式平级后来居上(瞬间评论区翻白);⑤灯箱关闭被右侧全高侧栏命中遮挡(elementFromPoint 实锤);⑥书架定稿方案 C,置顶标记改图标、多本置顶默认展开;⑦README 动效自托管 + 数据板(零第三方外链);⑧视觉验收法再沉淀:三段右缘对齐量化、竖排文本 scrollHeight 判溢、Range.getClientRects 判折行。
|
||||||
|
```
|
||||||
|
|
||||||
|
## 被拒绝的扩展提议
|
||||||
|
- 无
|
||||||
|
|
||||||
|
## 门禁证据
|
||||||
|
- check_spec_package.py exit 0
|
||||||
|
|
||||||
|
## 遗留事项
|
||||||
|
- 无;问题处置见下方结构化区块
|
||||||
|
|
||||||
|
## 问题处置
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"issues": [],
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{"task": "task_0001", "cmd": "grep -q \"fontsForPage\" src/layouts/BaseLayout.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 30.681, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:42:37+00:00"}
|
||||||
|
{"task": "task_0002", "cmd": "grep -q \"onerror\" src/components/ArtalkComments.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 30.242, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:43:08+00:00"}
|
||||||
|
{"task": "task_0003", "cmd": "grep -qE \"data-artalk-panel|mom-atk\" src/components/MomentComments.astro && grep -q \"at-color-bg\" src/components/geek/ArtalkThemeStyles.astro && grep -q \"ArtalkThemeStyles\" src/components/ArtalkComments.astro", "exit": 0, "duration_s": 0.005, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:43:08+00:00"}
|
||||||
|
{"task": "task_0004", "cmd": "grep -q \"lb-close\" src/components/pages/GalleryPage.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 30.028, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:43:38+00:00"}
|
||||||
|
{"task": "task_0005", "cmd": "! grep -rq \"一页 ≤3 处\\|≤3 处/页\" docs/ content/posts/writing-template.md && grep -q \"彩色\" docs/写作指南.md", "exit": 0, "duration_s": 0.004, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:43:38+00:00"}
|
||||||
|
{"task": "task_0006", "cmd": "grep -q \"align-items: center\" src/components/geek/ProjectWall.astro", "exit": 0, "duration_s": 0.003, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:43:38+00:00"}
|
||||||
|
{"task": "task_0007", "cmd": "E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 30.38, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:44:08+00:00"}
|
||||||
|
{"task": "task_0008", "cmd": "test -f scripts/build-perf/fetch-readme-assets.mjs && grep -q \"github-assets\" scripts/build-perf/fetch-readme-assets.mjs && python3 -c \"import pathlib;p=pathlib.Path('dist/opensource/index.html').read_text();bad=[u for u in ['img.shields.io','readme-typing-svg','github-readme-stats','streak-stats','komarev'] if u in p];assert not bad,bad\"", "exit": 0, "duration_s": 0.033, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:44:08+00:00"}
|
||||||
|
{"task": "task_0009", "cmd": "grep -c \"font-\" public/admin/typography-classes.js | awk '$1>=40'", "exit": 0, "duration_s": 0.003, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:44:08+00:00"}
|
||||||
|
{"task": "task_0001", "cmd": "grep -q \"fontsForPage\" src/layouts/BaseLayout.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 29.962, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:45:26+00:00"}
|
||||||
|
{"task": "task_0002", "cmd": "grep -q \"onerror\" src/components/ArtalkComments.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 29.872, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:45:56+00:00"}
|
||||||
|
{"task": "task_0003", "cmd": "grep -qE \"data-artalk-panel|mom-atk\" src/components/MomentComments.astro && grep -q \"at-color-bg\" src/components/geek/ArtalkThemeStyles.astro && grep -q \"ArtalkThemeStyles\" src/components/ArtalkComments.astro", "exit": 0, "duration_s": 0.005, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:45:56+00:00"}
|
||||||
|
{"task": "task_0004", "cmd": "grep -q \"lb-close\" src/components/pages/GalleryPage.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 29.988, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:26+00:00"}
|
||||||
|
{"task": "task_0005", "cmd": "! grep -rq \"一页 ≤3 处\\|≤3 处/页\" docs/ content/posts/writing-template.md && grep -q \"彩色\" docs/写作指南.md", "exit": 0, "duration_s": 0.004, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:26+00:00"}
|
||||||
|
{"task": "task_0006", "cmd": "grep -q \"align-items: center\" src/components/geek/ProjectWall.astro", "exit": 0, "duration_s": 0.002, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:26+00:00"}
|
||||||
|
{"task": "task_0007", "cmd": "E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE \"汇总: [0-9]+/[0-9]+ PASS\"", "exit": 0, "duration_s": 29.968, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:56+00:00"}
|
||||||
|
{"task": "task_0008", "cmd": "test -f scripts/build-perf/fetch-readme-assets.mjs && grep -q \"github-assets\" scripts/build-perf/fetch-readme-assets.mjs && python3 -c \"import pathlib;p=pathlib.Path('dist/opensource/index.html').read_text();bad=[u for u in ['img.shields.io','readme-typing-svg','github-readme-stats','streak-stats','komarev'] if u in p];assert not bad,bad\"", "exit": 0, "duration_s": 0.032, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:56+00:00"}
|
||||||
|
{"task": "task_0009", "cmd": "grep -c \"font-\" public/admin/typography-classes.js | awk '$1>=40'", "exit": 0, "duration_s": 0.003, "stdout_tail_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "tree_fp": "ec396f2bc636b87655d31daed6960522d1c311e699ca21959bdbe363543e385b", "at": "2026-11-03T04:46:56+00:00"}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# Phase 5i:字体加载根治、交互缺陷修复与书架/开源页再设计 - 项目范围
|
||||||
|
|
||||||
|
<!-- spec-format: 2 -->
|
||||||
|
|
||||||
|
## 1. 问题定义
|
||||||
|
- **项目目标**:①**字体切换全部失效的根因修复**(不是字体没做,是加载门禁错了)②按需扩展更多字族 ③Artalk「加载失败」误报与瞬间评论区配色脱同步 ④图库灯箱右上关闭被遮挡点不动,且右侧文字要能换字体/颜色 ⑤取消「彩色 ≤3 处/页」限制 ⑥开源页项目墙恢复居中 ⑦书架页重做 ⑧GitHub README 的动效图与更多展示形式回归(自托管,不再外链)
|
||||||
|
- **目标用户**:站长(写得更自由、字体真的能换)与读者(交互不再有假失败、书架更耐看)
|
||||||
|
- **核心价值**:把「看起来能用」变成「真的能用」——本轮多数是用户实测踩到的静默失效,根因都在加载门禁与层级覆盖
|
||||||
|
|
||||||
|
## 2. 假设与待确认
|
||||||
|
|
||||||
|
### 2.1 已确认事实(本轮实测取证,2026-11-02)
|
||||||
|
- **字体失效根因**:`src/layouts/BaseLayout.astro:76` 把 serif/kai/kuaile/hwmc 四份字体 CSS 全部关在 `track === 'reading'` 里;技术轨与全站页面(默认 `track='tech'`)从不加载它们 → `.font-kai` 计算值虽为 `"LXGW WenKai Screen"` 但该 @font-face 不在文档字体集内(`document.fonts` 实测仅 Noto Sans/JetBrains),浏览器回退系统宋体/衬线,表现为「字体没换」
|
||||||
|
- **汇文明朝链路**:`/fonts/subset/hwmc/fonts.css` 由 public 手工切片提供(339 片 unicode-range),仅在阅读轨被 preload;技术轨整条链路不加载
|
||||||
|
- **Artalk 误报根因**:`ArtalkComments.astro:126` `if (document.getElementById('artalk-lib')) return initArtalk();` —— 软导航后脚本标签已在但 `window.Artalk` 尚未就绪,走 `initArtalk()` → `!lib` → `showRetry(true)` 永久显示失败提示;而评论随后正常渲染(用户所见「总显示失败但实际正常」)
|
||||||
|
- **瞬间评论区配色脱同步**:Artalk 主题变量块选择器是 `#artalk-container` 与 `body .atk-layer-wrap`;瞬间的容器 id 为 `mom-atk-<slug>`,不在作用域内 → 回落到 Artalk 默认色
|
||||||
|
- **灯箱关闭失灵根因**:`#lb-close` 位于 (1220,16,44×44),`document.elementFromPoint` 命中的是 `.lb-meta.lb-l2`(右侧信息栏压在按钮上),点击被信息栏吃掉 → `lb.close()` 永不触发(生产实测 `open` 保持 true)
|
||||||
|
- 书架页现状:色脊卡 + 年份分组网格;信息密度低、悬停无反馈、无简介/评分等可读线索
|
||||||
|
- README 动效资源清单(7 类):readme-typing-svg、github-readme-stats、streak-stats、activity-graph、贡献蛇(daily Action 产出的 SVG)、shields 徽章、komarev 访客
|
||||||
|
|
||||||
|
### 2.2 关键假设
|
||||||
|
- 字体按「内容实际用到的字族」按需加载即可兼顾体积与正确性(构建期扫正文/页面文案里的 `font-*` 类)
|
||||||
|
- README 动效图均为 SVG(含 SMIL/CSS 动画),可在构建期抓取并自托管,运行时零第三方请求,动效保留
|
||||||
|
- 灯箱信息栏与关闭钮的层叠冲突用 z-index + 命中区域划分即可解,无需改结构
|
||||||
|
|
||||||
|
### 2.3 待确认问题
|
||||||
|
- [x] 字体扩展款式(用户选:宋系 / 楷系 / 手写系 / 现代黑系各补几款)
|
||||||
|
- [x] 书架重做方向(A 色脊墙精修 / B 封面网格 / C 书脊展开卡)
|
||||||
|
- [x] README 动效图确认「构建期抓取 + 自托管」路线
|
||||||
|
|
||||||
|
### 2.4 可选解释与取舍
|
||||||
|
- 字体:只按需加载,不做「全站全字族常开」(那会把单页体积拉到数 MB)
|
||||||
|
- README 动效:自托管后仍保留原服务生成逻辑(GitHub Action / 第三方接口),只是把产物入仓并在构建期更新
|
||||||
|
- 彩色限制取消后仍保留「灰阶外壳」红线(导航/页脚/按钮/背景不染色),只取消正文次数限制
|
||||||
|
|
||||||
|
### 2.5 已证伪路径
|
||||||
|
- 「字族没做」判断错误:@font-face 与切片文件都在,问题在加载门禁(本轮实测推翻)
|
||||||
|
- 外链 README 图直接保留:既有 502/超时与外链依赖问题(上一阶段已判弃),改自托管
|
||||||
|
|
||||||
|
## 3. 功能范围
|
||||||
|
|
||||||
|
### 3.1 核心功能(MVP)
|
||||||
|
- [x] T1 字族按需加载根治 + 字族扩展机制:BaseLayout 由「轨道门禁」改为「内容诉求驱动」,扫描正文与页面文案中的 `font-*` 类决定加载哪些字体 CSS;补字体扩展清单与接入流程
|
||||||
|
- [x] T2 Artalk 误报与配色同步:失败提示改为「真失败才提示」(脚本 onerror / 库未就绪超时且未挂载才提示),重置挂载状态机;主题变量覆盖全部 Artalk 实例容器(含瞬间逐条)
|
||||||
|
- [x] T3 灯箱:右上关闭恢复可点(层级与命中区域),右侧信息栏文字支持 markdown + 排版类(字体/颜色)
|
||||||
|
- [x] T4 取消彩色强调次数限制(文档 + 后台 hint + 示例文章同步)
|
||||||
|
- [x] T5 开源页项目墙恢复居中排版
|
||||||
|
- [x] T6 书架页重做(按用户选定方向)
|
||||||
|
- [x] T7 README 动效图自托管与展示创新(typing / stats / streak / activity-graph / snake 等构建期抓取入仓,配合原生数据卡与热力图组合呈现)
|
||||||
|
|
||||||
|
### 3.2 扩展功能
|
||||||
|
- 字体扩展的实际接入(款式待用户定)
|
||||||
|
|
||||||
|
### 3.3 不在范围内
|
||||||
|
- 换 CMS、评论系统替换、Artalk 服务端改造
|
||||||
|
|
||||||
|
## 4. 最小实现路径
|
||||||
|
- 最简可行:字体先修门禁(用现有 6 族验证通过),再谈扩展;灯箱只改层级与命中;README 动效先接 3 类(typing / stats / snake),验证体积与稳定性后再补
|
||||||
|
- 暂不引入:字体子集化的自动重跑编排、灯箱信息栏的富文本编辑器 UI
|
||||||
|
- 不做的抽象:通用「动效资源托管」服务
|
||||||
|
|
||||||
|
## 5. 技术决策
|
||||||
|
- 技术栈:Astro 7.4.4 + @fontsource(自托管字体 CSS)+ Artalk v2 + 构建期 SVG 抓取缓存(复用 README 缓存模式)
|
||||||
|
- 证据协议:evidence: runs
|
||||||
|
- 本轮允许改动:src/layouts/BaseLayout.astro、src/styles/{global,tokens}.css、src/components/{ArtalkComments,MomentComments}.astro、src/components/geek/{ViewMeta,ProjectWall,GithubProfile}.astro、src/components/pages/{GalleryPage,BooksPage}.astro、src/pages/{gallery,books}.astro、src/lib/{projects,site-content}.ts、content/site/*.yaml、content/photos/*.json(caption 富文本)、content/.github-assets/(新缓存目录)、public/admin/*、scripts/build-perf/*、infra/deploy/build.sh、docs/*、tests/e2e.mjs
|
||||||
|
- 本轮不应触碰:nginx/ESA、构建发布链主干顺序、双语路由结构、Artalk 服务端配置
|
||||||
|
- Git integration branch:`spec/2026-11-02_blog-5i-fonts-polish`
|
||||||
|
|
||||||
|
### 5.1 验证策略
|
||||||
|
- 范围级别:package
|
||||||
|
- 变更对象:字体加载策略、Artalk 挂载状态机与主题作用域、灯箱层级与富文本、书架与开源页版式、自托管动效资源
|
||||||
|
- 快速检查:`pnpm astro build`(node26)+ `python3 scripts/build-perf/config-check.py .`
|
||||||
|
- 集成检查:E2E(当前 46 项,本包新增字族加载/灯箱关闭/Artalk 误报断言)+ content-lint 0/0/0
|
||||||
|
- 升级触发:**已触发两次并记录理由**——①往 tokens.css 补 emoji 回退链(触及全局字体栈)②BaseLayout 字体加载策略改写(触及全站首屏资源)。两次都执行了全站视觉复核(glm-5.3-flash:max,≤6 图/轮,两轮共 9 张)与生产实测。以下情况同样升级:Artalk 挂载状态机、灯箱层级、构建闸门顺序。
|
||||||
|
- 全项目检查:生产实测五条(字体真加载 `document.fonts` 命中、灯箱点关闭真关、评论失败提示不再误报、瞬间评论区配色与页面一致、开源页动效图零外链);**升级条件**——仅当改动触及 BaseLayout 字体策略或 Artalk 挂载状态机时升级为全站视觉复核,本包因两者都动,已排一轮视觉终审
|
||||||
|
|
||||||
|
## 6. 成功标准与验证方式
|
||||||
|
- [x] 技术轨文章里的 `.font-kai/.font-song/.font-huiwen/.font-kuaile` 真加载对应字体(`document.fonts` 命中且渲染变化) -> verify: task_0001
|
||||||
|
- [x] 评论失败提示只在真失败时出现,正常挂载不提示 -> verify: task_0002
|
||||||
|
- [x] 瞬间评论区配色与页面主题一致(明暗双态) -> verify: task_0003
|
||||||
|
- [x] 灯箱右上关闭按钮点击必关(含缩放/信息栏展开态) -> verify: task_0004
|
||||||
|
- [x] 灯箱右侧文字支持字体与颜色类 -> verify: task_0005
|
||||||
|
- [x] 彩色强调不再有限次约束且文档同步 -> verify: task_0006
|
||||||
|
- [x] 开源页项目墙内容居中 -> verify: task_0007
|
||||||
|
- [x] 书架页信息密度与视觉达设计稿并过视觉终审 -> verify: task_0008
|
||||||
|
- [x] README 动效图自托管且生产零第三方请求 -> verify: task_0009
|
||||||
|
|
||||||
|
## 7. 风险与约束
|
||||||
|
- 灰阶外壳红线不变,仅取消正文彩色次数限制
|
||||||
|
- 自制切片/新增字体必须守单页增量 ≤150KB 阈值,超阈值只做子集化或降级为系统回退
|
||||||
|
- README 动效自托管:抓取失败必须回落(隐藏该块,绝不炸构建),且产物必须入仓保证构建确定性
|
||||||
|
- Artalk 状态机改动需覆盖三条触发路径(IO / 锚点 / 滚底),不得回归「评论区空着」
|
||||||
|
- 多车道并行:BaseLayout、ArtalkComments、GalleryPage、BooksPage 各归单一车道,admin config 与 docs 由 orchestrator 统一改
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Phase 5i:字体加载根治、交互缺陷修复与书架/开源页再设计 - 任务拆解
|
||||||
|
|
||||||
|
## 使用规则
|
||||||
|
- boundary/verify 齐备;verify 只读断言;车道工作树开发禁 git,收编由 orchestrator 统一提交
|
||||||
|
- 构建一律 `export PATH="$HOME/.local/node/bin:$PATH"`(Node 26)+ `pnpm astro build`
|
||||||
|
- E2E 口径:`pnpm astro build → cp -a dist /tmp/dist-e2e-5i → gz-server.py 18925 /tmp/dist-e2e-5i → E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs`
|
||||||
|
|
||||||
|
## 阶段一:实现
|
||||||
|
|
||||||
|
- [x] T1 字族按需加载根治
|
||||||
|
- claim: worker-one
|
||||||
|
- boundary: src/layouts/BaseLayout.astro(去掉 `track === 'reading'` 的字体门禁,改为「本页内容实际用到的字族」驱动:构建期扫正文/页面文案里的 `font-kai|font-song|font-fangsong|font-huiwen|font-kuaile|font-serif` 决定注入哪几份字体 CSS;零命中时只加载 sans/mono)、src/lib/ 新增字体诉求探测工具
|
||||||
|
- verify: `grep -q "fontsForPage" src/layouts/BaseLayout.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE "汇总: [0-9]+/[0-9]+ PASS"`
|
||||||
|
|
||||||
|
- [x] T2 Artalk 失败误报修复
|
||||||
|
- claim: op-artalk
|
||||||
|
- boundary: src/components/ArtalkComments.astro(状态机重写:脚本 onerror 才是失败;`artalk-lib` 已存在但库未就绪时等 load 事件而非立即判失败;失败提示只在「确实未挂载且已超时」出现;`mounting` 在所有失败/成功路径复位)
|
||||||
|
- verify: `grep -q "onerror" src/components/ArtalkComments.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE "汇总: [0-9]+/[0-9]+ PASS"`
|
||||||
|
|
||||||
|
- [x] T3 瞬间评论区配色同步
|
||||||
|
- claim: op-artalk
|
||||||
|
- boundary: src/components/MomentComments.astro(Artalk 主题变量作用域覆盖瞬间容器 `[data-artalk-panel]`/`mom-atk-*`,复用文章页那套 `--at-color-*` 映射:建议抽出共享样式片段避免两份漂移)
|
||||||
|
- verify: `grep -qE "data-artalk-panel|mom-atk" src/components/MomentComments.astro && grep -q "at-color-bg" src/components/geek/ArtalkThemeStyles.astro && grep -q "ArtalkThemeStyles" src/components/ArtalkComments.astro`
|
||||||
|
|
||||||
|
- [x] T4 灯箱关闭修复 + 右侧文字可排版
|
||||||
|
- claim: orchestrator
|
||||||
|
- boundary: src/components/pages/GalleryPage.astro(关闭钮层级/命中区域;右侧信息栏不再拦截点击)、content/photos/*.json(caption 允许 markdown + 排版类)、必要时 src/lib/exif.ts 注释同步
|
||||||
|
- verify: `grep -q "lb-close" src/components/pages/GalleryPage.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE "汇总: [0-9]+/[0-9]+ PASS"`
|
||||||
|
|
||||||
|
- [x] T5 取消彩色强调次数限制
|
||||||
|
- claim: orchestrator
|
||||||
|
- boundary: docs/写作指南.md、docs/管理台.md、public/admin/config.yml(hint 里去掉「≤3 处」表述)、content/posts/writing-template.md + posts-en 同名(示例文章说明同步)
|
||||||
|
- verify: `! grep -rq "一页 ≤3 处\|≤3 处/页" docs/ content/posts/writing-template.md && grep -q "彩色" docs/写作指南.md`
|
||||||
|
|
||||||
|
- [x] T6 开源页项目墙恢复居中
|
||||||
|
- claim: op-gitea
|
||||||
|
- boundary: src/components/geek/ProjectWall.astro(`align-items: center` + `text-align: center`,与用户审美偏好一致)
|
||||||
|
- verify: `grep -q "align-items: center" src/components/geek/ProjectWall.astro`
|
||||||
|
|
||||||
|
- [x] T7 书架页重做
|
||||||
|
- claim: orchestrator(方向待用户拍板)
|
||||||
|
- boundary: src/components/pages/BooksPage.astro、可选 content/site/books.yaml 新配置、src/i18n/ui.ts
|
||||||
|
- verify: `E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -qE "汇总: [0-9]+/[0-9]+ PASS"`
|
||||||
|
|
||||||
|
- [x] T8 README 动效图自托管与展示创新
|
||||||
|
- claim: op-gitea
|
||||||
|
- boundary: 新增 scripts/build-perf/fetch-readme-assets.mjs(构建期抓 typing/stats/streak/activity-graph/snake 等 SVG 到 content/.github-assets/,失败回落隐藏该块)、src/components/geek/GithubProfile.astro 或新增动效展示组件、build.sh 守卫挂载、docs 说明
|
||||||
|
- verify: `test -f scripts/build-perf/fetch-readme-assets.mjs && grep -q "github-assets" scripts/build-perf/fetch-readme-assets.mjs && python3 -c "import pathlib;p=pathlib.Path('dist/opensource/index.html').read_text();bad=[u for u in ['img.shields.io','readme-typing-svg','github-readme-stats','streak-stats','komarev'] if u in p];assert not bad,bad"`
|
||||||
|
|
||||||
|
- [x] T9 字族扩展(款式待用户拍板)
|
||||||
|
- claim: worker-one
|
||||||
|
- boundary: src/styles/tokens.css、src/styles/global.css、public/admin/typography-classes.js、public/fonts/(新增字体切片)、docs/写作指南.md 字体清单
|
||||||
|
- verify: `grep -c "font-" public/admin/typography-classes.js | awk '$1>=40'`
|
||||||
@@ -18,15 +18,15 @@ Use `##` for a section and `###` for a subsection. **Never use `#`** — the pos
|
|||||||
|
|
||||||
Leave a blank line between paragraphs. Inline you can use **bold**, *italic*, ~~strikethrough~~, `inline code`, and [ordinary links](https://astro.build).
|
Leave a blank line between paragraphs. Inline you can use **bold**, *italic*, ~~strikethrough~~, `inline code`, and [ordinary links](https://astro.build).
|
||||||
|
|
||||||
## 2. Colour emphasis: three per page at most
|
## 2. Colour emphasis: as much as you need
|
||||||
|
|
||||||
The rule comes from the design baseline: the shell is greyscale, so colour exists to weight one judgement in the body — three per page, maximum. More than that and it turns loud.
|
Colour is **no longer capped** (the old "three per page" limit was lifted on 2026-11-02). The one rule that remains is the shell: navigation, footer, buttons and background stay greyscale — the shell is temperament, the body is expression.
|
||||||
|
|
||||||
<span class="c-blue">First use: state one key conclusion in blue.</span> Then carry on normally.
|
<span class="c-blue">First use: state one key conclusion in blue.</span> Then carry on normally.
|
||||||
|
|
||||||
<span class="c-red">Second use: warn about a trap in red.</span> For example, “after changing a Markdown plugin you must clear `node_modules/.astro`, or the change silently does nothing”.
|
<span class="c-red">Second use: warn about a trap in red.</span> For example, “after changing a Markdown plugin you must clear `node_modules/.astro`, or the change silently does nothing”.
|
||||||
|
|
||||||
<span class="c-green">Third use: confirm a working path in green.</span> After three, this section stays uncoloured.
|
<span class="c-green">Confirm a working path in green.</span> If a whole paragraph deserves emphasis, mark the whole paragraph.
|
||||||
|
|
||||||
There are eight hues (blue / teal / green / yellow / orange / red / pink / purple), each with a standard and a `-soft` variant, plus four greyscale classes (`ink-muted` / `ink-warm` / `ink-cool` / `ink-faint`) for lowering tone — those do not count against the colour budget.
|
There are eight hues (blue / teal / green / yellow / orange / red / pink / purple), each with a standard and a `-soft` variant, plus four greyscale classes (`ink-muted` / `ink-warm` / `ink-cool` / `ink-faint`) for lowering tone — those do not count against the colour budget.
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ Refer to variables inline like `posts`.
|
|||||||
|
|
||||||
| Capability | Syntax | Note |
|
| Capability | Syntax | Note |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Colour emphasis | `<span class="c-blue">` | three per page at most |
|
| Colour emphasis | `<span class="c-blue">` | no limit (shell stays greyscale) |
|
||||||
| Typeface | `<span class="font-kai">` | a whole page adds font weight |
|
| Typeface | `<span class="font-kai">` | a whole page adds font weight |
|
||||||
| Image | `` | see the writing guide for size rules |
|
| Image | `` | see the writing guide for size rules |
|
||||||
| Video | frontmatter `video:` | lives in public/media, ≤50MB |
|
| Video | frontmatter `video:` | lives in public/media, ≤50MB |
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ description: 一篇文章演示全站可用的排版能力:标题层级、彩
|
|||||||
|
|
||||||
段落之间空一行即可。行内可以**加粗**、*斜体*、~~删除线~~、`行内代码`,也可以放[普通链接](https://astro.build)。
|
段落之间空一行即可。行内可以**加粗**、*斜体*、~~删除线~~、`行内代码`,也可以放[普通链接](https://astro.build)。
|
||||||
|
|
||||||
## 二、彩色强调:一页不超过三处
|
## 二、彩色强调:想用多少用多少
|
||||||
|
|
||||||
纪律来自设计基线:站点外壳是灰阶的,颜色只用来给正文某一个判断加重,一页最多三处。超过就变成花哨。
|
颜色现在**没有次数限制**(2026-11-02 起取消了原来的「一页最多三处」)。唯一还守着的是外壳:导航、页脚、按钮、背景保持灰阶——外壳是气质,正文是表达。
|
||||||
|
|
||||||
<span class="c-blue">第一处:一个关键结论用蓝色提出。</span> 后面照常叙述。
|
<span class="c-blue">第一处:一个关键结论用蓝色提出。</span> 后面照常叙述。
|
||||||
|
|
||||||
<span class="c-red">第二处:需要警示的坑用红色。</span> 比如「改完 Markdown 插件必须清 `node_modules/.astro`,否则改动静默不生效」。
|
<span class="c-red">第二处:需要警示的坑用红色。</span> 比如「改完 Markdown 插件必须清 `node_modules/.astro`,否则改动静默不生效」。
|
||||||
|
|
||||||
<span class="c-green">第三处:确认可行的路径用绿色。</span> 三处之后,本节不再上色。
|
<span class="c-green">确认可行的路径用绿色。</span> 想让整段都是重点也不必克制,把它们都标出来即可。
|
||||||
|
|
||||||
可用色相共 8 组(blue / teal / green / yellow / orange / red / pink / purple),每组有标准与 `-soft` 两档;另有 4 个灰阶层级类(`ink-muted` / `ink-warm` / `ink-cool` / `ink-faint`)用于降调,不算彩色额度。
|
可用色相共 8 组(blue / teal / green / yellow / orange / red / pink / purple),每组有标准与 `-soft` 两档;另有 4 个灰阶层级类(`ink-muted` / `ink-warm` / `ink-cool` / `ink-faint`)用于降调,不算彩色额度。
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export function sortPosts<T extends Post>(posts: T[]): T[] {
|
|||||||
|
|
||||||
| 能力 | 写法 | 注意 |
|
| 能力 | 写法 | 注意 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 彩色强调 | `<span class="c-blue">` | 一页 ≤3 处 |
|
| 彩色强调 | `<span class="c-blue">` | 不限次数(外壳仍灰阶) |
|
||||||
| 换字族 | `<span class="font-kai">` | 整页换会拉字体体积 |
|
| 换字族 | `<span class="font-kai">` | 整页换会拉字体体积 |
|
||||||
| 图片 | `` | 体积纪律见写作指南 |
|
| 图片 | `` | 体积纪律见写作指南 |
|
||||||
| 视频 | frontmatter `video:` | 放 public/media,≤50MB |
|
| 视频 | frontmatter `video:` | 放 public/media,≤50MB |
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
# 打字机动效文案(档案卡顶部逐字轮播;每行双语,最多 6 行;留空用内置默认三行)
|
||||||
|
typing:
|
||||||
|
- zh: 气象出身,写代码为乐
|
||||||
|
en: Trained in meteorology, coding for fun
|
||||||
|
- zh: 自托管一切能自托管的东西
|
||||||
|
en: Self-hosting whatever can be self-hosted
|
||||||
|
- zh: 拥抱开源,热爱开源
|
||||||
|
en: Embrace open source, love open source
|
||||||
|
- zh: 书与快门都在一个工作台
|
||||||
|
en: Books and shutters, one workbench
|
||||||
|
|
||||||
blurb:
|
blurb:
|
||||||
zh: 本站本身即开源:
|
zh: 本站本身即开源:
|
||||||
en: 'This site is itself open source:'
|
en: 'This site is itself open source:'
|
||||||
|
|||||||
+34
-3
@@ -11,10 +11,10 @@ cp content/posts/writing-template.md content/posts/my-new-post.md
|
|||||||
# 改 frontmatter 的 title / pubDate / tags / description,删掉不需要的段落
|
# 改 frontmatter 的 title / pubDate / tags / description,删掉不需要的段落
|
||||||
```
|
```
|
||||||
|
|
||||||
模板本身是一篇真文章(线上读:`/archives/writing-template/`),每节都在跑一种能力,你看到的效果就是源码的效果:标题层级、三处彩色强调、两族字体、引用、列表、代码窗条、表格、图片放大、链接卡片、`<details>` 折叠、分隔线。
|
模板本身是一篇真文章(线上读:`/archives/writing-template/`),每节都在跑一种能力,你看到的效果就是源码的效果:标题层级、彩色强调、字族切换、引用、列表、代码窗条、表格、图片放大、链接卡片、`<details>` 折叠、分隔线。
|
||||||
|
|
||||||
写之前只需记住三条纪律:
|
写之前只需记住三条纪律:
|
||||||
- **彩色 ≤3 处/页**:外壳是灰阶,颜色只用来给某个判断加重;超过就花哨
|
- **彩色不限次数**(2026-11-02 用户拍板取消原来的"一页最多三处"):正文想用多少处颜色都可以;仍守的是另一条——**外壳灰阶**(导航/页脚/按钮/背景不染色),因为外壳是气质,正文是表达
|
||||||
- **整页换字族要谨慎**:会给访问者拉一份中文字体(汇文明朝整页约 420KB,已子集化)
|
- **整页换字族要谨慎**:会给访问者拉一份中文字体(汇文明朝整页约 420KB,已子集化)
|
||||||
- **折叠放细节不放结论**:`<details>` 里的内容可能永远没人展开
|
- **折叠放细节不放结论**:`<details>` 里的内容可能永远没人展开
|
||||||
|
|
||||||
@@ -96,6 +96,12 @@ public/media/my-post/clip.mp4 ← 文件放这里
|
|||||||
|
|
||||||
见 `content/posts/media-sample.md`(draft 文章,仅构建验证用,不上线)。
|
见 `content/posts/media-sample.md`(draft 文章,仅构建验证用,不上线)。
|
||||||
|
|
||||||
|
## 灯箱说明文字(图库 caption)
|
||||||
|
|
||||||
|
图库照片的 `caption` 字段走同一套富文本管线:markdown(`**加粗**`、换行)+ 排版类(`<span class="c-blue font-kai">`)。灯箱里深底上的彩色会自动取暗底档。
|
||||||
|
|
||||||
|
图库灯箱关闭:右上 `×`、`Esc`、点背景、点图(1× 时)都能关;缩放后移动鼠标召唤控件。
|
||||||
|
|
||||||
## 链接卡片(OG 预览卡)
|
## 链接卡片(OG 预览卡)
|
||||||
|
|
||||||
**一行只放一个链接、且它独立成段**时,构建期会抓取该页的 OG 信息渲染成卡片(标题 / 描述 / 站点图标 / 可选缩略图):
|
**一行只放一个链接、且它独立成段**时,构建期会抓取该页的 OG 信息渲染成卡片(标题 / 描述 / 站点图标 / 可选缩略图):
|
||||||
@@ -195,6 +201,31 @@ python3 scripts/build-perf/subset-fonts.py \
|
|||||||
|
|
||||||
子集化产物输出到 `--out` 指定目录(如 `public/fonts/subset/`);把它接进站点(构建链挂守卫 + 字体 CSS 指向子集)是独立一步,接线后随构建自动生成,未接线前需手动跑。**换字/加字后重跑一次**,否则新字会回落到下一个切片或系统字体。
|
子集化产物输出到 `--out` 指定目录(如 `public/fonts/subset/`);把它接进站点(构建链挂守卫 + 字体 CSS 指向子集)是独立一步,接线后随构建自动生成,未接线前需手动跑。**换字/加字后重跑一次**,否则新字会回落到下一个切片或系统字体。
|
||||||
|
|
||||||
|
### 5i 字族扩展六款(2026-11-03,全站共 12 族)
|
||||||
|
|
||||||
|
| 类名 | 字体 | 适用场景 | 许可证 / 来源 | 切片 | 单页增量(实测) |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| `font-xiaowei` | 站酷小薇 ZCOOL XiaoWei | 文学味标题、书摘 | OFL-1.1 / google/fonts `ofl/zcoolxiaowei` | 100 片 | 44.9KB |
|
||||||
|
| `font-huangyou` | 站酷庆科黄油体 | 圆润标题、栏目名 | OFL-1.1 / `ofl/zcoolqingkehuangyou` | 100 片 | 27.1KB |
|
||||||
|
| `font-mashanzheng` | 马善政毛笔楷书 | 书法短句、题记 | OFL-1.1 / `ofl/mashanzheng` | 100 片 | 45.7KB |
|
||||||
|
| `font-liujianmaocao` | 柳建毛草 | 草书点缀(只宜 1-2 字) | OFL-1.1 / `ofl/liujianmaocao` | 100 片 | 30.0KB |
|
||||||
|
| `font-smiley` | 得意黑 Smiley Sans(Oblique) | 现代倾斜标题、强调句 | OFL-1.1 / `atelier-anchor/smiley-sans` v2.0.1 | 100 片 | 27.1KB |
|
||||||
|
| `font-neoxihei` | 霞鹜新晰黑 LXGW Neo XiHei | 比思源黑更清晰的正文黑体 | OFL / `lxgw/LxgwNeoXiHei` | 96 片 | 30.0KB |
|
||||||
|
|
||||||
|
- 六款均按**站内用字**细切(约 19 字/片,单片 2–12KB),且只在内容里写到对应类时才加载(探测在 `src/lib/font-needs.ts`)——首页、归档列表这类无字体类的页面**零增量**。
|
||||||
|
- **覆盖边界**:切片只含站内出现过的字(当前约 1900 字)。新写了字典外的新字(尤其生僻字)要先重跑切片,否则该字回落系统字族。
|
||||||
|
- **重切命令**(字体源文件不入仓,按需从上面的来源下载):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/build-perf/subset-fonts.py \
|
||||||
|
--split-ttf /path/to/YourFont.ttf --family "Font Family Name" \
|
||||||
|
--slices 100 --order-from public/fonts/subset/hwmc/fonts.css \
|
||||||
|
--out public/fonts/<shortname> \
|
||||||
|
--chars-from 'content/posts/*.md' 'content/site/*.yaml' 'content/moments/*.md'
|
||||||
|
```
|
||||||
|
|
||||||
|
- **体积闸门**:单页增量 >150KB 必须子集化或降级。本次六款实测 27–46KB(单句场景)全部达标;@fontsource 官方中文包切片粒度约 33 字/片、单片 40KB+,一句话就 300–440KB/页,**已弃用**(改从原始 TTF 细切)。
|
||||||
|
|
||||||
### 候补字体清单(未落地,加一款约"一条命令 + 一次体积账")
|
### 候补字体清单(未落地,加一款约"一条命令 + 一次体积账")
|
||||||
|
|
||||||
| 字体 | 许可证 | 允许 webfont 嵌入 | 未落地原因 |
|
| 字体 | 许可证 | 允许 webfont 嵌入 | 未落地原因 |
|
||||||
@@ -265,7 +296,7 @@ text: 今天把**置顶**做完了,顺手试了 <span class="c-teal">彩色</s
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
- `text` 支持 markdown(`**加粗**`、列表、`> 引用`)与**同一套排版类**(字体/颜色),因为走的是与全站文案相同的净化管线:危险标签整棵丢弃,只放行 35 项白名单类
|
- `text` 支持 markdown(`**加粗**`、列表、`> 引用`)与**同一套排版类**(字体/颜色),因为走的是与全站文案相同的净化管线:危险标签整棵丢弃,只放行 42 项白名单类
|
||||||
- 一条瞬间 = 一行时间线卡片,**每条都带独立评论区**(展开才挂载,双语页共用同一评论流,评论不分裂)
|
- 一条瞬间 = 一行时间线卡片,**每条都带独立评论区**(展开才挂载,双语页共用同一评论流,评论不分裂)
|
||||||
- 每条的「浏览 / 评论」数字是只读统计(不会因为别人点开评论而虚增浏览)
|
- 每条的「浏览 / 评论」数字是只读统计(不会因为别人点开评论而虚增浏览)
|
||||||
- `text` 与 `image` 至少填一项;图片建议先压缩
|
- `text` 与 `image` 至少填一项;图片建议先压缩
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
- markdown:`**加粗**`、`*斜体*`、列表、`> 引用`、`` `行内代码` ``
|
- markdown:`**加粗**`、`*斜体*`、列表、`> 引用`、`` `行内代码` ``
|
||||||
- 排版类 HTML:`<span class="c-blue font-kai">彩色 + 楷体</span>`(可用类清单见写作指南「文章排版类」一节,与文章完全同一份白名单)
|
- 排版类 HTML:`<span class="c-blue font-kai">彩色 + 楷体</span>`(可用类清单见写作指南「文章排版类」一节,与文章完全同一份白名单)
|
||||||
- 彩色**不再限次**(原「≤3 处/页」已取消);仍守外壳灰阶:导航/页脚/按钮/背景不染色
|
- 彩色**不再限次**(原来的"一页最多三处"已取消);仍守外壳灰阶:导航/页脚/按钮/背景不染色
|
||||||
|
|
||||||
**每条瞬间自带评论区**:时间线卡片下方有「评论」折叠条,读者点开才加载评论(不点开不为它付任何加载成本)。中文页与英文页共用同一条评论流,语言切换不会丢评论。
|
**每条瞬间自带评论区**:时间线卡片下方有「评论」折叠条,读者点开才加载评论(不点开不为它付任何加载成本)。中文页与英文页共用同一条评论流,语言切换不会丢评论。
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ pnpm astro build
|
|||||||
[ -f scripts/build-perf/gen-sw-precache.mjs ] && node scripts/build-perf/gen-sw-precache.mjs dist || echo "[build] sw-precache 生成器未就绪,跳过"
|
[ -f scripts/build-perf/gen-sw-precache.mjs ] && node scripts/build-perf/gen-sw-precache.mjs dist || echo "[build] sw-precache 生成器未就绪,跳过"
|
||||||
[ -f scripts/build-perf/inline-home-css.mjs ] && node scripts/build-perf/inline-home-css.mjs || echo "[build] inline-home 脚本未就绪,跳过"
|
[ -f scripts/build-perf/inline-home-css.mjs ] && node scripts/build-perf/inline-home-css.mjs || echo "[build] inline-home 脚本未就绪,跳过"
|
||||||
|
|
||||||
|
# README 动效资产(5i T8):**不在此跑抓取**(避免发布链被外网抖动拖累),只做存在性守卫 + 缺资产告警
|
||||||
|
if [ -f public/github-assets/manifest.json ]; then
|
||||||
|
echo "[build] github-assets 就绪:$(find public/github-assets -name '*.svg' | wc -l) 个自托管 SVG"
|
||||||
|
else
|
||||||
|
echo "[build] WARN public/github-assets/manifest.json 缺失——开源页数据板将只显示原生统计(可手动跑 node scripts/build-perf/fetch-readme-assets.mjs 补齐)"
|
||||||
|
fi
|
||||||
|
|
||||||
# 内容 lint(T3):断链/缺图在部署前拦截;CONTENT_LINT=skip|warn 逃生门见脚本头注
|
# 内容 lint(T3):断链/缺图在部署前拦截;CONTENT_LINT=skip|warn 逃生门见脚本头注
|
||||||
[ -f scripts/build-perf/content-lint.mjs ] && node scripts/build-perf/content-lint.mjs dist || echo "[build] content-lint 未就绪,跳过"
|
[ -f scripts/build-perf/content-lint.mjs ] && node scripts/build-perf/content-lint.mjs dist || echo "[build] content-lint 未就绪,跳过"
|
||||||
|
|
||||||
|
|||||||
+14
-5
@@ -169,8 +169,8 @@ collections:
|
|||||||
name: font
|
name: font
|
||||||
widget: select
|
widget: select
|
||||||
required: false
|
required: false
|
||||||
hint: 整页正文换字族;艺术/展示类字族(汇文、快乐体)体积大,单页成本会上升
|
hint: 整页正文换字族;艺术/展示类字族体积大。5i 新增六款(小薇/庆科黄油/马善政/柳建毛草/得意黑/新晰黑)均按站内用字切片,单页增量 27–46KB;站外用字(生僻字)会回落系统字族,需按 docs 里的命令重切
|
||||||
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
|
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile, font-xiaowei, font-huangyou, font-mashanzheng, font-liujianmaocao, font-smiley, font-neoxihei]
|
||||||
- label: 强调色类
|
- label: 强调色类
|
||||||
name: accent
|
name: accent
|
||||||
widget: select
|
widget: select
|
||||||
@@ -523,7 +523,7 @@ collections:
|
|||||||
name: font
|
name: font
|
||||||
widget: select
|
widget: select
|
||||||
required: false
|
required: false
|
||||||
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
|
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile, font-xiaowei, font-huangyou, font-mashanzheng, font-liujianmaocao, font-smiley, font-neoxihei]
|
||||||
- label: 强调色类
|
- label: 强调色类
|
||||||
name: accent
|
name: accent
|
||||||
widget: select
|
widget: select
|
||||||
@@ -535,6 +535,15 @@ collections:
|
|||||||
file: content/site/opensource.yaml
|
file: content/site/opensource.yaml
|
||||||
format: yaml
|
format: yaml
|
||||||
fields:
|
fields:
|
||||||
|
- label: 打字机动效文案(可选,≤6 条)
|
||||||
|
name: typing
|
||||||
|
widget: list
|
||||||
|
required: false
|
||||||
|
summary: '{{fields.zh}}'
|
||||||
|
hint: '档案卡顶部逐字打出的几行文案,2–6 条最佳;留空用内置默认。中英各一行,切换语言同步'
|
||||||
|
fields:
|
||||||
|
- { label: 中文, name: zh, widget: string }
|
||||||
|
- { label: English, name: en, widget: string }
|
||||||
- label: 叙述(链接前)
|
- label: 叙述(链接前)
|
||||||
name: blurb
|
name: blurb
|
||||||
widget: object
|
widget: object
|
||||||
@@ -553,8 +562,8 @@ collections:
|
|||||||
name: font
|
name: font
|
||||||
widget: select
|
widget: select
|
||||||
required: false
|
required: false
|
||||||
hint: 整页正文换字族;艺术/展示类字族(汇文、快乐体)体积大,单页成本会上升
|
hint: 整页正文换字族;艺术/展示类字族体积大。5i 新增六款(小薇/庆科黄油/马善政/柳建毛草/得意黑/新晰黑)均按站内用字切片,单页增量 27–46KB;站外用字(生僻字)会回落系统字族,需按 docs 里的命令重切
|
||||||
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
|
options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile, font-xiaowei, font-huangyou, font-mashanzheng, font-liujianmaocao, font-smiley, font-neoxihei]
|
||||||
- label: 强调色类
|
- label: 强调色类
|
||||||
name: accent
|
name: accent
|
||||||
widget: select
|
widget: select
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ window.TYPOGRAPHY_CLASSES = {
|
|||||||
{ cls: 'font-huiwen', label: '汇文明朝体', family: '"WF-Hwmc", serif', kind: '自托管' },
|
{ cls: 'font-huiwen', label: '汇文明朝体', family: '"WF-Hwmc", serif', kind: '自托管' },
|
||||||
{ cls: 'font-kuaile', label: '站酷快乐体', family: '"ZCOOL KuaiLe", serif', kind: '自托管' },
|
{ cls: 'font-kuaile', label: '站酷快乐体', family: '"ZCOOL KuaiLe", serif', kind: '自托管' },
|
||||||
{ cls: 'font-art-kuaile', label: '快乐体(艺术·仅标题)', family: '"ZCOOL KuaiLe", serif', kind: '艺术字' },
|
{ cls: 'font-art-kuaile', label: '快乐体(艺术·仅标题)', family: '"ZCOOL KuaiLe", serif', kind: '艺术字' },
|
||||||
|
// 5i T9 五款字族扩展(2026-11-03,均 OFL / 免费商用且允许 web 嵌入)
|
||||||
|
{ cls: 'font-xiaowei', label: '站酷小薇(文学·宋)', family: '"ZCOOL XiaoWei", serif', kind: '自托管' },
|
||||||
|
{ cls: 'font-huangyou', label: '站酷庆科黄油(标题)', family: '"ZCOOL QingKe HuangYou", sans-serif', kind: '自托管' },
|
||||||
|
{ cls: 'font-mashanzheng', label: '马善政(书法)', family: '"Ma Shan Zheng", "Kaiti SC", serif', kind: '自托管' },
|
||||||
|
{ cls: 'font-liujianmaocao', label: '柳建毛草(草书)', family: '"Liu Jian Mao Cao", "Kaiti SC", cursive', kind: '自托管' },
|
||||||
|
{ cls: 'font-smiley', label: '得意黑(斜体标题)', family: '"Smiley Sans", sans-serif', kind: '自托管' },
|
||||||
|
{ cls: 'font-neoxihei', label: '霞鹜新晰黑(正文黑)', family: '"LXGW Neo XiHei", "Noto Sans SC", sans-serif', kind: '自托管' },
|
||||||
],
|
],
|
||||||
color: [
|
color: [
|
||||||
{ cls: 'ink-1', label: '最重(标题级)', swatch: '#111113' },
|
{ cls: 'ink-1', label: '最重(标题级)', swatch: '#111113' },
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 634 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user