设计系统(wiki + dashboard 共用)
本质与导读
「不考虑工作量,最统一做法」—— 用户 2026-05-29 决策。本文是设计系统的契约
- 上手指南。改样式前先看这里。
抓硬约束
- 格式跟内容独立:markdown 内容(
wiki/pages/*.md) 跟 CSS 样式完全解耦, 写新页 / 写 prose 不需要懂 design system - wiki + dashboard 双 app 共用:跨 app 视觉语言一致(同色 / 同卡 / 同 chip)
- 改一处全站同步:token 只在
_tokens.css改;primitive 只在_atoms.css改; 组件只在apps/web/components/atoms/*改 - 便于扩展 / 移植:加新 app(如 mobile native / 第二 dashboard)只需 import 同 3 个文件 + 写自己 layout
因果分析:为什么 3 层
| 层 | 文件 | 改什么 | 谁能看到 |
|---|---|---|---|
| Layer 1 Token | apps/web/styles/_tokens.css | 颜色码 / 字号 / 阴影 / 字体 | 全站全部 |
| Layer 2 Primitive | apps/web/styles/_atoms.css | 卡形 / chip 形 / 按钮态 / callout 变体 | 任何引用 CSS 类的位置 |
| Layer 3 App-specific | apps/web/styles/globals.css(wiki),apps/invest-dashboard/src/dashboard.css(dashboard) | 业务 specific(wiki prose, dashboard cc-* 容器) | 各 app 自己 |
| Layer 4 React Atom | apps/web/components/atoms/* (待建) | <Card> <Chip> <Button> JSX | TSX 引用方 |
单一职责:每一层只管它该管的。改色去 1,改卡形去 2,改业务排版去 3,改组件 prop 去 4。
禁止逆向:Layer 3 不能 hardcode #f2e9dc(应 rgb(var(--c-page-bg)));Layer 2
不能加 body / :where(h1) 这种业务选择器。
解决方案:目录 + 命名
Layer 1 —— apps/web/styles/_tokens.css
apps/web/styles/_tokens.css:root {
/* 颜色 RGB triple(无 # 让 Tailwind /alpha 复用)*/
--c-page-bg: 242 233 220; /* warm cream 全站背景 */
--c-paper: 248 243 236; /* warm ivory 卡片底 */
--c-ink: 58 54 50; /* charcoal 主文字 */
--c-accent: 194 170 147; /* softened sand 品牌色 */
--c-danger: 175 90 80;
--c-success: 120 150 115;
/* ... */
/* 字号 / radius / shadow / 字体 */
--r-lg: 12px; --r-xl: 16px; --r-pill: 9999px;
--fs-body: 14px; --fs-label-xs: 11px;
--font-ui: "Noto Sans SC", ...;
}
html[data-theme="dark"] { /* 同 token 覆深色值 */ }
Layer 2 —— apps/web/styles/_atoms.css
apps/web/styles/_atoms.css/* 表面 */
.surface-card { background, border, radius, padding }
.surface-card--lg { ... bigger ... }
.surface-card--nested { ... 卡中卡 ... }
.surface-flat { 透明 wrapper }
.surface-chip { 圆形 chip / pill }
/* 文字 */
.text-primary .text-muted .text-accent
.text-success .text-danger .text-warning .text-info
/* 状态色背景(透明叠加)*/
.bg-success .bg-danger .bg-warning .bg-info
/* 按钮 */
.btn-ghost .btn-primary
/* Callout 变体(BEM)*/
.callout
.callout--risk
.callout--checklist
.callout--info
.callout--warning
.callout--success
.callout--debugtree
Layer 3 —— app-specific
Wiki 用 .wiki-prose(typography)+ 老 .wiki-article-card .wiki-panel-card
做 layout container,视觉为 transparent(2026-05-29 扁平化)。callouts 用
.callout + .callout--<variant> 而非自己定义。
Dashboard 用 .invest-cc 做容器 + .cc-panel / .cc-kpi / .cc-tag 做卡。
未来:cc-* 类逐步迁移到引用 surface-card / surface-chip(本 session 不动,
留迁移期)。
Layer 4 —— React atom 组件(待建)
apps/web/components/atoms/ 计划:
<Card variant?="lg|nested|flat"><Chip variant?="success|danger|warning|muted"><Button variant="ghost|primary" /><Callout variant="risk|checklist|info|warning|success">
JSX 用法:
import Card from '@shared/atoms/Card';
<Card variant="lg">…</Card>
Import 顺序(强制)
任何 app 入口 CSS 文件必须这个顺序 import:
/* 1. Token 必须最先 — 其他用 var() 引 */
@import "./_tokens.css";
/* 2. Primitive 用 token 定义 — 必须在业务样式前 */
@import "./_atoms.css";
/* 3. 业务样式(可 override primitive,但**只 override 不 redefine**)*/
.invest-cc { /* dashboard 容器 */ }
.wiki-prose { /* wiki typography */ }
主题(浅 / 深 / 霓虹)
- 真源:
_tokens.css的html[data-theme="light"|"dark"|"neon"]block - 切换:
document.documentElement.dataset.theme = '...',localStorage 持久化 - 状态栏:wiki ThemeToggle + dashboard DashboardShell.applyTheme 都用同套
STATUS_BARmap(light: #f2e9dc, dark: #1f1d1b, neon: #0a1124),通过<meta theme-color>同步 iOS / Android 顶栏。详见 memory [feedback_theme_color_dynamic_only]
防漂移规则(REVIEW 时必查)
- 新颜色不 hardcode ——
color: #98806a❌,color: rgb(var(--c-accent-dark))✓ - 新卡用 .surface-card —— 不要再写
border: 1px solid; border-radius: 12px;一遍 - 跨 app 样式必上 Layer 2 —— 只有 1 个 app 用的可留 Layer 3
- token 改了必跑
python3 scripts/automation/system_content_health.py确认 0 issue - lint
python3 scripts/lint/lint_pages.py跨色 chip / wiki-article-card 不要在 prose 里再嵌套 - 字号只用 8 级 grid —— 12/14/16/18/20/24/28/32(单源
_tokens.css)。新写 font-size 必落网格、 优先挂--fs-*;禁碎值(11.5/13.5/17/21)、禁 off-gridcalc(+1px)。 6b. hand-SVG 字号只用 4 级网格 —— 图内文字独立坐标系、不走 CSS token,收敛到 18=图标题 / 16=框内 / 11=框外 / 10=脚注·单位(2026-06-01 上抬,原 16/13/11/10)。 两种写法都算:font-size:内联/属性 +<style>内font:Npx简写;lint_pages.py的svg-font-scale(两正则)已强制。禁 8/9/12/14/15/17/22 碎值。 升号迁移经验(2026-06-01 全量 826 张 13→16/16→18):hand-SVG 框普遍有 padding 余量, +2/+3px 升号在 pilot+启发式榜首 7 张均无破版。mermaid 已于 2026-06-01 全部转 hand-SVG,wiki 不再有 mermaid 图;新图一律 hand-SVG。 6c. wiki md 正文阶梯 4 级 24/20/18/14(2026-05-31)——.prose.wiki-prose渲染域: H1=24 / H2=20 / H3·H4=18 / 正文=18(--fs-wiki-body,p·li·blockquote)/ code·meta=14。 原则:H 比正文大的保持大(H1·H2),≤正文的 H 就用正文字号(H3/H4=18),不发明碎档; H3/H4 与正文同号靠加粗+颜色分层。HARD:正文 ≤ 每一级标题、绝不大于标题(旧 bug 正文 20 > H2 18 倒挂已修)。 正文用 wiki-prose 专属 override,不动共享--fs-prose-body(srs 单独.prose仍正文 20 / H1 28,自成正常阶梯)。 - 手机端正文/列表零缩进 —— ≤768px 嵌套列表 padding 归零,层级靠 marker(· → ◦ → ▪)/ 颜色 / 标签, 不靠缩进推右(deep page 深嵌套手机不溢出);桌面可保留缩进。
- @media 政策 —— 连续属性(字号/间距/列宽)一律流式:
clamp()/auto-fit minmax()/ 横滚, 禁断点切换致拉伸突变;@media 只留真·布局模式切换(多列→单列 / 显隐 / 手机缩进)。 - 全局 token/reset 禁写 globals.css —— dashboard 不 import globals.css;凡全局 token /
<button>reset / 胶囊 chrome 放_tokens.css(L1)/_atoms.css(L2)。dashboard 组件 CSS 单源_dashboard.css(SPA dashboard.css + wiki globals.css 各 @import 一次)。
跨 app port 流程(产品角度)
未来要起第三个 app(比如手机原生 React Native / 公开版独立站):
- import
_tokens.css+_atoms.css(只动 path) - 视觉立刻 90% 对齐(token + primitive 全套)
- App-specific 排版只写 Layer 3 几十行
- React Native 不支持 CSS → 用
apps/web/styles/_tokens.json(未来从 _tokens.css 导出) - 加新 page 只用 Layer 4 atom 组件,不写 CSS
历史(怎么走到这步)
| 时间 | 事件 |
|---|---|
| 2026-05-28 早 | wiki / dashboard 各持一份 c-* token 镜像,改一处不同步 |
| 2026-05-28 中 | 抽 _tokens.css 单一真源,两边 @import |
| 2026-05-29 早 | wiki 卡片 mobile 仍有 2 层(article-card 包 prose),dashboard 1 层 |
| 2026-05-29 中 | .wiki-article-card 全屏扁平化(原 lg+ 已扁平),surface-card-sm/lg 全 opacity 对齐 dashboard cc-panel |
| 2026-05-29 晚 | 用户决策「最统一做法」→ 抽 _atoms.css Layer 2 primitive 层,建本 docs |
| 未来 | Layer 4 React atom 组件(<Card> <Chip> 等),旧 wiki/cc-* 类逐步迁移 |
链接
- 颜色真源:
apps/web/styles/_tokens.css - Primitive 真源:
apps/web/styles/_atoms.css - Wiki app 样式:
apps/web/styles/globals.css - Dashboard 组件层(单源,SPA+wiki 共用):
apps/web/styles/_dashboard.css - Dashboard app 外壳:
apps/invest-dashboard/src/dashboard.css - 相关记忆:feedback_theme_color_dynamic_only feedback_cssvar_force_resolve_for_jslib feedback_css_media_subset_trap feedback_style_reuse_first feedback_global_token_ssot