feat(reader): PDF 改 pdf.js 渲染+斜体 bug 根治+评论假挂载修复+排版类

【T1 PDF 内置阅读重做】iframe 对 arXiv PDF 实测 ERR_ABORTED(浏览器 PDF
插件策略差异)→ pdfjs-dist 6.4.299 客户端 canvas 渲染:只在 /papers/
动态 import(worker ?url 打包,不进全站 bundle);文档一次取回 + IO
懒渲染(rootMargin 400px)+ 页占位 aspect-ratio 防跳动 + 12s 首屏兜底 +
微信 UA 直接兜底;工具条页码/缩放/翻页/下载/arXiv/授权声明保留。红线:
PDF 由访客浏览器直取 arXiv(CORS * 实测),仓内零副本。真页实测:
13 页 canvas 全绘制、首屏墨迹像素非空、零 console 错误。

【T2 斜体排版 bug 真凶】global.css 的 `.prose-* p > em:only-child
{ display:block; text-align:center }` 图注样式按"斜体独占段"自动命中,
把所有正文独占段斜体变成块级居中。改:图注用显式 .fig-cap 驱动 + 补
em/i { display:inline; font-style:italic } 基线;media-sample 迁移新写法,
指南注明旧写法失效原因。实测独占段与行内斜体均 display:inline/italic。

【T3 评论"假挂载"真 bug】原 initArtalk 一进来就置 mounted=true——脚本
404/被拦截时把空容器误标已挂载,5s 兜底被绕过,正是"评论区一直空着"的
来源之一。改为库就绪才算成功;另加三触发路径(IO 主 + 锚点点击 + 滚到
页底 2s 兜底)、5s 失败提示+重试钮、软导航重挂、成功打
data-artalk-mounted=1 供 E2E。

【T4 文章排版类 + 安全白名单】11 个受限类(ink-1/2/3/muted/accent、
font-serif/kai/sans/mono、drop-cap、quote-line、fig-cap)全走 tokens 禁
任意 hex;新增 rehype-class-whitelist.ts:className 白名单 + 剥离 style
与 on*;实测注入用例只剩 class="ink-2",style/onclick 全无。新坑入档:
markdown raw HTML 在 hast 是 type:'raw' 节点、白名单插件看不见 span,必须
先 rehype-raw 再过滤 → 插件链 [rehypeRaw, rehypeClassWhitelist,
rehypeLinkCards]。新依赖:pdfjs-dist、rehype-raw。

车道:op-artalk(T1 6/6、T2 2/2、T3 3/3、T4 6/6);收编复验:build 46 页、
E2E 37/37、四专项 playwright 实测(PDF 13 canvas/斜体 inline/白名单净化/
评论 mounted 标记)

验证: node v26.13.0 + astro 7.4.4 构建 46 页 exit 0;E2E 37/37 PASS

Spec: none (阅读体验四件,车道级交付)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-02 15:59:28 +08:00
1 parent 328ab68f18
commit 280654f9e3
11 files changed
+621 -55

No files matched your search

+30 -2
View File
@@ -22,10 +22,11 @@ content/posts/
```markdown
![外滩夜景](./assets/my-post/bund.jpg)
*图:外滩的傍晚* ← 紧跟媒体的斜体独立段 = 图注(居中小字)
<p class="fig-cap">图:外滩的傍晚</p> ← 显式图注类(居中小字)
```
- 图注可选;写法固定为 `*…*` 单独成段,紧跟图片
- 图注可选;**必须用 `<p class="fig-cap">…</p>`**(2026-11-02 起)
- ⚠️ 旧写法 `*斜体独立段*` 已不再自动当图注:此前它会把正文里所有独占成段的斜体都变成块级居中(用户实测的排版 bug),现在斜体恢复为正常行内强调
- 压缩纪律:入仓前长边 ≤2400px(可跑 `python3 scripts/photos_ingest.py`,对 posts 资产同样有效的思路,图片请自行用同规格压缩)
## 视频 / 音频
@@ -83,6 +84,33 @@ https://astro.build/
- **缓存**:结果存 `content/.link-cache.json`(入仓,保证构建确定性);条目 30 天后自动重抓。想强制刷新某条——删掉该 URL 的条目即可
- 缩略图取 `og:image`,无图不占位;图标取站点而非第三方 favicon 服务
## 文章排版类(受限白名单)
正文里可用 `<span class="…">` / `<p class="…">` 做**受限**排版。构建期有白名单过滤:**只放行下表类名,其它 class 与 `style`、`on*` 属性一律被剥离**(防注入 + 保护灰阶骨架)。
| 类名 | 作用 |
|---|---|
| `ink-1` / `ink-2` / `ink-3` | 指定灰阶层(正文/次要/更淡) |
| `ink-muted` | 最淡灰(注释感) |
| `ink-accent` | 强调色(链接色,仅少量点缀) |
| `font-serif` | 思源宋(书评正文族) |
| `font-kai` | 霞鹜文楷(金句族) |
| `font-sans` | 思源黑(UI/技术族) |
| `font-mono` | 等宽族(标签/数值) |
| `drop-cap` | 段落首字下沉(书评开篇) |
| `quote-line` | 金句块(左侧竖线 + 文楷) |
| `fig-cap` | 图注(居中小字) |
```markdown
<span class="ink-muted">次要说明</span>
<span class="font-kai">金句可以换文楷</span>
<p class="drop-cap">开篇段落,首字会下沉。</p>
<p class="quote-line">所谓暮色,就是光慢慢地承认自己要走。</p>
```
- **颜色只能走上面这些类**(内部用 tokens,亮暗双态都可读);写 `style="color:red"` 会被构建期剔除
- 斜体就用普通 markdown `*斜体*`——行内强调,不会换行也不会居中
## 发布提醒
- push main → webhook 自动构建发布(约 10 秒)