Files
pangolin/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md
T
wangjia a22db0874f feat(ds-flow): Phase 5.4 — pre-commit 增挂 ds-flow 条件闸
.githooks/pre-commit 在原有(红线/SQL/codegen-drift)基础上增挂三道 ds-flow 闸,
条件触发、秒级:
- 原型校验(check-ds):动了 design/prototype/ 才跑
- 跨端同源(check-l1-sync):动了 prototype/ 或 web/{website,usercenter}/ 才跑
- Flutter 颜色单源(check_ds_code --changed):动了 client/lib/*.dart 才跑(只扫改动)

install-hooks.sh 说明同步更新。启用仍是每台机一次性 `bash ci/install-hooks.sh`
(不代跑,改本机 git config;CLAUDE.md 治理章节已注明)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 01:42:27 +08:00

8.8 KiB
Raw Blame History

前端设计系统治理重构(ds-flow 落地全端)

用 ds-flow 方法论把 pangolin 全部前端(Flutter 五端 + 官网 website + 用户中心 usercenter) 收口到「设计只有一个出生地(原型单源),代码永远是镜像;漂移由静态闸在提交/CI 前拦截, 走样由 golden/fidelity 双级像素验收兜底」。

关键前提(摸底结论)pangolin 不是从零 bootstrap,已约 65% 达标—— token 单源(design/colors_and_type.css[data-theme=dark])、Flutter codegen + drift 闸、 golden + CI 闸、pre-commit(写好未启用)都在。本计划是补缺口 + Web 共享原子层去重 不是推倒重来。

主题模型:pangolin 用 light / dark 两主题(非 jiu 的 a/b/c 三主题),全程保持。

已定决策:① Web 两端各自实现 + 同源闸(不建跨端共享组件包); ② design/ui_kits/ 的 jsx/css 端原型收敛为纯 HTML 原型并删副本; ③ 先定稿本计划,再逐刀执行(每刀 commit)。

参考样板:~/code/jiudesign/prototype/ + tools/ + client/lib/core/theme/ + docs/frontend-overview.html)。


Phase 0 — 更新 CLAUDE.md + 计划落库

  • 0.1 CLAUDE.md 新增「## 前端设计系统治理(ds-flow)」章节:
    • 原型单源位置(design/prototype/tokens/atoms/icons/index.html 登记簿)+ 只读约定
    • codegen 命令(Flutter gen_flutter_tokens.mjsWeb build-tokens.mjs 同源)
    • 三层治理 L1/L2/L3 规则速查
    • 四道静态闸清单 + 「违规谁拦」对照表(原型校验 / 跨端同源 / 代码色单源 / codegen 零 diff
    • golden(多主题回归自比)/ fidelity(对原型 pixelmatch,本地体检不进 CI)双闸定位
  • 0.2 本 .md 定稿 + 生成 HTML 阅读版 docs/frontend-ds-refactor-plan.html,登记进 docs/index.html「实现计划」
  • 0.3 /todo 建 tier-1 条目跟踪本重构,拆 6 个子任务(对应 Phase 1-5 + 收尾)

Phase 1 — 原型单源三件套(design/prototype/

把散在 ui_kits/6 端 jsx/css 原型)+ preview/20 规格 HTML+ _ds_manifest.json(登记簿) 的东西收敛成 ds-flow 标准三件套。

  • 1.1 建 design/prototype/ 目录;serve.mjs 照搬 jiu(零依赖热重载,默认端口按 jiu)
  • 1.2 design/prototype/tokens.css:从现有 colors_and_type.css 迁移/规整为 「基础 :root(主题无关标量:间距/圆角/字号/字体/阴影/动效)+ [data-theme=dark] 颜色覆盖块」结构。 保持数值不变,只重排为 ds-flow 结构;colors_and_type.css 作为兼容别名或迁移为薄封装(不破坏现有 codegen)
  • 1.3 design/prototype/atoms.css:把按钮/卡片/输入/语言下拉/徽章/状态药丸等公用原子类沉淀为 只引 var(--token) 的 CSS(镜像 design/preview/ 现有规格 + client widgets 实现语义)
  • 1.4 design/prototype/icons.jsSVG sprite 单源(<symbol id="i-*">), 收敛现有分散图标(website Icon.astro / usercenter icons.tsx / Flutter pangolin_icons.dart 三处的图标集)
  • 1.5 design/prototype/index.html:活登记页——三…两主题(light/dark)切换 + data-swatches 声明式色板 + 字号梯度 + 圆角/间距/阴影 + 全部公用组件原子展示卡 + 图标库全展示。每个 atom 必须在此登记
  • 1.6 design/ui_kits/ 的 jsx/css 端原型:提炼进 prototype 后删除 jsx 组件副本(消除与 「禁向 design/ 提组件代码副本」的冲突 + 漂移源);保留必要的屏级 HTML 布局参考迁进 prototype/screens/
  • 1.7 更新/退役 _ds_manifest.json + _ds_bundle.js:登记簿职责交给 index.html, manifest 若仍被消费则保留为派生产物(记清谁是真源)

Phase 2 — Web token 升为一等公民 + 同源闸

现状:Web 的 build-tokens.mjs 只是「原样拷 css,删 Google Fonts 行」。升级为受闸守护的同源关系。

  • 2.1 确认两端 token 落点与生成链:website→src/styles/tokens.gen.css、 usercenter→public/colors_and_type.css;源统一指向 design/prototype/tokens.cssPhase 1 后)
  • 2.2 建 tools/check-l1-sync.mjs(照搬 jiu 裁剪):
    • ① website tokens.gen.css token 值 ≡ 原型 tokens.css(逐值)
    • ② usercenter public/colors_and_type.css ≡ 原型(逐值)
    • ③ icons 同源:website / usercenter / Flutter 三处图标集 ⊆ 原型 icons.js sprite
    • ④ Web 硬编码色扫描(白名单 #fff/#000/logo 固定色,其余报警)
  • 2.3 codegen 幂等:重跑 build-tokens.mjsgit diff 零差异(纳入 CI,见 Phase 5)

Phase 3 — Web 共享原子层对齐(各自实现 + 同源闸)★工作量最大

不建跨端组件包;两端各自实现,但都对齐 design/prototype/atoms.css,靠闸保证不漂移。

  • 3.1 抽公共原子清单:langsel(语言下拉,刚修的两套合规范)/ button / card / input / badge / pill。 对每个原子在 atoms.css 定义 canonical 样式
  • 3.2 websitewebsite.css + site-extra.css 里的按钮/卡片/下拉 class 对齐 atoms.css 语义, 残留 #fff/#000/logo 外的硬编码色清零(当前业务硬编码 ~30 处,多为可保留的白/黑/logo)
  • 3.3 usercentershared.tsxcard/input/LangSeg 内联对象对齐 atoms.css 语义; 残留 13 处硬编码(基本 #fff)核对,非白/黑/logo 的清零
  • 3.4 两端 langsel 行为/样式一致性核对(此前刚统一为自定义下拉,纳入 atoms 登记)
  • 3.5 更新 design/CONTRACT.md:Web 原子清单 + 屏级台账(同步/快照/代码先行三态)

Phase 4 — Flutter 收尾 + golden 补齐

Flutter 已很干净(UI 层零裸 hex),只需收尾。

  • 4.1 清 client/lib/widgets/adaptive_menu.dart 唯 1 处裸 Material 色 → 走 token
  • 4.2 测试字体补 CJK 子集:用 tools/fonts/make-cjk-subset.sh 生成 Noto Sans SC 子集放 client/test/fonts/flutter_test_config.dart 注册——消除 golden 中文与生产渲染差异
  • 4.3 处理现存 6 张 client/test/golden/failures/ diff:逐张确认「原型对得上」后 --update-goldens 重录入库
  • 4.4 golden 覆盖扩容:desktop/tablet/mobile 全屏 × light/dark 双主题矩阵 (现有 desktop_pages/tablet_pages/components/auth → 补 mobile + 主题维度)
  • 4.5 client/test/helpers/harness.dart 对齐 jiu golden_harness.dart 手法: 多主题循环辅助 + 钉死 viewport/dpr + ProviderScope 固定数据(防动态值翻车)

Phase 5 — 静态闸挂满 + 启用 pre-commit + fidelity 体检

  • 5.1 硬编码色扫描闸:
    • Flutter client/tool/check_ds_code.mjs(照搬 jiu,含 --changed 供 pre-commit):禁 Color(0x..)/裸 Colors.x
    • Web hex 扫描并入 check-l1-sync.mjs
  • 5.2 原型校验闸 design/prototype/tools/check-ds.mjs(照搬 jiu 12 道,按 pangolin 断点/主题裁剪)
  • 5.3 CI 串起来(.gitea/workflows/ci.yml 增补): 原型校验 → 跨端同源 → 代码色单源 → codegen 零 diff(已有)→ 测试含 golden(已有,补 mobile+主题)
  • 5.4 启用 pre-commitci/install-hooks.sh 纳入 onboarding 文档 + CLAUDE.md .githooks/pre-commit 增挂 check-ds --changed(只在动了 design/prototype/ 时跑,轻量条件触发)
  • 5.5 fidelity 像素闸(本地体检,不进 CI):tools/screens.mjs 屏注册表 + tools/fidelity.mjs (原型 Chromium 截图 vs Flutter golden pixelmatch,逐屏阈值=实测残差+2pp,两边统一注入 CJK 字体)
  • 5.6 全景文档 docs/frontend-overview.html(照搬 jiu 十节):一次 UI 改动标准路径 + 目录地图 + 三层分治 + 闸全景 + 像素验收体系 + 响应式范式 + 规则速查,登记进 docs/index.html

Verification(端到端)

  • 原型node design/prototype/serve.mjs 起服务,浏览器逐屏目检 light/dark;check-ds.mjs 12 道全绿
  • 同源node tools/check-l1-sync.mjs 全绿(tokens 逐值 / icons 同集 / Web hex 白名单)
  • Flutterflutter analyze + flutter test(含 golden ×双主题);check_ds_code.mjs 全绿;codegen 重跑零 diff
  • Web:两端 npm run build 通过;token 同源闸绿;langsel/button/card 对齐 atoms
  • fidelitynode tools/fidelity.mjs 逐屏残差在阈内(首次校准记录各屏实测值)
  • 闸生效ci/install-hooks.sh 后改一处硬编码色/未登记组件 → pre-commit 或 CI 拦下

不在本轮

  • 新功能/新屏开发(本轮是治理重构,不加业务)
  • iOS/iPad 专属布局深度优化(响应式已覆盖,超阈再单独立项)
  • 三主题扩展(保持 light/dark 双主题)