diff --git a/content/posts/fonts-test.md b/content/posts/fonts-test.md new file mode 100644 index 0000000..c3bc4cd --- /dev/null +++ b/content/posts/fonts-test.md @@ -0,0 +1,31 @@ +--- +title: "字体族样例" +pubDate: 2026-11-02 +category: reading +tags: [test, hidden] +draft: false +--- + +字体测试样张(hidden):验证系统回退字族的渲染。 + +
宋体族(系统回退):秋天的海面像一块被风抚平的铁皮。
+ +楷体族(系统回退):秋天的海面像一块被风抚平的铁皮。
+ +黑体族(系统回退):秋天的海面像一块被风抚平的铁皮。
+ +仿宋族(系统回退):秋天的海面像一块被风抚平的铁皮。
+ +暖调正文:秋天的海面像一块被风抚平的铁皮。
+ +冷调正文:秋天的海面像一块被风抚平的铁皮。
+ +最淡可读档:秋天的海面像一块被风抚平的铁皮。
+ +弱强调:秋天的海面像一块被风抚平的铁皮。
+ +霞鹜文楷 Light(自托管 300):秋天的海面像一块被风抚平的铁皮。
+ +蓝色标准:秋天的海面像一块被风抚平的铁皮。
+黄色标准(已压暗):秋天的海面像一块被风抚平的铁皮。
+红色 soft:秋天的海面像一块被风抚平的铁皮。
diff --git a/docs/research/10-页面后台化方案.md b/docs/research/10-页面后台化方案.md new file mode 100644 index 0000000..e70d770 --- /dev/null +++ b/docs/research/10-页面后台化方案.md @@ -0,0 +1,394 @@ +# 页面后台化方案:内容 / 布局 / 样式的可编辑边界 + +> 调研 + 提案,不改代码。基线 = 工作树 2026-11-02(含在途未提交改动)。 +> 口径:所有结论落到本仓文件/字段;"能编辑什么"和"不能编辑什么"同等重要。 +> **在途关系**:工作树里另有一条未提交车道(`git diff --stat`:home.yaml / opensource.yaml / projects.ts / site-content.ts / content.config.ts / ProjectWall.astro / index.astro / en-index / tokens.css / global.css,共 306 增)已落地「首页区块开关 + 开源页可见性 + README 开篇」。本文把它当**既有事实**评估,只补缺口与验收,不重复设计。 + +--- + +## 0. 现状盘点(文件级锚点) + +| 关注点 | 现有实现 | 位置 | +|---|---|---| +| 集合/单例 schema | `siteHome` / `siteAbout` / `siteOpenSource` 三个 `glob(pattern 精确到单文件)` 单例 | `src/content.config.ts:78,114,119` | +| 后台字段 | `site_pages` 一集合三 files,字段与 schema 一一对应 | `public/admin/config.yml:110-260` | +| 文案访问层(含字段级回落) | `pick()/pickBi()` + `SITE_DEFAULTS` 逐字对齐历史文案 | `src/lib/site-content.ts:18-62` | +| markdown 渲染 | `createMarkdownProcessor()` **无参**(关键,见 §7) | `src/lib/site-content.ts:122-127` | +| 关于页结构 | h1 → intro(markdown) → `IdCard` → tracks(3 条硬编码) → build 段 | `src/components/pages/AboutPage.astro:1-70` | +| 关于页可变文案 | tracks/build 段全部来自 `t()` 字典(**非后台可改**) | `src/i18n/ui.ts:73-84` | +| 首页 | 结构化区块:IdCard/PostList/最新影像/Heatmap/ProjectWall/心跳 | `src/pages/index.astro`(zh/en 两份重复) | +| 开源页 | blurb + Heatmap + ProjectWall(limit 99) | `src/pages/opensource.astro` | +| 项目数据 | 构建期双源 fetch + 去重 + 过滤/排序 + 仓内 fallback JSON(现仅 1 条 `blog`) | `src/lib/projects.ts:24-134`、`src/data/projects-fallback.json` | +| README 开篇 | `GET /repos/wait4xx/wait4xx/readme`(Accept raw)+ `content/.github-readme.md` 缓存 | `src/lib/site-content.ts:204-256` | +| markdown 净化 | 仅文章管线挂了白名单(class/style/on*) | `astro.config.mjs:28`、`src/lib/rehype-class-whitelist.ts` | +| 设计 tokens | 全部 CSS 变量,明暗双套 | `src/styles/tokens.css`(124 行,含 dark 覆盖) | + +**结论**:后台能力当前是「**平铺标量字段**」形态——能改文案与几个开关,不能改**结构、顺序、字段种类**。关于页的骨架(tracks/build 两段)完全在代码与 i18n 字典里,这正是用户"整页可编辑"诉求的断点。 + +--- + +## 1. 需求拆解(可验收能力清单) + +| 编号 | 能力 | 现状 | 缺口 | +|---|---|---|---| +| C1 | 关于页**所有文案**可改(含 tracks/build 段) | intro 可改,其余在 `ui.ts` | 全部结构化区块未入 CMS | +| C2 | 关于页**结构可改**(增删段、调顺序、开关名片区) | 硬编码 | 无块模型 | +| C3 | 首页区块开关 / 条数 / 副标题 | 在途已实现(`sections.*`、`perTrackLimit`、`latestPhotos`、`subtitle`) | 缺"展示策略"类字段(见 §6) | +| C4 | 开源页"展示哪些项目" | 在途已实现(`mode/include/exclude/sort/perSource`) | 语义定稿 + 断言 + 现有 6 条截断副作用(见 §4) | +| C5 | 开源页开篇 = GitHub profile README | 在途已实现(`intro_from: github-readme`) | 缓存位置被 `git clean` 抹掉(见 §4.4) | +| C6 | **样式**可调(字体/字号/间距/灰阶/圆角) | 全在 `tokens.css` | 无数据层 | +| C7 | 双语 en 轨保真 | 字段级 `{zh,en}` + 回落 | 块模型需延续同规矩 | +| C8 | 构建期零运行时 + SEO/灰阶不回归 | 现状成立 | 需把"不回归"写成断言 | + +--- + +## 2. 五方案对比 + +| | A 结构化单例字段扩展 | B 块构建器 | C 富文本整页 | D 样式即数据 | E 混合(推荐) | +|---|---|---|---|---|---| +| 能力上限 | 低:只能改预定义字段的值 | 高:增删/排序/差异化结构 | 最高:任意内容 | 中:只动感官参数 | 高(结构)+ 中(局部自由) | +| 破版风险 | 极低 | 低(渲染器受控) | **高**:作者可写出非设计语言结构 | 中(对比度/尺度) | 低-中 | +| XSS 面 | 0(无 HTML) | 小(组件渲染,URL/图片字段受控) | **大**:`set:html` 直通 | 0 | 小(唯一自由区走净化管线) | +| 编辑体验 | 顺手但僵硬;20 字段后 config.yml 成清单墙 | 顺手(新增时选块型、拖拽排序) | 最自由但无护栏 | 顺手(几个 color/number) | 顺手(块为主,自由区为辅) | +| 工作量 | 0.5d/页 | 3-4d(渲染器 + 9 类块 + 后台 types) | 0.5d(已有 intro 通道)但治不住质量 | 1d | 4-5d(含 B+D+净化) | +| 维护成本 | 每加一项改两处(yml+schema) | 每加块型改三处(yml+schema+组件),但**互不干扰** | 内容问题无代码兜底,靠人审 | 用户改坏颜色需回滚 git | 同 B,另加 token 白名单 | +| 对我们仓的结论 | **只适合开关/条数**(首页现状即其上限形态),**不作为关于页主路线** | 关于页主力 | **不作为主路线**(灰阶/双语/SEO 三条红线都靠人守) | 采纳为**独立一层**(受限白名单) | **采纳** | + +补充结论(逐条): +- **A 的极限量化**:`public/admin/config.yml` 现已 260 行、覆盖 4 集合。关于页若走 A(名片/技能卡/时间线各 4-6 字段),预估 +60 行 yml、+40 行 schema、+30 行组件分支;且"某段删掉"只能靠 `enabled: false` 假装,顺序固定。→ 只保留给首页(首页是聚合页,区块种类稳定)。 +- **B 的关键前提**:Sveltia 0.252 支持 **`list` 的 `types` + `typeKey`**(异构块),证据见 §3.4;无此能力则 B 退化成"同构对象列表"(每块字段全冗)。 +- **C 的现实定位**:`about.yaml` 已有 markdown 整块通道(`intro`),可立刻扩成"多段 markdown 长文"。问题:长文无法表达 tracks 卡片(图标+双行)、无法控制段间节奏,且 raw HTML 通道当前**未净化**(§7.1)——直接放开等于开洞。 +- **D 的边界**:可调项必须白名单化(约 12 个),不是整份 tokens.css;`--measure`(9 处引用)、`--accent`(38 处)属高放大倍率旋钮,见 §3.6。 + +--- + +## 3. 推荐方案 E:结构与落点 + +### 3.1 四层数据分层 + +| 层 | 载体 | 谁能改 | 例子 | +|---|---|---|---| +| L1 页面骨架 | `content/site/*.yaml` 的 `blocks: []` | 后台(增删排序) | 关于页整页 | +| L2 区块字段 | 每块 `type` 决定字段集(zod discriminatedUnion) | 后台 | prose / tracks / cards / timeline / quote / figure / linklist / cta / divider | +| L3 局部自由区 | `prose` / `richtext` 块内的 markdown(受白名单类 + tag 白名单) | 后台 | 一段带列表的说明 | +| L4 感官参数 | `content/site/theme.yaml` → 构建期生成 CSS 变量 | 后台(白名单旋钮) | 正文字号、圆角、强调色 | + +### 3.2 yaml 结构总览(一眼看全) + +``` +content/site/ +├── home.yaml # 已有:tagline/avatar/favicon/socials/subtitle/latestPhotos/perTrackLimit/sections/* +│ # 新增:heroStyle / projectsLimit / photosSource / postsTracks / announcement(markdown) +├── about.yaml # 已有:intro{zh,en}(保留为兼容字段,见 §5.5) +│ # 新增:layout{showIdCard,container} + blocks:[] +├── opensource.yaml # 已有(在途):blurb/blurb_after/repo_url/repo_label/pinned/mode/include/exclude/sort/perSource/intro_from +│ # 新增:projectsTitle / showHeatmap / intro_fallback_blurb(README 取不到时的专用文案) +└── theme.yaml # 新增:白名单感官参数(§3.6) +``` + +### 3.3 组件与读取层落点(写代码时照此建文件) + +| 落点 | 职责 | +|---|---| +| `src/lib/page-blocks.ts`(新) | `getAboutBlocks(locale)`:读 `siteAbout` → 过滤 `enabled:false` → 未知 `type` 跳过 + `console.warn` → 文本字段 `pickBi` 回落 zh → 长度上限(块数 ≤ 24、单块文本 ≤ 4000 字) | +| `src/components/blocks/BlockRenderer.astro`(新) | `switch (block.type)` → 渲染子组件;统一外壳 `