Files
ycode/design-system.md
T
xiaohan.yuan 3ceae1e983 chore(design-system): add extraction artifact and token drift gate
Record the design decisions actually in use and add a static gate that blocks new bare colors, bare sizes, important overrides, and wb token definitions outside token sources.
2026-10-18 18:36:43 +08:00

468 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# YCode 设计系统现状(Extract,2026-10-18)
> **本文件是现状快照,不是目标方案。** 只记录当前仓库里实际生效的 token、刻度、组件与约定,供后续 Build / Audit 逐条对照。
> 目标分层、兼容层边界与迁移顺序见 `docs/设计系统提取与统一方案-2026-10-18.md`(本文件第 6 节只做指向,不复制方案内容)。
> 采集范围:`src/renderer/src`(统计时排除第三方资产目录 `workbuddy/artifacts/recovered-pierre/`、`workbuddy/workbench/source-code-assets/`)与构建产物 `out/renderer/`。
> 采集方式:`rg` 文本检索 + 正则统计 + PowerShell 逐字节读取文件;未做浏览器运行时取值,未改动任何实现文件。
> 工作树快照说明:提取期间同批 P0 工作已落地 `scripts/check-design-tokens.mjs`、`scripts/design-token-baseline.json`(`npm run check:tokens`)并更新 `scripts/verify-ui.mjs`;本文件第 5.5 / 6 节按**当前工作树**(含这些未提交改动)记录。
## 0. 规模与测量基线
| 指标 | 实测值 | 说明 |
| --- | ---: | --- |
| CSS 文件 / TSX 文件 | 109 / 151 | `src/renderer/src` 全量,含恢复层 |
| CSS 行数 | 19,790 | 逐文件 `Get-Content` 行数求和 |
| `var(--yc-*)` 引用 | 1,372 | 与方案文档记录的 1,372 一致 |
| `var(--wb-*)` 引用 | 22,766 | 方案文档记录 22,756(本文件实测多 10 处) |
| `!important` | 926 | 方案文档记录 925(本文件实测多 1 处) |
| `tokens.css` 中 `--yc-*` 声明 | 271 | `:root` 229 + `html[data-theme='dark']` 18 + `.cb-font-size-fixed` 24 |
| `workbuddy/typography/tokens.css` 中 `--wb-*` 声明 | 115 | 唯一的根级 `--wb-*` 家族(排版/间距) |
| 原生控件 | `<button>` 362 / `<input>` 48 / `<textarea>` 8 / `<select>` 2 | TSX 内直接书写 |
| 内联 `<svg>` | 164(其中 69 个在 `*Icons.tsx` 模块内) | 图标模块共 25 个 |
| `wb-button` 类出现(TSX) | 247 次,分布在 18 个文件 | 变体计数见 3.1 |
| 本地 `className="btn…"` | 12 处 | 见 3.2 |
## 1. 权威来源:谁在根级生效,谁只是作用域闭包
### 1.1 根级生效的层
| 层 | 位置(选择器) | 内容 | 声明数 |
| --- | --- | --- | ---: |
| **YCode 权威 token** | `src/renderer/src/styles/tokens.css:17` `:root` | 调色板、语义色、间距/字号/行高/字重、控件尺寸、圆角、字体族、布局、描边、阴影、动效、字号档位 | 229 |
| 深色重映射 | `src/renderer/src/styles/tokens.css:352` `html[data-theme='dark']` | 只重映射 text/bg/border/气泡/阴影;未列出的沿用浅色 | 18 |
| **根级 WB 排版 token** | `src/renderer/src/workbuddy/typography/tokens.css:5` `:root` | `--wb-spacing-*`、`--wb-font-size-*`、`--wb-font-line-height-*`、`--wb-font-weight-*`、语义体例(body/caption/code/h1-h3/display/spec-*/chatflow-*)、`--wb-button-{height,font-size,line-height,icon-size}-*` | 115 |
| 固定字号边界重解析 | `src/renderer/src/styles/tokens.css` 末尾 `.cb-font-size-fixed, .cb-font-size-fixed *` | 在内层把 `--yc-text-*` 重新指回 `--wb-font-*`,避免全局字号档位重复叠加 | 24 |
依赖方向(实测):
- `--yc-space-1…10/12` 全部 `var(--wb-spacing-N)`;例外 `--yc-space-11: 56px` 是硬写(WB 无 `--wb-spacing-11`)。
- `--yc-font-size-1…11`、`--yc-font-weight-400/500/600/700`、大部分 `--yc-line-height-*` 均指向 `--wb-font-*`;例外 `--yc-line-height-6-2: 26px` 是硬写(WB 无该 token,见 5.3)。
- `--yc-font-mono: var(--wb-font-mono)` → `--wb-font-code-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`。
- `--yc-text-body/caption/code/h1/h2/h3/display-*` 全部 `var(--wb-font-*)` 别名,是 YCode 侧唯一一层"语义字号"入口。
### 1.2 `--wb-*`:除排版外全部是"按作用域复制的兼容闭包"
根级只定义了 115 个排版/间距 token;**颜色、圆角、控件尺寸、按钮/输入/弹窗等 `--wb-*` 在根上没有定义**,而是各页面/组件在自己的 subtree 里整份复制。实测 `--wb-palette-brand-8:` 在 13 个 CSS 文件里被重复声明:
| 作用域(已逐行核验) | 文件:行 |
| --- | --- |
| `.yc-capability-center` | `src/renderer/src/capabilities/capability-center-source.css:2` |
| `.models-settings-panel` | `src/renderer/src/components/model-settings.css:146` |
| `.source-home` | `src/renderer/src/components/source-home-recovered.css:2` |
| `.source-workspace-picker` | `src/renderer/src/components/source-workspace-picker-recovered.css:2` |
| `.chat-pane.cr-theme` | `src/renderer/src/workbuddy/conversation/source-styles.css:7` |
| (其余 8 个文件同族复制) | `components/settings-shell-source.css`、`components/workspace-source.css`、`components/source-general-settings-recovered.css`、`components/source-settings-navigation-recovered.css`、`components/source-select/source-select-recovered.css`、`projects/source-project-controls.css`、`workbuddy/composer/add-menu/source.css`、`workbuddy/composer/model-selector/source.css`、`workbuddy/subagents/theme.css` |
闭包缺失的直接后果(可复现):
- `--wb-size-control-sm/ms/md/lg/xl/2xl`、`--wb-icon-size-sm/ms/md/lg/xl` 只在这些作用域内定义(例:`capability-center-source.css:8`、`model-settings.css:146`、`workbuddy/conversation/source-styles.css:7`),根上没有。
- 因此排版 token 里的 `--wb-button-height-small: var(--wb-size-control-sm)`、`--wb-button-icon-size-medium: var(--wb-icon-size-md)` 等,只有在某个闭包作用域内才会解析成功;出作用域即失效。
- `--wb-font-line-height-9`、`--wb-font-line-height-6-2` 被 7 个 CSS 文件引用(`var(--wb-font-line-height-9)`、`var(--wb-font-line-height-6-2)`),但**全仓库没有任何定义**;`--wb-font-spec-h2-line-height`、`--wb-font-spec-h5-line-height` 同样指向未定义项。
恢复层命名家族(用于判断"这段 CSS 来自哪里"):
| 前缀 / 形态 | 含义 | 唯一选择器数(实测) |
| --- | --- | ---: |
| `cr-*` | 会话渲染恢复层(chat renderer) | 591 |
| `cb-*` | 原版通用组件层(button/checkbox/input/…) | 204 |
| `ec-*` | 能力中心/专家中心恢复层 | 227 |
| `sm-*` | 本地技能/市场页面 | 274 |
| `dc-*` | 抽屉/面板少量恢复规则 | 6 |
| `_name_hash_index` | 原版 CSS Module 哈希类名(如 `._about_385qb_250`、`._dialogOverlay_peiew_7`、`._icon_vnue1_21`) | 大量 |
### 1.3 CSS 加载顺序与冲突点
声明的顺序(源码为准):
| 入口 | 顺序 |
| --- | --- |
| `src/renderer/src/main.tsx:5-10` | `workbuddy/typography/tokens.css` → `styles/tokens.css` → `styles/app.css` → `styles/sidebar.css` → `workbuddy/conversation/source-styles.css` → `workbuddy/conversation/source-adapters.css` |
| `src/renderer/src/settings.tsx:4-6` | `workbuddy/typography/tokens.css` → `styles/tokens.css` → `styles/app.css` → `styles/settings-entry.css` |
组件级追加(在入口之后由组件模块自带,顺序受模块求值影响):
| 文件:行 | 导入 |
| --- | --- |
| `src/renderer/src/App.tsx:19-21` | `panel-motion-source.css`、`drawer-motion-source.css`、`panel-layout-adapters.css` |
| `src/renderer/src/components/Sidebar.tsx:34-35` | `workspace-source.css`、`sidebar-shell-source.css` |
| `src/renderer/src/components/SettingsDialog.tsx:7-11` | `source-select/source-select-recovered.css`、`source-select/source-select.css`、`source-general-settings.css`、`settings-shell-source.css`、`../styles/settings-entry.css` |
| `src/renderer/src/components/ChatPane.tsx:8` | `workbuddy/conversation/search-highlight-adapters.css` |
| `src/renderer/src/capabilities/CapabilityCenter.tsx:9` | `capability-center-source.css` |
| `src/renderer/src/components/SourceHome.tsx:7` | `source-home.css`(其第 1 行 `@import './source-home-recovered.css'`) |
| `src/renderer/src/components/ModelSettingsPanel.tsx:9-10` | `model-settings.css`、`custom-model-settings.css` |
| `src/renderer/src/projects/ProjectListPage.tsx:11-13` | `source-project-controls.css`、`source-projects-recovered.css`、`project-layout.css` |
构建产物实测(`out/renderer/`,与"声明顺序"并不一致):
- `out/renderer/index.html` 只挂 2 个样式表,且顺序为 `app-h0tta3aw.css` → `index-C92zurN-.css`。
- `app-h0tta3aw.css` 的**第一条规则**是恢复层 `.source-select-host{--wb-palette-…}`,来自 `SettingsDialog.tsx` 的导入;`--yc-*` 根块出现在约 178.6 KB 处,晚于 `.settings-modal-overlay`(约 152.5 KB)。
- `styles/sidebar.css`(`.sidebar__brand-block` 约 2.87 MB)与 `.chat-pane.cr-theme`(约 2.89 MB)落在第二个样式表 `index-C92zurN-.css` 里。
冲突点清单:
1. 声明顺序 ≠ 生效顺序:`main.tsx` 的 `import App` / `import { SettingsWindow }` 写在样式导入之前,打包后组件自带 CSS 先于入口样式落地。
2. 同特异性并列时由后加载者获胜(本地 `.btn` 与恢复 `wb-button` 在同一元素上并用时需要显式顺序,`styles/app.css` 与 `sidebar-shell-source.css` 都定义过按钮外观)。
3. 作用域闭包不可迁移:把元素移出 `.source-home` / `.models-settings-panel` / `.chat-pane.cr-theme` 等宿主后,`--wb-*` 立即失配。
4. 深色主题按作用域各写一遍:`html[data-theme='dark'] …scope…` 与组件自带的 `.dark/.vscode-dark` 兼容分支同时存在,优先级取决于加载顺序。
### 1.4 `--yc-*` 也不是严格单源
| 位置 | 重新声明的变量 | 原因(文件内注释) |
| --- | --- | --- |
| `src/renderer/src/styles/sidebar.css:14-15` `.sidebar` | `--yc-font-sans`、`--yc-text-primary` | 侧栏保留原版 shell 回退栈 |
| `src/renderer/src/styles/sidebar.css:29-36` `html[data-theme='dark'] .sidebar` | `--yc-bg-secondary`、`--yc-bg-hover`、`--yc-bg-active`、`--yc-text-*`、`--yc-border-tertiary` | 暗色侧栏用 `#1f1f1f` 而非全局 `#171717` |
| `src/renderer/src/styles/sidebar.css:708-710` `.notif-panel` | `--yc-notif-bg/-border/-title` | 通知面板局部 token |
| `src/renderer/src/components/task-menu.css:21-26,41-46` `.conversation-context-menu` | `--yc-task-menu-*` | Portal 不在 `.chat-pane.cr-theme` 内,显式给同值 |
| `src/renderer/src/projects/project-menu.css:3-6,21-24` `.yc-project-more` | `--yc-project-menu-*` | Portal 不继承侧栏 token |
| `src/renderer/src/App.tsx:396`(内联 style) | `--yc-layout-main` | 运行时计算主列宽度;由 `workbuddy/workbench/panel-layout-adapters.css:2` 消费 |
## 2. 实际生效的 scales(只列组件真正在用的步骤)
计数列 = 该 token 在 `src/renderer/src`(CSS/TSX/TS)中的出现次数,**含 `tokens.css` 自身的别名定义**,用于说明"这一步确实被消费"。
### 2.1 颜色:中性阶(来源 `styles/tokens.css:19-36`)
| Token | 值 | 计数 |
| --- | --- | ---: |
| `--yc-black-100` | `#000000` | 5 |
| `--yc-black-70 / -50 / -30 / -20 / -15 / -10` | `rgba(0,0,0,.7/.5/.3/.2/.15/.1)` | 各 1–2 |
| `--yc-white-100` | `#ffffff` | 9 |
| `--yc-gray-1` | `#fafafa` | 2 |
| `--yc-gray-2` | `#f7f7f7` | 2 |
| `--yc-gray-3` | `#f2f2f2` | 2 |
| `--yc-gray-4` | `#ebebeb` | 2 |
| `--yc-gray-5` | `#e6e6e6` | 3 |
| `--yc-gray-6` | `#dedede` | 2 |
### 2.2 品牌与状态色
| Token | 浅色值 | 深色处理 | 计数 |
| --- | --- | --- | ---: |
| `--yc-brand-8` | `#00c29a` | 不重映射(恢复层深色用 `#4cf0ce`) | 13 |
| `--yc-brand-soft` | `#dff7f2` | 不重映射 | 1 |
| `--yc-green-8` | `#0cbf5b` | 不重映射 | 1 |
| `--yc-orange-8` | `#ff7800` | 不重映射 | 1 |
| `--yc-red-8` | `#f64041` | 不重映射 | 3 |
| `--yc-blue-8` | `#3370ff` | 不重映射 | 2 |
| `--yc-status-success / warning / error / info` | 即 green/orange/red/blue-8 别名 | 同左 | 9 / 7 / 29 / 5 |
恢复层同一时刻的 palette 值(`capability-center-source.css:2` 与其 dark 分支):`--wb-palette-brand-8` 浅色 `#00c29a`、深色 `#4cf0ce`;`gray-3/4/5` 浅色 `#f2f2f2/#ebebeb/#e6e6e6`、深色 `#1f1f1f/#242424/#3a3a3a`。
### 2.3 语义色(浅色 → 深色)
| Token | 浅色 | 深色(`html[data-theme='dark']`) | 计数 |
| --- | --- | --- | ---: |
| `--yc-text-primary` | `rgba(0,0,0,.9)` | `rgba(255,255,255,.9)` | 99 |
| `--yc-text-secondary` | `rgba(0,0,0,.7)` | `rgba(255,255,255,.7)` | 80 |
| `--yc-text-tertiary` | `rgba(0,0,0,.5)` | `rgba(255,255,255,.5)` | 74 |
| `--yc-text-disabled` | `rgba(0,0,0,.3)` | `rgba(255,255,255,.3)` | 3 |
| `--yc-text-inverse` | `#ffffff` | `#1f1f1f` | 2 |
| `--yc-bg-primary` | `#ffffff` | `#1f1f1f` | 56 |
| `--yc-bg-secondary` | `#f7f7f7` | `#171717` | 27 |
| `--yc-bg-tertiary` | `#f2f2f2` | `#242424` | 8 |
| `--yc-bg-hover` | `#ebebeb` | `#2a2a2a` | 39 |
| `--yc-bg-active` | `#e6e6e6` | `#333333` | 6 |
| `--yc-bg-scrim` | `rgba(0,0,0,.35)` | `rgba(0,0,0,.6)` | 2 |
| `--yc-border-primary` | `#e6e6e6` | `#333333` | 46 |
| `--yc-border-secondary` | `#ebebeb` | `#2a2a2a` | 5 |
| `--yc-border-tertiary` | `#f2f2f2` | `#242424` | 4 |
| `--yc-border-strong` | `#dedede` | `#3d3d3d` | 3 |
| `--yc-bubble-user-bg` | `#f2f2f2` | `#2f2f2f` | 2 |
### 2.4 间距阶(`--yc-space-*` = `--wb-spacing-*`)
| 步骤 | 值 | 计数 | 步骤 | 值 | 计数 |
| --- | ---: | ---: | --- | ---: | ---: |
| `space-1` | 2px | 24 | `space-7` | 24px | 5 |
| `space-2` | 4px | 41 | `space-8` | 32px | 2 |
| `space-3` | 8px | 60 | `space-9` | 40px | 7 |
| `space-4` | 12px | 44 | `space-10` | 48px | 2 |
| `space-5` | 16px | 22 | `space-11` | 56px(硬写) | 1 |
| `space-6` | 20px | 14 | `space-12` | 64px | 8 |
恢复层同时高频使用 `--wb-spacing-*` 本体(`-1` 282、`-2` 354、`-3` 508、`-4` 313、`-5` 288、`-6` 99、`-7` 90、`-8` 73、`-9` 26、`-10` 45、`-12` 46,另有 `-0` 15、`-2-5` 53)。
### 2.5 字号 / 行高 / 字重
字号阶(`--yc-font-size-N`,计数含定义):
| N | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| px | 8 | 10 | 12 | 13 | 14 | 16 | 18 | 20 | 24 | 28 | 32 |
| 计数 | 1 | 10 | 23 | 10 | 15 | 4 | 9 | 2 | 1 | 1 | 1 |
行高阶(`--yc-line-height-*`):`4:16`、`4-2:18`、`5:20`、`5-2:22`、`6:24`、`6-2:26`(硬写)、`7:28`、`8:32`、`10:40`。
字重:`400 / 500 / 600 / 700`。
语义体例(`--yc-text-*` → `--wb-font-*`,size/line-height/weight):
| 体例 | 值 | 计数(size) |
| --- | --- | ---: |
| body | 14 / 22 / 400 | 21 |
| body-strong | 14 / 22 / 600 | 3 |
| caption | 12 / 18 / 400 | 36 |
| code | 13 / 20 / 400 | 3 |
| h1 | 24 / 32 / 600 | 1 |
| h2 | 20 / 28 / 600 | 2 |
| h3 | 16 / 24 / 600 | 2 |
| display | 32 / 40 / 700 | 1 |
对话流(chatflow,独立一套,默认 offset=0,实际值 = `calc(基准 + var(--yc-font-offset) × 倍率)`):h1 21/37、h2 19/33、h3 17/30、h4 15/26、p1 15/26、p2 13/23、p3 11/19。
Markdown 正文:根字号 `--yc-md-root: 17.143px`、行高 `1.75`、段落 `0.875em`、行内代码 `12.857px / 22.5px`。
字体族:`--yc-font-sans: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif`;`--yc-font-mono` 继承 `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`。
全局字号档位(`src/renderer/src/fontSize.ts` + `tokens.css` 末尾):
| 档 | mdRoot | offset |
| ---: | ---: | ---: |
| 1 | 16px | -1 |
| 2(默认) | 17.143px | 0 |
| 3 | 18.286px | +1 |
| 4 | 20.571px | +2 |
| 5 | 22.857px | +3(仅正文放大) |
| 6 | 26.286px | +4(仅正文放大) |
`--yc-font-offset-global` 由 JS 写入,控件侧统一夹取 `--yc-font-offset: clamp(-1, var(--yc-font-offset-global), 2)`。
### 2.6 控件尺寸阶
| Token | 值 | 计数 | | Token | 值 | 计数 |
| --- | ---: | ---: | --- | --- | ---: | ---: |
| `--yc-size-3` | 12px | 3 | | `--yc-size-10` | 40px | 4 |
| `--yc-size-3-2` | 14px | 5 | | `--yc-size-11` | 44px | 1 |
| `--yc-size-4` | 16px | 9 | | `--yc-size-12` | 48px | 2 |
| `--yc-size-5` | 20px | 5 | | `--yc-size-13` | 52px | 1 |
| `--yc-size-6` | 24px | 7 | | `--yc-size-14` | 56px | 2 |
| `--yc-size-7` | 28px | 11 | | `--yc-size-17` | 68px | 1 |
| `--yc-size-8` | 32px | 2 | | `--yc-size-9` | 36px | 1 |
语义控件高度:`--yc-control-sm:24`、`ms:28`、`md:32`、`lg:40`、`xl:48`、`2xl:56`;实际消费 `control-md` 18 次、`control-xl` 3 次、`control-2xl` 2 次、`control-ms` 2 次、`control-sm/lg` 各 1 次。
### 2.7 圆角阶
| Token | 值 | 计数 | Token | 值 | 计数 |
| --- | ---: | ---: | --- | ---: | ---: |
| `--yc-radius-none` | 0 | 1 | `--yc-radius-xl` | 12px | 7 |
| `--yc-radius-xs` | 2px | 4 | `--yc-radius-2xl` | 16px | 6 |
| `--yc-radius-sm` | 4px | 8 | `--yc-radius-3xl` | 20px | 1 |
| `--yc-radius-md` | 6px | 16 | `--yc-radius-4xl` | 24px | 2 |
| `--yc-radius-lg` | 8px | 29 | `--yc-radius-full` | 9999px | 16 |
| 语义:`--yc-radius-bubble` | 16px | 3 | `--yc-radius-input` | 24px | 2 |
恢复层圆角集合与之一致(`capability-center-source.css` 实测出现 0/2/4/6/8/12/16/20/24/9999px)。
### 2.8 阴影
| Token | 浅色值 | 深色值 | 计数 |
| --- | --- | --- | ---: |
| `--yc-shadow-input` | `rgba(0,0,0,.03) 0 16px 32px -8px, rgba(0,0,0,.06) 0 2px 4px -4px` | `0 1px 2px rgba(0,0,0,.3), 0 4px 12px rgba(0,0,0,.35)` | 3 |
| `--yc-shadow-popover` | `0 4px 16px rgba(0,0,0,.1)` | 不重映射 | 1 |
| `--yc-shadow-dialog` | `0 12px 32px rgba(0,0,0,.16)` | `0 12px 32px rgba(0,0,0,.5)` | 1 |
### 2.9 动效
| Token | 值 | 计数 |
| --- | --- | ---: |
| `--yc-motion-fast` | `0.1s` | 3 |
| `--yc-motion-medium` | `0.15s` | 1 |
| `--yc-motion-slow` | `0.2s` | 1 |
| `--yc-motion-easing` | `cubic-bezier(0.4, 0, 0.2, 1)` | 1 |
恢复层使用自己的时长/缓动闭包(实测出现值):时长 `.1s / .15s / .2s / .3s / .4s`,缓动 `cubic-bezier(.2,0,0,1)`、`cubic-bezier(.4,0,.2,1)`、`cubic-bezier(.4,0,1,1)`、`cubic-bezier(0,0,.2,1)`、`linear`。
### 2.10 布局常量
| Token | 值 | 计数 | 备注(来源文件内实测说明) |
| --- | ---: | ---: | --- |
| `--yc-layout-sidebar-expanded` | 280px | 2 | 实测 @1334 窗口;@1276 实测为 240px,宽度本身可变 |
| `--yc-layout-sidebar` | = expanded | 5 | 当前展开默认 |
| `--yc-sidebar-rail-width` | 44px | 1 | 收起后的窄轨 |
| `--yc-layout-right` | 647px | 4 | 详情面板实测宽 |
| `--yc-layout-right-min` | 320px | 1 | 最小宽 |
| `--yc-content-max` | 832px | 4 | `.cr-message-list__content` |
| `--yc-content-inline-pad` | 40px | 1 | `--yc-space-9` |
| `--yc-input-max` | 784px | 6 | `.cr-input-box` |
| `--yc-titlebar-height` | 30px | 6 | 顶部条带 |
| `--yc-titlebar-leading` | 92px | 3 | 左侧操作区 |
| `--yc-window-control-width` | 46px | 2 | 单钮宽 |
| `--yc-titlebar-menu-min-width` | 200px | 2 | 菜单最小宽 |
| `--yc-window-control-icon` | 10px | 3 | 窗口控制图标 |
| `--yc-dialog-width / -narrow-width` | 560px / 420px | 1 / 1 | 对话框 |
### 2.11 实测一次性常量(非标准阶,具名后组件不写裸像素)
选取后续组件最常复用的一组(全部定义在 `styles/tokens.css`「实测常量」段):
| Token | 值 | Token | 值 |
| --- | ---: | --- | ---: |
| `--yc-scrollbar-size` | 6px | `--yc-input-min-height` | 96px |
| `--yc-scrollbar-thumb-alpha` | 0.2 | `--yc-input-editor-min-height` | 64px |
| `--yc-resizer-hit` | 6px | `--yc-input-max-height` | 200px |
| `--yc-sidebar-item-height` | 31px | `--yc-input-box-white-height` | 144px |
| `--yc-sidebar-section-label-height` | 30px | `--yc-input-editor-home` | 74px |
| `--yc-sidebar-section-head-height` | 34px | `--yc-input-footer-row` | 40px |
| `--yc-sidebar-tab-height` | 32px | `--yc-prompt-row-height` | 38px |
| `--yc-sidebar-footer-height` | 57px | `--yc-prompt-row-step` | 50px |
| `--yc-discover-height` | 28px | `--yc-msg-header-height` | 24.5px |
| `--yc-user-menu-height` | 40px | `--yc-bubble-max-height` | 310px |
| `--yc-user-avatar-size` | 28px | `--yc-tool-body-max-height` | 320px |
| `--yc-icon-btn-sm / -md` | 24px / 32px | `--yc-panel-tab-min-width / -max-width` | 80px / 240px |
| `--yc-badge-size / -offset` | 14px / 2px | `--yc-home-content-width` | 800px |
| `--yc-segmented-height` | 32px | `--yc-home-quick-actions-width` | 680px |
| `--yc-segmented-item-width` | 72px | `--yc-home-title-size / -line-height` | 30px / 42px |
| `--yc-dialog-width` | 560px | `--yc-empty-desc-max-width` | 324px |
| `--yc-line-height-19 / -21 / -245 / -2625` | 19 / 21 / 24.5 / 26.25px | `--yc-letter-spacing-badge` | 0.2px |
## 3. 组件清单
层级标记:**[Y]** = YCode 自有实现;**[R]** = REA 恢复组件(生成物,勿手改);**[L]** = 本地旧类/一次性实现(迁移目标见第 6 节)。
### 3.1 可复用组件矩阵
| 组件 | 代码 path | 类名 / 变体 | 层级 | 备注(实测) |
| --- | --- | --- | --- | --- |
| Button / IconButton | `src/renderer/src/components/task-confirm-dialog.tsx`、`components/SourceChatHeader.tsx`、`components/ArchivedTasksDialog.tsx`、`workbuddy/user-menu/AccountMenu.tsx`、`projects/ProjectDetailPage.tsx`、`capabilities/*Page.tsx` | `wb-button` + `--primary(16) / --secondary(23) / --grey(未用) / --ghost(13) / --link(3) / --danger(4) / --icon(9) / --circle(5) / --loading(2) / --disabled(2) / --full(1)`;尺寸 `--small(14) / --medium(41) / --xsmall(1)`;内部 `wb-button__content(24)`、`wb-button__icon(29)` | [R] 样式(各 scope 闭包) + [Y] 调用点 | 共 247 次类名出现 / 18 个 TSX 文件;`<button>` 原生 362 个 |
| IconButton(本地) | `src/renderer/src/styles/app.css:934-949`、`components/Sidebar.tsx:346`、`components/NotificationsPanel.tsx:148` | `.btn-icon` | [L] | 与 `wb-button--icon/circle` 并存的第三套图标按钮 |
| Button(本地) | `src/renderer/src/styles/app.css:949-981` | `.btn`、`.btn--primary`、`.btn--ghost` | [L] | 12 处 TSX 使用:`components/AboutDialog.tsx:50/53`、`components/ChatPane.tsx:499-526`、`components/SettingsDialog.tsx:80` |
| Button(页面级) | `src/renderer/src/automations/automation-page.css` | `.automation-button`、`--primary / --secondary / --danger` | [L] | 自动化页专用 |
| Input / Textarea | `components/ModelSettingsPanel.tsx`、`components/EditableModelSelect.tsx`、`components/WorkspaceDialog.tsx`、`components/SourceWorkspacePicker.tsx`、`capabilities/ExpertsPage.tsx`、`projects/ProjectListPage.tsx` | `wb-input`、`wb-input-wrapper`、`wb-input__inner / __prefix / __suffix / __clear / __icon-button / __count / __tips`、`wb-input--filled / --status-error / --with-affix`、`wb-input-wrapper--small/medium/filled/disabled`、`wb-input-group__addon`;文本域 `wb-textarea` | [R] 样式 + [Y] 调用点 | `<input>` 48、`<textarea>` 8 |
| Textarea(本地) | `projects/ProjectInstructionDrawer.tsx:25`、`capabilities/ConnectorsPage.tsx:25`、`components/MemorySettingsPanel.tsx:293/472`、`components/PersonalizationSettingsPanel.tsx:336` | `.project-instruction-drawer__textarea`、`.mcp-config-textarea`、`.memory-settings-panel__manage-editor`、`.local-memory-editor` | [L] | 四套局部文本域样式 |
| Select | `components/source-select/SourceSelect.tsx`(宿主,渲染 `<span class="source-select-host">`)、`components/source-select/RecoveredSelectCore.tsx`、`components/source-select/SourceSelectPopover.tsx` | `wb-select__panel / __list / __option / __option--selected / __option--single-selected / __option-label / __empty`、`wb-select-popover`;宿主 props:`size: small/medium/large`、`shape`、`placement`、`showSearch`、`allowClear`、`portalRoot` | [R] 核心 + [Y] 包装 | 另有 `components/EditableModelSelect.tsx`、`components/SourceModelPicker.tsx`(`.source-model-picker`) |
| Select(原生) | `src/renderer/src/automations/AutomationRecords.tsx:100,112` | `<select>` | [L] | 全仓库仅 2 处 |
| Dialog | `components/task-confirm-dialog.tsx` + `components/task-confirm-dialog.css`、`components/ArchivedTasksDialog.tsx` + `.css`、`components/WorkspaceDialog.tsx` + `components/workspace-source.css`、`components/SettingsDialog.tsx` + `components/settings-shell-source.css` | `wb-modal`、`wb-modal__overlay / __overlay--center / __header / __header-row / __title / __title-wrap / __body / __footer / __footer--right / __footer-actions / __close`、`wb-modal-anim-open`;设置页用 `.settings-modal`、`.settings-modal-overlay` | [R] | 另有 `components/AboutDialog.tsx`(本地 `.dialog`)、`workbuddy/composer/permission/SourcePermissionControl.tsx`(确认弹窗) |
| Popover / Menu | `components/AppDiscoverPopover.tsx` + `components/app-discover-popover.css`、`workbuddy/user-menu/AccountMenu.tsx` + `account-menu-source.css`、`components/task-menu.tsx` + `task-menu.css`、`projects/ProjectMenu.tsx` + `project-menu.css`、`components/source-select/SourceSelectPopover.tsx` | `wb-popover`、`wb-popover--placement-top`、`wb-dropdown`、`wb-dropdown__item / __list / __label / __check / __icon / __search / __scroll / __footer`、`wb-dropdown--single / --scrollable`;YCode 侧 `.yc-project-more`、`.conversation-context-menu` | [R]+[Y] | 侧栏菜单在 `.chat-pane.cr-theme` 之外,`task-menu.css` 显式给出等价 token |
| Tabs / Segmented | `components/SourceSettingsNavigation.tsx` + `components/settings-shell-source.css`(`.settings-navigation__item` 等)、`components/Sidebar.tsx:369-415` + `styles/sidebar.css`(`.conversation-list-tab-button`)、`components/SourceHome.tsx`(`.wb-scene-tabs`,样式在 `source-home-recovered.css`)、`capabilities/ExpertsPage.tsx` | Segmented:`wb-segmented`、`wb-segmented__item / __item--active / __item-label / __thumb / __thumb--measured`;Tabs:`conversation-list-tab-button`、`wb-scene-tabs__pill` | [R] 样式 + [Y] 容器 | 无 `wb-tabs` 类(全仓库 0 次);Segmented 尺寸 token 见 2.11 |
| Checkbox | `components/source-select/RecoveredSelectCore.tsx`、`components/ModelSettingsPanel.tsx`、`workbuddy/composer/permission/SourcePermissionControl.tsx` | `wb-checkbox`、`__box / __control / __former / __icon / __input / __label`、`--checked / --disabled / --indeterminate / --readonly` | [R] | 样式闭包在 `model-settings.css`、`source-select-recovered.css`、`source-permission-recovered.css` |
| Switch | `components/GeneralSettingsPanel.tsx`、`components/MemorySettingsPanel.tsx`、`components/PersonalizationSettingsPanel.tsx`、`workbuddy/composer/permission/SourcePermissionControl.tsx`、`capabilities/SkillsPage.tsx` | `wb-switch`、`__track / __thumb / __input`、`--small / --large / --danger` | [R] | 主要样式与主题化在 `components/settings-shell-source.css` |
| Card | `components/ModelSettingsPanel.tsx`(`.models-settings-panel__card`,`model-settings.css:6`)、`components/AppearanceSettingsPanel.tsx`(`.appearance-card`,`source-appearance-panel-recovered.css`)、`components/Sidebar.tsx`(`.conversation-list-invite-friends__card`,`sidebar-shell-source.css`)、`components/ToolCard.tsx`(`.tool-card*`,`styles/app.css:425+`)、`workbuddy/conversation/MessageQuoteCard.tsx`(`.cr-input-quote-card*`,`message-quote-source.css`)、`capabilities/ExpertsPage.tsx`(`.expert-card`,`expert-source.css`) | 无统一 Card 组件;无 `wb-card` 类(0 次) | 混合 | 6 套独立卡片样式 |
| ListItem / NavItem | `components/SourceWorkspacePicker.tsx`(`wb-dropdown__item`)、`components/SourceSettingsNavigation.tsx`(`.settings-navigation__item`)、`components/Sidebar.tsx`(`.sidebar__item*`、`.conversation-item`,`styles/sidebar.css` + `components/workspace-source.css`)、`capabilities/SkillsPage.tsx`(`wb-dropdown__item`) | `wb-dropdown__item--selected / --empty`、`.settings-navigation__item--active`、`.sidebar__item--menu-open` | [R]+[Y] | 侧栏列表项几何:31px 高、`padding 5px 12px`(`tokens.css` 注释实测) |
| Badge / Tag | 使用点:`components/Sidebar.tsx:369/415/596`(`.sidebar__version-badge`、`.conversation-list-version-badge`、`.sidebar__tab-beta`、`.msg-center-badge`)、`capabilities/ConnectorsPage.tsx:84`(`.mcp-installed-badge`)、`projects/ProjectDetailPage.tsx:527`(`.task-item__source-badge`)、`components/AppearanceSettingsPanel.tsx:41`(`.appearance-badge--validity`)、`components/ModelSettingsPanel.tsx:224`(`models-settings-panel__connection-failed-badge`) | 无统一 Badge;`wb-tag` 仅在 `capabilities/expert-source.css`、`components/workspace-source.css` 有样式,TSX 无使用 | 混合 | `styles/app.css:1417-1443` 还有无双基 `.badge / .badge--ok / .badge--warn`,TSX 未使用 |
| EmptyState | `capabilities/ExpertsPage.tsx`(`.capability-expert-empty`,`expert-source.css`;插图 `capabilities/assets/empty-created-expert.svg`)、`components/Sidebar.tsx`(`.conversation-list-empty`、`.sidebar__empty`,`sidebar-shell-source.css` / `sidebar.css`)、`automations/AutomationPage.tsx`(`.automation-empty-state`)、`library/LibraryPage.tsx`(经 `library.css` `.library-feed-empty`、`.library-local-empty`) | 每页各写一套;恢复层另有 `colleague-chat-empty-profile`(`styles/tokens.css` 中记录其 gap/尺寸实测) | 混合 | 无 `wb-empty` 类(0 次) |
| Avatar | `components/SourceAgentAvatar.tsx`(REA 生成的固定 SVG,ev_d6e6920f…)、`workbuddy/user-menu/AccountMenu.tsx`(用户头像,28px,`--yc-user-avatar-size`)、`components/MessageBubble.tsx`(`.assistant-avatar`,`workbuddy/conversation/source-styles.css`)、`workbuddy/subagents/*`(`.yc-member-avatar`,`subagents/adapters.css`) | `.wb-avatar` 样式仅在 `projects/source-project-detail-recovered.css` 与 `styles/tokens.css` 注释中出现;无 `wb-avatar` JSX 使用 | 混合 | `.avatar*`/`avatar-item` 等类名还散落在若干页面 |
| Spinner | `components/ArchivedTasksDialog.tsx`(`.archived-tasks-spin`)、`automations/AutomationPage.tsx`(`.automation-running-spinner`)、`workbuddy/artifacts/ArtifactContentRenderer.tsx`、`workbuddy/mermaid/MermaidBlock.tsx`(`.loading-spinner`)、`workbuddy/conversation/MessageEditorIcons.tsx`(`.cr-input-spin`)、`workbuddy/subagents/*`(`.yc-member-spinner`) | 关键帧:`wb-icon-spin`(`components/source-select/source-select-recovered.css`);无 `wb-spinner` 类 | 混合 | 各模块自带旋转样式 |
| Skeleton | `library/LibraryPageParity.tsx`(`.library-skeleton`、`.library-feed-skeleton`、`.library-local-skeleton`,`library/library.css`)、`components/sidebar-shell-source.css`(`.conversation-list-skeleton`)、`capabilities/connectors-source.css`(`.connector-skeleton*`)、`components/settings-panel-loader.tsx` + `styles/settings-entry.css`(`.settings-panel-loading`) | 无 `wb-skeleton` 类 | [Y]+[R] | 4 套骨架模式 |
| Tooltip | `components/source-select/RecoveredSelectTooltip.tsx`、`workbuddy/composer/context-info/ComposerContextInfo.tsx:189`(`wb-tooltip wb-tooltip--placement-top wb-tooltip--fade-open`、`wb-tooltip__content / __arrow`)、`workbuddy/conversation/UserMessageEditor.tsx:20`(选择器白名单引用 `.wb-tooltip`) | `wb-tooltip--placement-* / --interactive / --no-padding / --fade-*`;token:`--wb-tooltip-z-index:1070`(运行时兜底) | [R] | 样式闭包在 `sidebar-shell-source.css`、`source-select-recovered.css`、`composer/context-info/source.css`、`composer/model-selector/source.css`、`conversation/question-source.css` |
| Toast / Notice | `components/ModelSettingsPanel.tsx:219`(`.model-ui-toast`,`model-settings.css:406`,fixed 顶部居中、z-index 1200)、`capabilities/SkillsPage.tsx:107`(`.yc-skill-notice` / `.yc-skill-error`,`skills-host.css`)、`workbuddy/subagents/SubagentDetailPanel.tsx:72-75` 与 `components/RightSidebar.tsx:32`(`.yc-member-notice`,`subagents/adapters.css`)、`workbuddy/message-actions/MessageActionToolbar.tsx`(`.wb-message-actions__pending / __error`) | 无统一 Toast;恢复层只保留 `--wb-message-*` token(`capability-center-source.css` 闭包内),无 JSX 宿主 | 混合 | `styles/app.css:1448-1462` 的 `.notice`(含 dark 规则)在 TSX 中查无使用 |
### 3.2 有样式、无 JSX / 已废弃的入口
| 项 | 位置 | 现状 |
| --- | --- | --- |
| `.notice` | `styles/app.css:1448`、`:1458`(dark) | TSX 无 `className="notice"` |
| `.badge / .badge--ok / .badge--warn` | `styles/app.css:1417-1443` | TSX 无使用 |
| `wb-tag` | `capabilities/expert-source.css`、`components/workspace-source.css` | 只有恢复样式,无 TSX 宿主 |
| `--wb-message-*`(Toast/Message 组件 token) | `capabilities/capability-center-source.css` | 只有 token 闭包,无组件宿主 |
| `.input / .input--mono`、`.dialog / .dialog__actions`、`.menu-dropdown*` | `styles/app.css` | 本地旧类;`.dialog` 由 `components/AboutDialog.tsx`、`components/ChatPane.tsx` 使用,`.menu-dropdown*` 由 `components/TitleBar.tsx` 使用 |
### 3.3 图标与原生控件现状
- 图标模块 25 个(`components/icons.tsx`、`components/icons-extra.tsx`、`components/general-settings-icons.tsx`、`components/task-menu-icons.tsx`、`components/SourceChatHeaderIcons.tsx`、`components/source-select/SourceSelectIcons.tsx`、`capabilities/{ConnectorSourceIcons,SkillSourceIcons}.tsx`、`library/{LibraryIcons,SourceLibraryIcons,SourceLibraryChromeIcons}.tsx`、`automations/automation-source-icons.tsx`、`projects/ProjectIcon.tsx`、`workbuddy/**/{*Icons,icons,account-menu-icons}.tsx`)。
- 内联 `<svg>` 164 个,其中仅 69 个位于 `*Icons.tsx`,其余内联在页面/组件里。
- 原生控件:`<button>` 362 / `<input>` 48 / `<textarea>` 8 / `<select>` 2(`automations/AutomationRecords.tsx`)。
- `wb-icon` 类在多个恢复闭包中有独立尺寸规则(例:`source-select-recovered.css` 中 `.wb-icon` 与 `wb-icon--spin` 动画)。
## 4. 约定(当前实际遵守 / 未遵守的规矩)
| 主题 | 现状 | 证据 |
| --- | --- | --- |
| 类名体系 | 四类并存:`wb-*`(原版组件/恢复层)、`yc-*`(YCode 自有宿主与页面)、恢复家族 `cr-*/cb-*/ec-*/sm-*/dc-*`、原版 CSS Module 哈希 `_name_hash_index` | 见 1.2;`yc-*` 选择器 59 个(唯一) |
| 组件实现方式 | 无组件库:全部是"类名 + 手写 JSX";按钮/输入/弹窗在每个页面各自拼类名 | `package.json` 依赖无 UI kit;`wb-button` 247 次、`wb-input*` 多处手拼 |
| 无 Tailwind | 仓库无 `tailwind.config.*` / `postcss.config.*`(仅有 postcss 传递依赖),源码无 `@apply` | 根目录文件列表 + `package.json` |
| 无 `cn` / `clsx` / classnames 依赖 | `package.json` 无该依赖;全仓库唯一的拼接 helper 是 `components/ModelSettingsPanel.tsx:41` 的 `const cx = (name) => prefix + name`(前缀 `models-settings-panel__`),只做加前缀,不做条件合并 | 代码检索 |
| className 处理 | 直接字符串字面量或模板字符串拼接(如 `className={'a ' + b}`、`[..].filter(Boolean).join(' ')`,后者出现在恢复运行时) | TSX 全量检索 |
| 主题切换 | `document.documentElement.dataset.theme = 'light' | 'dark'`,由 `src/renderer/src/useSharedTheme.ts` 统一写入(`localStorage['ycode:theme']`,两个窗口共享);组件通过 `html[data-theme='dark']` 重映射 | `useSharedTheme.ts:8-20`、`App.tsx:41`、`SettingsDialog.tsx:95`、`tokens.css:352` |
| 恢复模块的并行主题属性 | 宿主还会在子树上打 `data-cr-theme="dark|light"`(以及 `data-theme`),供 `[data-cr-theme=dark]` 恢复规则命中 | `components/ChatPane.tsx:420`、`components/SourceModelPicker.tsx:47`、`workbuddy/composer/add-menu/SourceComposerAddMenu.tsx:29`、`workbuddy/subagents/SubagentDetailPanel.tsx:37` 等 |
| 平台/桌面标记 | `body[data-electron-desktop]`、`body[data-platform]` 由入口写入;恢复 CSS 另有 `body.wb-mobile-layout` 分支 | `main.tsx:16-17`、`settings.tsx:11-12`、`settings-shell-source.css` |
| 字号档位 | `--yc-font-offset-global` 由 `fontSize.ts` 写入;`.cb-font-size-fixed` 边界内重解析,防止"双重放大" | `fontSize.ts`、`tokens.css` 末尾块 |
| 恢复文件不可手改 | `*-source.css` / `*-recovered.css` 带生成头(REA ev id + SHA),由 `scripts/rea/recover-*.mjs` 生成;页面通过 `@import` 或 TSX import 引入(例:`components/source-home.css:1`) | 13 个 CSS 带 `generated by / Recovered from` 头;`scripts/rea/` 下 80+ recovery 脚本 |
| 打包入口 | 主窗口与设置窗口共用 `window.ycode` 假桥(`scripts/verify-ui.mjs`),命名空间现覆盖 24 个(与渲染进程使用的 24 个一致) | 见 5.5 |
## 5. 例外与风险
### 5.1 重复调色板作用域
- 13 个文件重复定义 `--wb-palette-brand-8`(含浅色/深色两套),根上没有权威 `--wb-palette-*`。
- 组件一旦被移出 `.source-*` / `.models-settings-panel` / `.yc-capability-center` / `.chat-pane.cr-theme` 等宿主,就会掉色、掉圆角、掉主题。
- 新组件引用 `--wb-*` 只有在正确作用域内才成立;引用 `--yc-*` 才有全局保证(且仍需注意 1.4 的局部重声明)。
### 5.2 作用域之外的尺寸/图标 token 未定义
- `--wb-size-control-*`、`--wb-icon-size-*` 只在闭包内出现(`capability-center-source.css:8`、`model-settings.css:146`、`source-styles.css:7` 等),排版 token 中引用它们的 `--wb-button-height-*`、`--wb-button-icon-size-*` 在根作用域不可解析。
### 5.3 悬空 token 引用
- `--wb-font-line-height-9`(7 个文件引用)与 `--wb-font-line-height-6-2`(多个恢复文件引用)全仓库无定义;`--yc-line-height-6-2: 26px` 是同值硬写替代。
- 影响 `--wb-font-spec-h2-line-height`、`--wb-font-spec-h5-line-height` 及部分恢复规则的 line-height 声明(部分浏览器会按 invalid-at-computed-value 处理)。
### 5.4 加载顺序不是声明顺序
- 入口先 `import App/SettingsWindow`、后导入样式,打包后组件自带 CSS 先落地(实测 `app-h0tta3aw.css` 首条规则来自 `source-select-recovered.css`)。
- 结果:`styles/app.css`、`styles/sidebar.css` 与恢复层、settings-shell 的相对顺序依赖构建产物,而非源码书写意图。
### 5.5 `scripts/verify-ui.mjs` 假桥状态(相对方案文档已变化)
- 方案文档记录"假桥缺少 `window.ycode.library`";**本次实测该断言已过期**:`scripts/verify-ui.mjs` 的 STUB 现定义 24 个命名空间(`window/edit/app/config/general/personalization/agents/memory/models/workspace/session/chat/experts/skills/mcp/projects/automation/library/attachments/speech/git/browser/terminal/resources`),与渲染进程实际使用的 24 个一致。
- 残留风险:假桥是**手工维护的 preload 形状副本**(无类型约束、返回值多为空集合),新增命名空间后必须同步,否则页面静默半挂载;它只能保证"能挂载",不能保证数据态渲染。
- 同批新增的静态守护 `scripts/check-design-tokens.mjs` + `scripts/design-token-baseline.json`(入口 `npm run check:tokens`)扫描 `src/renderer/src` 的裸 hex、裸 px、`!important`、`--wb-*` 定义、`var(--yc-*)`/`var(--wb-*)` 使用;门禁分类为 `core / local / adapter`,`source / recovered / vendor` 只记录不阻塞。本次实测 `node scripts/check-design-tokens.mjs --json`(334 个文件):`ycVarUses` 1,372、`wbVarUses` 22,766、`important` 926,与本文件第 0 节手工统计完全一致;对比口径时以该 JSON 为准(它按分类拆分,本文件第 5.6 节只列头部文件)。
### 5.6 `!important` 与 CRLF
- `!important` 总量 926,集中在恢复/投影文件:
| 文件 | 数量 |
| --- | ---: |
| `projects/source-project-detail-recovered.css` | 287 |
| `projects/source-projects-recovered.css` | 272 |
| `components/workspace-source.css` | 108 |
| `workbuddy/workbench/source-code-assets/editor-gwlzV742.css` | 97 |
| `components/sidebar-shell-source.css` | 19 |
| `capabilities/created-expert-source.css` | 16 |
| `workbuddy/composer/add-menu/source.css`、`components/source-memory-settings-recovered.css` | 各 13 |
| `components/source-home-recovered.css`、`workbuddy/user-menu/account-menu-source.css`、`workbuddy/workbench/panel-motion-source.css` | 各 11 |
本次点名的四个核心文件:`capabilities/capability-center-source.css` 0、`components/model-settings.css` 3、`components/source-home-recovered.css` 11、`workbuddy/conversation/source-styles.css` 3。
- 换行符:320 个 CSS/TSX/TS 文件为 LF,**11 个为 CRLF**:`capabilities/ExpertsPage.tsx`、`capabilities/SkillsPage.tsx`、`components/ChatPane.tsx`、`components/MessageBubble.tsx`、`components/model-settings.css`、`components/ModelSettingsPanel.tsx`、`components/PersonalizationSettingsPanel.tsx`、`components/RightSidebar.tsx`、`components/Sidebar.tsx`、`workbuddy/conversation/SourceWriteFileView.tsx`、`workbuddy/conversation/ToolCallRenderer.tsx`。跨文件 diff 会整文件抖动。
### 5.7 深色主题按作用域重写
- 除了 `tokens.css` 的 18 条根级重映射,深色还分别写在:`model-settings.css:147`、`source-home-recovered.css:3`、`source-select-recovered.css:3`、`source-workspace-picker-recovered.css:3`、`source-chat-header-recovered.css:3`、`source-model-picker-recovered.css:3`、`source-settings-navigation-recovered.css:3`、`source-general-settings-recovered.css`、`source-agents-panels-recovered.css:7`、`source-about-help-panels-recovered.css:4`、`source-appearance-panel-recovered.css:4`、`source-memory-settings.css:41`、`settings-shell-source.css:6`、`library/library.css:44`、`projects/project-menu.css:20`、`automations/automation-page.css:1625,2730`、`components/app-discover-popover.css:49`、`workbuddy/workbench/workbench-adapters.css:48-50`、`workbuddy/subagents/theme.css` 等,且部分恢复规则同时识别 `body.dark / body.vscode-dark / .vscode-dark`。
- 风险:主题值多份拷贝,任一处漏改会出现"局部亮块"。
### 5.8 已知组件层重复
- 按钮 3 套(`wb-button` / `.btn+.btn-icon` / `.automation-button`),输入框 ≥4 套,弹窗 2 套(`wb-modal` / `.dialog`),提示 4 套(`model-ui-toast` / `yc-skill-notice` / `yc-member-notice` / `.notice`),空态每页一套,骨架 4 套,图标 25 个模块 + 95 处散落内联 SVG(164 − 69,见 3.3)。
## 6. 目标层(指向方案,不在此展开)
目标架构、兼容层桥接规则、组件抽取优先级(Button/Input/Select/Dialog/Popover/Tabs → Checkbox/Switch/Card/ListItem/Badge/EmptyState → Avatar/Spinner/Tooltip/Toast)与 P0→P4 迁移顺序,全部以 `docs/设计系统提取与统一方案-2026-10-18.md` 为准。组件接口契约(命名规范、变体矩阵、禁止事项)以同批产出的 `docs/界面基础组件规范-2026-10-18.md` 为准(如该文件存在);本文件第 5.5 节已回填 P0 两项工具的当前实测状态(`npm run check:tokens` 静态守护、修正后的 `scripts/verify-ui.mjs` 假桥),后续 Build / Audit 以这两个入口 + 本文件第 2 节取值为改动前后的基线。
## 附录:复核命令
```powershell
# 权威层与声明数
rg -c -- "--yc-[a-z0-9-]+\s*:" src/renderer/src/styles/tokens.css
rg -c -- "--wb-[a-z0-9-]+\s*:" src/renderer/src/workbuddy/typography/tokens.css
# 作用域重复调色板
rg -l -- "--wb-palette-brand-8:" src/renderer/src
# 悬空 token
rg -l -- "var\(--wb-font-line-height-9\)|var\(--wb-font-line-height-6-2\)" src/renderer/src
rg -n -- "--wb-font-line-height-(9|6-2):" src/renderer/src
# 加载顺序(源码)
Select-String -Path src/renderer/src/main.tsx,src/renderer/src/settings.tsx -Pattern "import '.+\.css'"
# 加载顺序(产物)
Select-String -Path out/renderer/index.html -Pattern '\.css'
# 假桥覆盖面
rg -o -- "window\.ycode\.[a-zA-Z]+" src/renderer/src --glob "*.tsx" --glob "*.ts" | Sort-Object -Unique
# !important / CRLF 抽查
rg -o -F "!important" src/renderer/src --glob "*.css" | Measure-Object
```