Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e09a362cc | ||
|
|
8debd99e61 | ||
|
|
be87917443 | ||
|
|
aaa9cd9274 | ||
|
|
2f7cbcf7bd | ||
|
|
6096a9dafe | ||
|
|
59eda420b3 | ||
|
|
740ec470fa |
No files matched your search
@@ -0,0 +1,84 @@
|
||||
# Phase 5g:页面后台化(blocks 模型)与字体子集化 - 项目范围
|
||||
|
||||
<!-- spec-format: 2 -->
|
||||
|
||||
## 1. 问题定义
|
||||
- **项目目标**:①按 docs/research/10 方案 E 把关于页改造成「块式页面构建器」(结构可增删排序)②样式即数据(theme.yaml → 构建期 CSS 变量,含对比度闸门)③首页字段细化并抽 HomePage 消 zh/en 双份 ④开源页收尾(README 缓存/回落/告警)⑤后台文档与 hint 补齐 ⑥字体子集化工具(把艺术字体单页增量从数百 KB 降到数十 KB)
|
||||
- **目标用户**:站长(希望整页可编辑、能上更多艺术字体)与读者(版式与可读性不退化)
|
||||
- **核心价值**:内容与结构的编辑权交回后台,同时守住灰阶体系/双语/SEO/构建期零运行时四条红线
|
||||
|
||||
## 2. 假设与待确认
|
||||
|
||||
### 2.1 已确认事实
|
||||
- Sveltia 0.252 支持 list 的 types + typeKey(方案 10 §3.4 从本仓 bundle 取证),块模型可行
|
||||
- 页面文案 markdown 净化(D1/D2)已在 2cab243 落地(P0 完成)
|
||||
- 字体实测:@fontsource CJK 切片粒度导致单页 +163KB~+8605KB;现有 6 自托管族为基线
|
||||
|
||||
### 2.2 关键假设
|
||||
- 块渲染器受控,破版风险低于整页 HTML 直编(方案 10 §2 对比表)
|
||||
- 字体子集化(pyftsubset 按页实际用字)能把艺术字体单页增量压到 ≤150KB 阈值内
|
||||
|
||||
### 2.3 待确认问题
|
||||
- [x] 关于页整页可编辑路线 → 用户 2026-11-02 批准方案 E(blocks + theme.yaml + 局部自由区)
|
||||
- [x] 字体扩充路线 → 先落 6 族,其余按子集化工具就绪后再评估(本包 T7 交付工具)
|
||||
|
||||
### 2.4 可选解释与取舍
|
||||
- 关于页保留 intro markdown 通道作为 compat(blocks 为空时三级回落:blocks → intro → 默认文案)
|
||||
- 样式即数据只开放白名单旋钮(约 12 项),不开放整份 tokens.css
|
||||
- 图片只走 Astro image() 管线,禁止块内填外链/绝对路径(schema 层拦)
|
||||
|
||||
### 2.5 已证伪路径
|
||||
- 整页富文本直编(C 方案):XSS 面大、无设计兜底,弃
|
||||
- 新增 webfont 直接上(不子集化):单页 +535KB~+8605KB,超阈值,弃(改走 T7 工具)
|
||||
|
||||
## 3. 功能范围
|
||||
|
||||
### 3.1 核心功能(MVP)
|
||||
- [ ] T1 blocks 骨架:schema(discriminatedUnion)+ page-blocks.ts + BlockRenderer + prose/tracks/divider 三块 + 后台 types 声明
|
||||
- [ ] T2 块型扩充:cards/timeline/quote/figure/linklist/cta + 图标键白名单 + 图片 image() 管线
|
||||
- [ ] T3 样式即数据:theme.yaml + theme.ts + BaseLayout 内联变量 + 对比度闸门脚本
|
||||
- [ ] T4 首页细化与去重:抽 HomePage.astro 消 zh/en 双份 + 字段细化(projectsLimit/announcement 等)
|
||||
- [ ] T5 开源页收尾:README 缓存策略/超时/回落矩阵 + fallback JSON 回填 + include 未命中 WARN
|
||||
- [ ] T6 文档与 hint:docs/管理台.md(块编辑用法)+ 写作指南扩充 + admin 全字段中文 hint
|
||||
- [ ] T7 字体子集化工具:按页用字裁剪艺术字体为小切片 + build.sh 守卫挂载 + 实测对比
|
||||
|
||||
### 3.2 扩展功能
|
||||
- 无
|
||||
|
||||
### 3.3 不在范围内
|
||||
- 换 CMS、页面布局的任意拖拽网格、运行时编辑器
|
||||
|
||||
## 4. 最小实现路径
|
||||
- 最简单可行方案:块类型先用 3 类跑通闭环(prose/tracks/divider),再扩到 9 类;theme 只做 12 个白名单旋钮
|
||||
- 暂不引入:可视化块预览、块级动画配置
|
||||
- 不做的抽象:通用页面 DSL(只服务现有页面)
|
||||
|
||||
## 5. 技术决策
|
||||
- 技术栈:Astro 7.4.4 + zod discriminatedUnion + Sveltia list/types + pyftsubset(fonttools)
|
||||
- 证据协议:evidence: runs
|
||||
- 本轮允许改动:src/content.config.ts、src/lib/{page-blocks,theme,site-content}.ts、src/components/blocks/*、src/components/pages/{AboutPage,HomePage}.astro、src/pages/{index,en/index,opensource,en/opensource}.astro、src/layouts/BaseLayout.astro、public/admin/*、content/site/*.yaml、scripts/build-perf/*、infra/deploy/build.sh、docs/*、tests/e2e.mjs
|
||||
- 本轮不应触碰:nginx/ESA、图库灯箱(GalleryPage/PhotoZoom)、Header/Footer 结构
|
||||
- Git integration branch:`spec/2026-11-02_blog-5g-pages`
|
||||
|
||||
### 5.1 验证策略
|
||||
- 范围级别:package
|
||||
- 变更对象:页面数据模型与渲染器、后台配置、样式变量生成、字体产物、文档
|
||||
- 快速检查:`pnpm astro build`(node26)
|
||||
- 集成检查:`node tests/e2e.mjs`(37 项,本包预期新增块/主题断言)+ content-lint 0/0/0
|
||||
- 全项目检查:字体体积账(三页增量)+ 视觉复核(glm-5.3-flash:max,块版式与主题变量双态);仅在构建链或 BaseLayout 结构再变更时升级范围
|
||||
- 升级触发:若 theme 变量波及全局排版(字体字号全站变化)或 blocks 改动触及首页/文章页结构,升级为全站视觉复核与 E2E 全量并记录理由
|
||||
|
||||
## 6. 成功标准与验证方式
|
||||
- [ ] 关于页整页由 yaml blocks 驱动,增删排序生效 -> verify: task_0001
|
||||
- [ ] 九类块全部可渲染且旧内容零回归(三级回落) -> verify: task_0002
|
||||
- [ ] theme.yaml 改值 → 产物 CSS 变量变化,对比度闸门拦截不达标 -> verify: task_0003
|
||||
- [ ] 首页 zh/en 由同一组件渲染且字段可配 -> verify: task_0004
|
||||
- [ ] 开源页 README 失败矩阵与 fallback 告警可用 -> verify: task_0005
|
||||
- [ ] 后台文档与 hint 完整 -> verify: task_0006
|
||||
- [ ] 字体子集化工具把指定字体单页增量压到 ≤150KB -> verify: task_0007
|
||||
|
||||
## 7. 风险与约束
|
||||
- 灰阶体系与双语红线不变;彩色仅正文强调
|
||||
- 块渲染器未知类型跳过 + WARN,绝不炸构建
|
||||
- 字体子集化需保证字形覆盖(裁错字会出现豆腐块)→ 断言:子集后页面文本逐字命中
|
||||
- 多车道并行:共享文件(content.config.ts/admin config/docs)按 boundary 划界,tokens/global 由 orchestrator 或指定单车道
|
||||
@@ -0,0 +1,42 @@
|
||||
# Phase 5g:页面后台化(blocks 模型)与字体子集化 - 任务拆解
|
||||
|
||||
## 使用规则
|
||||
- boundary/verify 齐备;verify 只读断言;车道工作树开发禁 git,收编由 orchestrator 统一提交
|
||||
- 构建一律 `export PATH="$HOME/.local/node/bin:$PATH"`(Node 26)
|
||||
|
||||
## 阶段一:实现
|
||||
|
||||
- [x] T1 blocks 骨架(关于页块式页面构建器)
|
||||
- claim: op-gitea
|
||||
- boundary: src/content.config.ts(siteAbout 加 blocks: z.array(discriminatedUnion))、新增 src/lib/page-blocks.ts(getAboutBlocks:过滤 enabled、未知 type 跳过+WARN、文本 pickBi 回落、块数≤24/单块≤4000 字)、新增 src/components/blocks/{BlockRenderer,Prose,Tracks,Divider}.astro、AboutPage.astro 改由 blocks 驱动(blocks 空→intro markdown→默认文案三级回落)、public/admin/config.yml 加 list+types(typeKey: type)
|
||||
- verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && grep -q "discriminatedUnion" src/content.config.ts && grep -q "BlockRenderer" src/components/pages/AboutPage.astro && grep -q "typeKey" public/admin/config.yml`
|
||||
|
||||
- [x] T2 块型扩充与图片管线
|
||||
- claim: op-gitea
|
||||
- boundary: 新增 src/components/blocks/{Cards,Timeline,Quote,Figure,LinkList,Cta}.astro + 图标键白名单(复用 SocialLinks 注册表或新建 icons 注册表)、schema 块型补全(图片字段用 image(),禁止外链字符串)、content/site/assets/ 目录、near docs 图表说明
|
||||
- verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && ls src/components/blocks/ | grep -qC1 "Cards\|Timeline" && grep -q "image()" src/content.config.ts`
|
||||
|
||||
- [x] T3 样式即数据(theme.yaml + 对比度闸门)
|
||||
- claim: op-artalk
|
||||
- boundary: 新增 content/site/theme.yaml(12 个白名单旋钮:prose-size/measure/radius/accent/leading 等)、新增 src/lib/theme.ts(getTheme + themeVarsCss 生成 :root:root{…})、BaseLayout.astro head 内联 theme 变量(构建期静态)、新增 scripts/build-perf/contrast-check.mjs(断言 theme 结果下正文对比度 ≥4.5)、public/admin/config.yml 加 theme 单例、build.sh 守卫挂载
|
||||
- verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && test -f content/site/theme.yaml && node scripts/build-perf/contrast-check.mjs dist`
|
||||
|
||||
- [ ] T4 首页细化与去重
|
||||
- claim: op-artalk
|
||||
- boundary: 新增 src/components/pages/HomePage.astro(承接现 index.astro 区块逻辑,locale prop)、src/pages/{index,en/index}.astro 改为薄壳、home.yaml 增 projectsLimit / announcement(markdown)/ postsTracks(轨开关细分),site-content 访问器同步
|
||||
- verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && test -f src/components/pages/HomePage.astro && grep -q "HomePage" src/pages/en/index.astro`
|
||||
|
||||
- [x] T5 开源页收尾(缓存/回落/告警)
|
||||
- claim: worker-one
|
||||
- boundary: src/lib/site-content.ts(README 缓存策略与超时、回落矩阵)、content/.github-readme.md 与 README HTML 剥离策略(复用 rehype-content-sanitize 已挡危险标签;补: 外链徽章不阻断)、src/data/projects-fallback.json 回填 5-8 条真实仓、projects.ts include 未命中 console.warn
|
||||
- verify: `E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && python3 -c "import json;d=json.load(open('src/data/projects-fallback.json'));assert len(d)>=5"`
|
||||
|
||||
- [ ] T6 文档与后台 hint 补齐
|
||||
- claim: worker-one
|
||||
- boundary: docs/管理台.md(块编辑怎么用、增删排序、预览限制)、docs/写作指南.md(块字段表/受限类/主题项)、public/admin/config.yml 全字段中文 hint(含 T1-T4 新增字段)
|
||||
- verify: `test -f docs/管理台.md && grep -q "blocks\|区块" docs/管理台.md && grep -c "hint" public/admin/config.yml | awk '$1>=20'`
|
||||
|
||||
- [x] T7 字体子集化工具
|
||||
- claim: orchestrator
|
||||
- boundary: 新增 scripts/build-perf/subset-fonts.py(pyftsubset 按指定字体 + 页面实际用字生成子集 woff2 + 重写 fonts.css 指向子集文件)、infra/deploy/build.sh 守卫挂载、docs/写作指南加字流程补"子集化"一节
|
||||
- verify: `test -f scripts/build-perf/subset-fonts.py && python3 -c "import fontTools; print('fonttools ok')" && E2E_BASE=http://127.0.0.1:18924 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS"`
|
||||
+68
-6
@@ -1,9 +1,17 @@
|
||||
# 关于页正文(后台「页面文案 → 关于页」可改,markdown 编辑)
|
||||
# intro = 多段 markdown 正文,渲染在「关于」标题下方、名片之前;留空回落默认文案
|
||||
# 支持的语法:段落、列表、粗斜体、行内代码、链接(渲染走 Astro 的 markdown 管线)
|
||||
intro:
|
||||
# 关于页(后台「页面文案 → 关于页」可改)
|
||||
# ── 一级:blocks 块式正文(按顺序渲染,可拖拽排序;某块 enabled: false 即隐藏)
|
||||
# ── 二级:intro 多段 markdown(仅在 blocks 为空时使用)
|
||||
# ── 三级:内置默认文案(两者都空时兜底,构建永不炸)
|
||||
layout:
|
||||
# 名片区(头像/名字/身份语/社交)开关:头像等数据事实源在「主页设置」
|
||||
showIdCard: true
|
||||
|
||||
blocks:
|
||||
- type: prose
|
||||
width: narrow
|
||||
body:
|
||||
zh: |
|
||||
写作者 · 读者 · 快门按压者,拥抱开源。
|
||||
<span class="font-huiwen c-red">写作者</span> · 读者 · 快门按压者,拥抱开源。
|
||||
|
||||
这里是我三条轨道的公开工作台:**读过的书**留下评注,**写过的代码**进项目墙,**按下的快门**收入图库。
|
||||
|
||||
@@ -15,7 +23,7 @@ intro:
|
||||
|
||||
本站本身即开源,构建与发布全链都在仓里。
|
||||
en: |
|
||||
Writer · Reader · Shutter-presser, embracing open source.
|
||||
<span class="font-huiwen c-red">Writer</span> · Reader · Shutter-presser, embracing open source.
|
||||
|
||||
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.
|
||||
|
||||
@@ -26,3 +34,57 @@ intro:
|
||||
- Images go to the gallery, with a bit of EXIF and one line of curation
|
||||
|
||||
This site is itself open source — the full build and deploy pipeline lives in the repo.
|
||||
|
||||
- type: tracks
|
||||
title:
|
||||
zh: 兴趣版图
|
||||
en: Interests
|
||||
items:
|
||||
- icon: book
|
||||
name:
|
||||
zh: 阅读
|
||||
en: Reading
|
||||
desc:
|
||||
zh: 文学与戏剧为主,读到哪写到哪。
|
||||
en: Mostly literature and drama; I write as I read.
|
||||
- icon: terminal
|
||||
name:
|
||||
zh: 技术
|
||||
en: Tech
|
||||
desc:
|
||||
zh: Linux、容器与自托管,把家里的小机器折腾成顺手的工具。
|
||||
en: Linux, containers, and self-hosting — turning the little machines at home into handy tools.
|
||||
- icon: camera
|
||||
name:
|
||||
zh: 摄影
|
||||
en: Photography
|
||||
desc:
|
||||
zh: 街拍与山野,随身一台无反,在等光的间隙按快门。
|
||||
en: Street and landscapes with a mirrorless camera, pressing the shutter while waiting for the light.
|
||||
|
||||
- type: prose
|
||||
title:
|
||||
zh: 本站如何构建
|
||||
en: How this site is built
|
||||
body:
|
||||
zh: 页面由 Astro 静态生成,不含运行时框架 JS;内容住在自托管 gitea——本地编辑器与 gitea 网页写的是同一个 git 仓库,push 之后由 homelab 自动构建发布;评论走自托管 Artalk。页脚 built from 一行链到本次构建对应的 commit,构建过程透明可追溯。
|
||||
en: Pages are statically generated by Astro with no runtime framework JS. Content lives on a self-hosted gitea — my local editor and the gitea web UI write to the same git repository, and each push is built and published automatically by the homelab. Comments run on self-hosted Artalk. The built-from line in the footer links to the commit behind this build, keeping the process transparent and traceable.
|
||||
|
||||
# ---- 二级回退(blocks 为空时使用)----
|
||||
intro:
|
||||
zh: |
|
||||
写作者 · 读者 · 快门按压者,拥抱开源。
|
||||
|
||||
这里是我三条轨道的公开工作台:**读过的书**留下评注,**写过的代码**进项目墙,**按下的快门**收入图库。
|
||||
en: |
|
||||
Writer · Reader · Shutter-presser, embracing open source.
|
||||
|
||||
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)
|
||||
# 页面级排版覆盖(后台「关于页 → 页面排版覆盖」可改):
|
||||
# 整页换字族会带来字体体积成本(如 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
|
||||
@@ -0,0 +1,37 @@
|
||||
# 主题旋钮(样式即数据 · 层 4):只放白名单内的 9 组旋钮。
|
||||
# 红线:--measure(版心)与断点/纸墨/code 配色不在此列——它们牵动版面结构与分轨身份。
|
||||
# 全部留空 = 沿用 src/styles/tokens.css 的既有值(零配置零变化)。
|
||||
# 钳制与单调性在 src/lib/theme.ts 里做:越界值被夹取而非报错,构建不会因主题配置失败。
|
||||
|
||||
# ① 强调色(明/暗两值;构建期闸门校验正文对比度 ≥4.5,不达标回落默认)
|
||||
accent_light: '#3454d1'
|
||||
accent_dark: '#8ea2ff'
|
||||
|
||||
# ② 图片圆角(4–16;08 文档裁定上限 14)
|
||||
radius_img: 10
|
||||
|
||||
# ③ 标题字号(22–32;必须 h1 > h2 > h3,否则整体回落默认)
|
||||
text_h1: 27
|
||||
text_h2: 22
|
||||
text_h3: 19
|
||||
|
||||
# ④ 正文字号(16–22)
|
||||
prose_size_reading: 20
|
||||
prose_size_tech: 19
|
||||
|
||||
# ⑤ 正文行高(1.5–2.0)
|
||||
leading_reading: 1.75
|
||||
leading_tech: 1.7
|
||||
|
||||
# ⑥ 间距梯度(8–80;必须严格递增 3 < 4 < 5 < 6,否则回落默认)
|
||||
space_3: 16
|
||||
space_4: 24
|
||||
space_5: 40
|
||||
space_6: 64
|
||||
|
||||
# ⑦ 段落流距(0–2em)
|
||||
flow_p: 0.9
|
||||
flow_h2_post: 0.6
|
||||
|
||||
# ⑧ 过渡时长(150–600ms)
|
||||
dur: 350
|
||||
@@ -185,6 +185,32 @@ https://astro.build/
|
||||
后台编辑器里:**选中文字 → Insert 菜单 → 「排版(字体/颜色)」→ 面板里点一个类**,文字即被 `<span class="…">` 包住;点已套用的片段可改类,Backspace 可整体删除。
|
||||
面板里的两类与上表一一对应(字体 8 / 颜色 9),类清单单一事实源在 `public/admin/typography-classes.js`。
|
||||
|
||||
## 三层排版架构(全站,不只文章正文)
|
||||
|
||||
**层 1 · 页面文案富文本**:后台「页面文案」里的 tagline / subtitle / blurb / blurb_after / intro / 关于页 blocks 的 prose 块,全部走同一条富文本管线(markdown + raw + 内容净化 + class 白名单 + 链接卡片)。可以直接写:
|
||||
|
||||
```yaml
|
||||
tagline:
|
||||
zh: '<span class="font-kai c-blue">写作者</span> · 读者 · 快门按压者,拥抱开源。'
|
||||
```
|
||||
|
||||
渲染入口唯一:`src/lib/site-content.ts` 的 `renderRich()`(行内场景传 `{ inline: true }` 自动剥外层 `<p>`,否则 `<p>` 套 `<p>` 会被浏览器拆散)。
|
||||
**不开放**:导航/页脚/按钮等硬编码界面外壳——那是 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 秒)
|
||||
|
||||
@@ -33,6 +33,7 @@ pnpm astro build
|
||||
# 按页字体 CSS 子集化(车道 A 任务 1):裁 @font-face 声明数,构建仓与本地同链;
|
||||
# 存在性守卫:新文件未推送到 main 前构建仓无此脚本,绝不让发布链因车道在途文件断掉
|
||||
[ -f scripts/build-perf/subset-font-css.mjs ] && node scripts/build-perf/subset-font-css.mjs dist || echo "[build] subset 脚本未就绪,跳过"
|
||||
[ -f scripts/build-perf/contrast-check.mjs ] && node scripts/build-perf/contrast-check.mjs dist || echo "[build] contrast 脚本未就绪,跳过"
|
||||
# 首页阻塞 CSS 内联(车道 D):守卫先行同上——脚本未到 main 前绝不炸链
|
||||
[ -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 脚本未就绪,跳过"
|
||||
|
||||
+335
-3
@@ -58,6 +58,29 @@ collections:
|
||||
- { label: 草稿, name: draft, widget: boolean, required: false, default: false }
|
||||
- { label: 正文, name: body, widget: markdown }
|
||||
|
||||
# 主题旋钮(样式即数据 · 层 4):只放白名单内的 9 组,越界值会被构建期钳制
|
||||
- name: site_theme
|
||||
label: 主题设置
|
||||
file: content/site/theme.yaml
|
||||
fields:
|
||||
- { label: 强调色(亮), name: accent_light, widget: color, required: false, hint: '亮色模式强调色,如 #3454d1;构建期校验正文对比度 ≥4.5' }
|
||||
- { label: 强调色(暗), name: accent_dark, widget: color, required: false, hint: '暗色模式强调色,如 #8ea2ff' }
|
||||
- { label: 图片圆角, name: radius_img, widget: number, required: false, value_type: int, min: 4, max: 16, hint: '范围 4–16(建议 ≤14)' }
|
||||
- { label: 一级标题字号, name: text_h1, widget: number, required: false, value_type: int, min: 22, max: 32, hint: '22–32,且必须大于 h2' }
|
||||
- { label: 二级标题字号, name: text_h2, widget: number, required: false, value_type: int, min: 22, max: 32, hint: '22–32,必须小于 h1、大于 h3' }
|
||||
- { label: 三级标题字号, name: text_h3, widget: number, required: false, value_type: int, min: 16, max: 32, hint: '16–32,必须小于 h2' }
|
||||
- { label: 书评正文字号, name: prose_size_reading, widget: number, required: false, value_type: int, min: 16, max: 22, hint: '16–22' }
|
||||
- { label: 技术文正文字号, name: prose_size_tech, widget: number, required: false, value_type: int, min: 16, max: 22, hint: '16–22' }
|
||||
- { label: 书评行高, name: leading_reading, widget: number, required: false, value_type: float, min: 1.5, max: 2.0, step: 0.05, hint: '1.5–2.0' }
|
||||
- { label: 技术文行高, name: leading_tech, widget: number, required: false, value_type: float, min: 1.5, max: 2.0, step: 0.05, hint: '1.5–2.0' }
|
||||
- { label: 间距 3, name: space_3, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 < 间距 4' }
|
||||
- { label: 间距 4, name: space_4, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 3 且 < 间距 5' }
|
||||
- { label: 间距 5, name: space_5, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 4 且 < 间距 6' }
|
||||
- { label: 间距 6, name: space_6, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 5' }
|
||||
- { label: 段间距, name: flow_p, widget: number, required: false, value_type: float, min: 0, max: 2, step: 0.05, hint: '0–2(em)' }
|
||||
- { label: 标题下间距, name: flow_h2_post, widget: number, required: false, value_type: float, min: 0, max: 2, step: 0.05, hint: '0–2(em)' }
|
||||
- { label: 过渡时长, name: dur, widget: number, required: false, value_type: int, min: 150, max: 600, hint: '150–600(毫秒)' }
|
||||
|
||||
# 瞬间:随手发(text/image 至少其一——Sveltia 无法表达条件必填,两者都设可选,
|
||||
# 保存前自查;pubDate 必填)。图片走图库媒体库(content/photos 同源可复用)
|
||||
- name: moments
|
||||
@@ -119,10 +142,45 @@ collections:
|
||||
fields:
|
||||
- label: 身份语
|
||||
name: tagline
|
||||
- label: 页面排版覆盖(可选)
|
||||
name: typography
|
||||
widget: object
|
||||
required: false
|
||||
hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
|
||||
fields:
|
||||
- label: 正文字体类
|
||||
name: font
|
||||
widget: select
|
||||
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]
|
||||
- label: 强调色类
|
||||
name: accent
|
||||
widget: select
|
||||
required: false
|
||||
options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
|
||||
- { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05 }
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 公告(可选,markdown)
|
||||
name: announcement
|
||||
widget: object
|
||||
required: false
|
||||
hint: 渲染在名片区下方;留空则不显示公告块
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: markdown, required: false }
|
||||
- { label: 英文, name: en, widget: markdown, required: false }
|
||||
- { label: 项目墙条数, name: projectsLimit, widget: number, required: false, value_type: int, min: 1, max: 99, hint: '首页项目墙显示几条(1–99,缺省 6)' }
|
||||
- label: 轨细分开关(首页文章列表)
|
||||
name: postsTracks
|
||||
widget: object
|
||||
required: false
|
||||
hint: 关掉某轨则该轨文章不在首页列出(全开=现状)
|
||||
fields:
|
||||
- { label: 阅读轨, name: reading, widget: boolean, required: false, default: true }
|
||||
- { label: 技术轨, name: tech, widget: boolean, required: false, default: true }
|
||||
- { label: 照片轨, name: photo, widget: boolean, required: false, default: true }
|
||||
- label: 副标题(可选,markdown 短文本)
|
||||
name: subtitle
|
||||
widget: object
|
||||
@@ -183,20 +241,294 @@ collections:
|
||||
- name: about
|
||||
label: 关于页
|
||||
file: content/site/about.yaml
|
||||
# 块内图片上传落 content/site/assets/,yaml 写 ./assets/xxx(Astro 图片管线)
|
||||
media_folder: content/site/assets
|
||||
public_folder: ./assets
|
||||
fields:
|
||||
- label: 正文(markdown,多段)
|
||||
name: intro
|
||||
- label: 页面块(拖拽排序;每块可折叠)
|
||||
name: blocks
|
||||
widget: list
|
||||
typeKey: type
|
||||
required: false
|
||||
summary: '{{fields.type}}'
|
||||
hint: '点「+ 添加」选块型。关掉某块用该块内的「显示」开关'
|
||||
types:
|
||||
- label: 正文(markdown)
|
||||
name: prose
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 小标题(可选)
|
||||
name: title
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 正文(markdown)
|
||||
name: body
|
||||
widget: object
|
||||
hint: 渲染在「关于」标题下方、名片之上;支持段落/列表/粗斜体/链接;留空用默认文案
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: markdown, required: false }
|
||||
- { label: 英文, name: en, widget: markdown, required: false }
|
||||
- label: 宽度
|
||||
name: width
|
||||
widget: select
|
||||
required: false
|
||||
default: narrow
|
||||
options: [{ label: 版心宽度, value: narrow }, { label: 通栏, value: full }]
|
||||
- label: 版图(图标+名称+描述)
|
||||
name: tracks
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 标题
|
||||
name: title
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 条目
|
||||
name: items
|
||||
widget: list
|
||||
summary: '{{fields.name.zh}}'
|
||||
fields:
|
||||
- label: 图标
|
||||
name: icon
|
||||
widget: select
|
||||
required: false
|
||||
options: [book, terminal, camera, code, git, rss, email, github, bilibili, x, star, link]
|
||||
hint: 白名单外或留空 → 显示首字占位
|
||||
- label: 名称
|
||||
name: name
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 描述
|
||||
name: desc
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: text, required: false }
|
||||
- { label: 英文, name: en, widget: text, required: false }
|
||||
- label: 卡片(2/3 列)
|
||||
name: cards
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 标题(可选)
|
||||
name: title
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- { label: 列数, name: columns, widget: number, required: false, default: 3, min: 2, max: 3, value_type: int }
|
||||
- label: 卡片条目
|
||||
name: items
|
||||
widget: list
|
||||
summary: '{{fields.title.zh}}'
|
||||
fields:
|
||||
- label: 标题
|
||||
name: title
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 描述
|
||||
name: desc
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: text, required: false }
|
||||
- { label: 英文, name: en, widget: text, required: false }
|
||||
- { label: 链接(可选), name: href, widget: string, required: false }
|
||||
- label: 角标(可选)
|
||||
name: tag
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 时间线
|
||||
name: timeline
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 标题(可选)
|
||||
name: title
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 条目
|
||||
name: items
|
||||
widget: list
|
||||
summary: '{{fields.time}} · {{fields.title.zh}}'
|
||||
fields:
|
||||
- { label: 时间, name: time, widget: string, hint: '自由文本,如 2024 — 2026' }
|
||||
- label: 标题
|
||||
name: title
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 描述(可选)
|
||||
name: desc
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: text, required: false }
|
||||
- { label: 英文, name: en, widget: text, required: false }
|
||||
- label: 引文
|
||||
name: quote
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 引文
|
||||
name: text
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: text, required: false }
|
||||
- { label: 英文, name: en, widget: text, required: false }
|
||||
- label: 出处(可选)
|
||||
name: cite
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 图片
|
||||
name: figure
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- { label: 图片(必填,请用后台上传), name: image, widget: image, hint: '禁止填外链:只能上传(落 content/site/assets/),走 Astro 图片管线' }
|
||||
- { label: 替代文本(无障碍), name: alt, widget: string, required: false }
|
||||
- label: 图注(可选)
|
||||
name: caption
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 链接清单
|
||||
name: linklist
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 标题(可选)
|
||||
name: title
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 链接条目
|
||||
name: items
|
||||
widget: list
|
||||
summary: '{{fields.label.zh}} → {{fields.href}}'
|
||||
fields:
|
||||
- label: 名称
|
||||
name: label
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- { label: 链接, name: href, widget: string }
|
||||
- label: 备注(可选)
|
||||
name: note
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 行动按钮
|
||||
name: cta
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 说明文字
|
||||
name: text
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- { label: 按钮链接, name: href, widget: string }
|
||||
- label: 按钮文字
|
||||
name: label
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
- { label: 英文, name: en, widget: string, required: false }
|
||||
- label: 分隔
|
||||
name: divider
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 显示, name: enabled, widget: boolean, required: false, default: true }
|
||||
- label: 样式
|
||||
name: style
|
||||
widget: select
|
||||
required: false
|
||||
default: line
|
||||
options: [{ label: 细分隔线, value: line }, { label: 纯留白, value: space }]
|
||||
- label: 名片区开关
|
||||
name: layout
|
||||
widget: object
|
||||
required: false
|
||||
hint: 关掉则不显示头像/名字/社交(它们的数据在「主页设置」)
|
||||
fields:
|
||||
- { label: 显示名片区, name: showIdCard, widget: boolean, required: false, default: true }
|
||||
- label: 正文回退(blocks 为空时用,markdown,多段)
|
||||
name: intro
|
||||
widget: object
|
||||
required: false
|
||||
hint: 仅在「页面块」为空时渲染;与块同时存在时以块为准
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: markdown, required: false }
|
||||
- { label: 英文, name: en, widget: markdown, required: false }
|
||||
- label: 页面排版覆盖(可选)
|
||||
name: typography
|
||||
widget: object
|
||||
required: false
|
||||
hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
|
||||
fields:
|
||||
- label: 正文字体类
|
||||
name: font
|
||||
widget: select
|
||||
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]
|
||||
- label: 强调色类
|
||||
name: accent
|
||||
widget: select
|
||||
required: false
|
||||
options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
|
||||
- { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05 }
|
||||
- name: opensource
|
||||
label: 开源页
|
||||
file: content/site/opensource.yaml
|
||||
fields:
|
||||
- label: 叙述(链接前)
|
||||
name: blurb
|
||||
- label: 页面排版覆盖(可选)
|
||||
name: typography
|
||||
widget: object
|
||||
required: false
|
||||
hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
|
||||
fields:
|
||||
- label: 正文字体类
|
||||
name: font
|
||||
widget: select
|
||||
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]
|
||||
- label: 强调色类
|
||||
name: accent
|
||||
widget: select
|
||||
required: false
|
||||
options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
|
||||
- { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05 }
|
||||
widget: object
|
||||
fields:
|
||||
- { label: 中文, name: zh, widget: string, required: false }
|
||||
|
||||
@@ -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' },
|
||||
|
||||
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user