diff --git a/design/CONTRACT.md b/design/CONTRACT.md index 7e61452..35cbc38 100644 --- a/design/CONTRACT.md +++ b/design/CONTRACT.md @@ -90,3 +90,33 @@ - 连接键 off 态:原型用实心 11px 环,Flutter 用「虚线轨道环」(design/CLAUDE.md §5 canonical 连接键),以 §5 为准。 - 账户页:生产实现比原型多设备管理/兑换/联系/协议行,属真实功能扩展,沿用同设计语言。 - golden 测试环境未打包 Noto Sans SC → CJK 显示为方块,仅影响 golden 文字、不影响真机;布局可判。节点网格/周柱在未登录测试态无数据(需注入演示数据方显内容)。 + +--- + +## 6. ds-flow · Web 原子清单 + 屏级三态台账(2026-07 治理) + +> 决策:Web 两端(website / usercenter)框架不同(Astro-island vs Next 静态),**各自实现 + 同源闸**——不建跨端共享组件包,两端对齐同一 `design/prototype/atoms.css` 语义,靠 `tools/check-l1-sync.mjs` 强制 token 值 + 图标同源不漂移。 + +### 6.1 公用原子清单(canonical = `design/prototype/atoms.css`) +| 原子 | 原型 class | website 实现 | usercenter 实现 | +|---|---|---|---| +| 按钮 | `.btn`/`-primary`/`-ghost`/`-subtle`/`-danger` | `website.css .btn*`(class) | `shared.tsx`(CSSProperties) | +| 卡片 | `.card` | `.card`/`.plan` | `shared.tsx card` | +| 输入 | `.input`/`.field` | 表单 class | `shared.tsx input` | +| 徽章/药丸 | `.pill`/`.badge`(状态/accent/outline) | `.tag`/`.plan` 徽章 | 内联 pill | +| 语言下拉 | `.langsel`/`.menu` | `Header.jsx` 自控下拉 | `shared.tsx LangSeg` | +> 两端语言下拉已统一为「自控菜单」(非原生 select,防 macOS 弹层漂移),行为一致、均对齐 `.langsel`/`.menu` 语义。 + +### 6.2 图标:三端 ⊆ 原型 sprite +`design/prototype/icons.js`(58 Lucide)是图标单源。usercenter `LUCIDE`(键+路径)、Flutter `pangolin_icons._byName`(键)由 `check-l1-sync ③` 强制 ⊆ 原型;website 经 lucide-react 构建期内联。 + +### 6.3 屏级三态台账(L2) +| 面 | 态 | 基准 | 说明 | +|---|---|---|---| +| Flutter mobile/tablet/desktop | 快照 | golden ×light/dark | 原型退役,golden + 本契约文字为准 | +| website(官网各屏) | 代码先行 | 无原型屏 | canonical 在 `web/website/`,token/图标同源闸守护 | +| usercenter(各视图) | 代码先行 | 无原型屏 | canonical 在 `web/usercenter/`,同上 | +| 组件原子层 | 同步 | `prototype/index.html` 登记页 | L1 无例外先原型;`check-ds`(Phase 5)强制登记 | + +### 6.4 硬编码色白名单(`check-l1-sync ④`) +`#fff/#ffffff/#000/#000000` + 品牌 logo 固定色 `#B96A3D/#FAF3ED/#F4EFE8/#9E5630/#3D2213`;其余一律 `var(--token)` 或行内 `ds-allow` 豁免。website 页脚恒暗区灰阶已就近吸附 `--sand-300/400/500`。 diff --git a/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md b/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md index 69269dd..c48214c 100644 --- a/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md +++ b/docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md @@ -73,14 +73,14 @@ 不建跨端组件包;两端各自实现,但都对齐 `design/prototype/atoms.css`,靠闸保证不漂移。 -- [ ] 3.1 抽公共原子清单:langsel(语言下拉,刚修的两套合规范)/ button / card / input / badge / pill。 +- [x] 3.1 抽公共原子清单:langsel(语言下拉,刚修的两套合规范)/ button / card / input / badge / pill。 对每个原子在 `atoms.css` 定义 canonical 样式 -- [ ] 3.2 website:`website.css` + `site-extra.css` 里的按钮/卡片/下拉 class 对齐 atoms.css 语义, +- [x] 3.2 website:`website.css` + `site-extra.css` 里的按钮/卡片/下拉 class 对齐 atoms.css 语义, 残留 `#fff/#000`/logo 外的硬编码色清零(当前业务硬编码 ~30 处,多为可保留的白/黑/logo) -- [ ] 3.3 usercenter:`shared.tsx` 的 `card/input/LangSeg` 内联对象对齐 atoms.css 语义; +- [x] 3.3 usercenter:`shared.tsx` 的 `card/input/LangSeg` 内联对象对齐 atoms.css 语义; 残留 13 处硬编码(基本 `#fff`)核对,非白/黑/logo 的清零 -- [ ] 3.4 两端 langsel 行为/样式一致性核对(此前刚统一为自定义下拉,纳入 atoms 登记) -- [ ] 3.5 更新 `design/CONTRACT.md`:Web 原子清单 + 屏级台账(同步/快照/代码先行三态) +- [x] 3.4 两端 langsel 行为/样式一致性核对(此前刚统一为自定义下拉,纳入 atoms 登记) +- [x] 3.5 更新 `design/CONTRACT.md`:Web 原子清单 + 屏级台账(同步/快照/代码先行三态) --- diff --git a/tools/check-l1-sync.mjs b/tools/check-l1-sync.mjs index 56515e3..3f045d1 100644 --- a/tools/check-l1-sync.mjs +++ b/tools/check-l1-sync.mjs @@ -94,7 +94,7 @@ function checkWebTokenSync(label, webPath) { // ── ④ Web 硬编码色扫描 ────────────────────────────────────── { // 白名单:纯白/纯黑 + 品牌 logo 固定色(SVG 内联 fill,非业务散色) - const ALLOW = new Set(['fff', 'ffffff', '000', '000000', 'b96a3d', 'faf3ed', '9e5630', '3d2213']); + const ALLOW = new Set(['fff', 'ffffff', '000', '000000', 'b96a3d', 'faf3ed', 'f4efe8', '9e5630', '3d2213']); // 排除:生成的 token 定义文件 + 构建产物 const SKIP = new Set([ 'web/website/src/styles/tokens.gen.css', diff --git a/web/website/src/styles/website.css b/web/website/src/styles/website.css index b19793a..2e7ce30 100644 --- a/web/website/src/styles/website.css +++ b/web/website/src/styles/website.css @@ -227,17 +227,17 @@ section{padding:88px 0} .cta-ghost:hover{border-color:#fff} /* ---------- footer ---------- */ -.ftr{background:var(--sand-950);color:#cfc6b8;padding:64px 0 32px} +.ftr{background:var(--sand-950);color:var(--sand-300);padding:64px 0 32px} [data-theme="dark"] .ftr{background:#000} .ftr .top{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:36px} .ftr .nm{font-family:var(--font-display);font-weight:700;font-size:18px;color:#fff;display:flex;align-items:center;gap:10px} -.ftr .tag{font-size:13.5px;line-height:1.6;margin:14px 0 0;max-width:280px;color:#a89e8e} -.ftr h4{font-family:var(--font-sans);font-size:12px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#8a8070;margin:0 0 14px} +.ftr .tag{font-size:13.5px;line-height:1.6;margin:14px 0 0;max-width:280px;color:var(--sand-400)} +.ftr h4{font-family:var(--font-sans);font-size:12px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--sand-500);margin:0 0 14px} .ftr ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:10px} -.ftr ul a{font-size:14px;color:#cfc6b8} +.ftr ul a{font-size:14px;color:var(--sand-300)} .ftr ul a:hover{color:#fff} .ftr .mono{font-family:var(--font-mono);font-size:12.5px} -.ftr .bot{display:flex;align-items:center;justify-content:space-between;margin-top:46px;padding-top:24px;border-top:1px solid rgba(255,255,255,.1);font-size:12.5px;color:#8a8070;flex-wrap:wrap;gap:12px} +.ftr .bot{display:flex;align-items:center;justify-content:space-between;margin-top:46px;padding-top:24px;border-top:1px solid rgba(255,255,255,.1);font-size:12.5px;color:var(--sand-500);flex-wrap:wrap;gap:12px} /* ---------- responsive ---------- */ @media (max-width:980px){