Why: The design system still described preview as a right-rail tab, while the implementation now keeps a timeline in the transcript and opens files in a closable pane beside the chat. Evidence: make test passed (core, backend, frontend 51, ui 71, agent-command). Impact: Dev pins core d437530, backend dab8f31, ui 8bfe8a8, frontend 0ed8ad3. DESIGN.md §6, §9.3, and §9.6 match that layout. Refs: feature/chat-timeline-preview Co-authored-by: Cursor <cursoragent@cursor.com>
208 lines
11 KiB
Markdown
208 lines
11 KiB
Markdown
# Agent-System-Dev 设计系统(DESIGN.md)
|
||
|
||
写给 Agent 与人:在本仓生成或修改任何 UI 之前,先遵循本文,再发明新的视觉规则。
|
||
违反本文视为**设计系统缺陷**,不是风格偏好。
|
||
|
||
四原则:**美观、现代、简洁、易用**。每条规则都是四原则在某一维度上的可执行化。
|
||
|
||
参照体系:ZCode(zai-org/ZCode)开源仓的 DESIGN.md、`packages/ui/src/styles.css`
|
||
主题真值与动效配方。本文的色板、字号标尺、圆角层级、动效参数均逐条对照其源码校准。
|
||
|
||
---
|
||
|
||
## 1. 产品性格
|
||
|
||
Agent-System-Dev 是桌面优先、Web 兼容的 AI 工作台。界面应**冷静、高密度、可操作**,而非装饰性的。
|
||
|
||
为长会话、高信息密度、可读的对话与工具输出、键盘驱动的工作流而设计。
|
||
|
||
避免:营销式大留白、默认渐变装饰、大面积品牌色铺底、背景/卡片/浮层层次含混。
|
||
|
||
## 2. 主题
|
||
|
||
- 用户可选主题:跟随系统 / 浅色 / 深色。实现为 `:root[data-theme='dark' | 'light']`。
|
||
- 深色基准为 Zai Dark 复刻;浅色基准为 Zai Light。**令牌唯一来源:`@ui/tokens.css`**。
|
||
- 禁止在组件里出现裸色值(hex/rgb 字面量);一切颜色经语义令牌消费。
|
||
守护测试(`design-guard.test.ts`)以基线棘轮拦截新增裸值。
|
||
|
||
### 2.1 表面阶梯(层次靠背景阶梯,不是描边堆叠)
|
||
|
||
| 令牌 | 深色 (Zai Dark) | 浅色 (Zai Light) | 用途 |
|
||
|---|---|---|---|
|
||
| `--bg-inset` | `#101010` | `#ececee` | 窗口间隙(面板化布局的"底座")、代码底 |
|
||
| `--bg` | `#161616` | `#f8f8f8` | 应用底、主区背景 |
|
||
| `--bg-panel` | `#202020` | `#ffffff` | 侧栏/面板/头部 |
|
||
| `--bg-raised` | `#2b2b2b` | `#ffffff` | 卡片、输入、菜单、浮层 |
|
||
| `--bg-hover` | `rgba(255,255,255,.05)` | `rgba(13,13,13,.05)` | 通用悬停 |
|
||
| `--bg-active` | `rgba(255,255,255,.10)` | `rgba(13,13,13,.08)` | 选中态 |
|
||
|
||
### 2.2 边框(发丝三档)
|
||
|
||
`--border-soft: rgba(255,255,255,.06)` / `--border: rgba(255,255,255,.10)` /
|
||
`--border-strong: rgba(255,255,255,.15)`(浅色对应 13,13,13 的 .08/.10/.16)。
|
||
边框只做轮廓;选中优先用 `--bg-active` 填充而非换边框色。
|
||
|
||
### 2.3 文本
|
||
|
||
`--text`(主读文本,深 `#d4d4d4` / 浅 `#262626`)、`--text-dim`(62%)、`--text-faint`(38%)。
|
||
用文本层级制造信息密度,先于增加更多边框或颜色。
|
||
|
||
### 2.4 强调与语义色
|
||
|
||
- 交互强调蓝:`--accent`(深 `#4099ff` / 浅 `#0b7fff`)。**只用于**链接、选中指示、聚焦环、
|
||
进行中指示;不做大面积铺底、不做主按钮底色。
|
||
- 主按钮:单色系反色——`--primary`(深 `#ffffff` / 浅 `#0d0d0d`)配 `--primary-foreground`
|
||
(反向黑/白)。品牌色保持克制。
|
||
- 语义:`--ok #46bf72`、`--warn #ff8a30`、`--err #ff5c5c`(浅色 `#1e8a3e/#e07b00/#e03131`)。
|
||
语义色只表语义;确认等待类统一绿色语言,不用红/橙装饰。
|
||
|
||
## 3. 字号标尺(唯一字号体系)
|
||
|
||
全局唯一可调变量 `--ui-font-size`(默认 14px),派生:
|
||
|
||
| 令牌 | 公式 | 默认 | 角色 |
|
||
|---|---|---|---|
|
||
| `--fs-ui-xl` | +4px | 18 | 阅读标题 h1 |
|
||
| `--fs-ui-lg` | +2px | 16 | 阅读标题 h2 |
|
||
| `--fs-ui-base` | = | 14 | 正文、常用按钮、区块标题 |
|
||
| `--fs-ui-caption` | −1px | 13 | 紧凑辅助文案 |
|
||
| `--fs-ui-sm` | −2px | 12 | 次要信息、行内代码 |
|
||
| `--fs-ui-xs` | −4px | 10 | 徽标、快捷键、极弱元数据 |
|
||
|
||
规则:UI 组件一律用标尺令牌;禁止行内 `font-size` 数值与 Tailwind 式任意字号
|
||
(守护测试棘轮拦截)。用户调字号只改 `--ui-font-size`,不改根字号;图标、间距、圆角不随字号缩放。
|
||
例外:代码/Diff/终端/文档正文用独立阅读字号(等宽 12–12.5px、文档 13.5px)。
|
||
|
||
字体:`--font` 系统栈优先(-apple-system/PingFang SC…);路径、命令、代码、快捷键用 `--mono`。
|
||
|
||
## 4. 间距
|
||
|
||
基数 4px。节奏:4(图标与文字)→ 8(控件内边距/行内间隙)→ 12(紧凑列表行)→
|
||
16(卡片/面板标准内边距)→ 20–24(大区块/对话框内部)。用少量重复间距,不用任意值。
|
||
|
||
## 5. 圆角(按嵌套层级,不按组件重要性)
|
||
|
||
| 令牌 | 值 | 用途 |
|
||
|---|---|---|
|
||
| `--radius-xs` | 4 | 最内层(嵌在 6px 控件里的小元素) |
|
||
| `--radius-sm` | 6 | 基础控件(嵌套时降档)、chip |
|
||
| `--radius` | 8 | 输入、菜单壳、工具行 |
|
||
| `--radius-lg` | 12 | 卡片、气泡、工具调用块、**面板(见 §6)** |
|
||
| `--radius-xl` | 16 | 对话框、全屏视图壳 |
|
||
| `--radius-full` | 999 | 仅用于刻意的胶囊/圆形 |
|
||
|
||
嵌套降档:12 → 8 → 6 → 4;最内层不低于 4。对话框内部重新从 12 起算。
|
||
禁止任意值。`rounded-full` 不因组件类型自动获得。
|
||
|
||
## 6. 布局:面板化工作区
|
||
|
||
桌面工作区 = 浮在 `--bg-inset` 底座上的**独立圆角面板**(左栏 / 对话主区 / 预览区 / 右栏):
|
||
面板 `--radius-lg` 圆角 + `--border-soft` 发丝描边,面板之间 **4px 间隙**,应用四周 4px 内衬。
|
||
拖拽分隔条:透明 4px 命中区,hover/拖拽时显示 2px `--border-strong` 指示线(两端留出面板圆角)。
|
||
|
||
预览区插在对话与右栏之间,只在当前会话有打开的文件时出现。宽度可拖(420–1100),
|
||
用 `--bg`,不受右栏 560 上限约束。打开第一张标签时收起右栏,关掉最后一张时恢复右栏原状。
|
||
标签按会话记住,切回该会话时恢复。
|
||
|
||
层次规则:左栏与右栏用 `--bg-panel`,对话主区与预览区用 `--bg`;窄屏可退化为通栏。
|
||
信息架构原则:**对话优先**——普通用户仅凭对话即可完成全部工作,右栏纯辅助、可完全收起;
|
||
系统管理类视图独立成区(管理员专属入口),不混入用户设置。
|
||
|
||
## 7. 海拔(Elevation)
|
||
|
||
克制深度,分层顺序:背景对比 > 发丝描边 > 浮层阴影 > 注意级阴影。
|
||
|
||
- 基础层:无阴影,靠背景阶梯;
|
||
- 卡片:无阴影或 `--shadow-md` 极弱;
|
||
- 菜单/弹层:`--shadow-md`;
|
||
- Toast/重要浮卡:`--shadow-lg`。
|
||
|
||
禁止用大软阴影做普通布局分层。
|
||
|
||
## 8. 动效(MotionKit)
|
||
|
||
动效解释状态变化,不装饰屏幕。快、低调;禁止长弹簧(仅点赞/完成反馈可用一次过冲)。
|
||
**全部动效经 `@ui/motion.css` 的 `mk-*` 工具类消费;组件文件禁止私有 `@keyframes`**
|
||
(守护测试拦截)。所有动效在 `prefers-reduced-motion: reduce` 下禁用。
|
||
|
||
| 工具类 | 参数 | 用途 |
|
||
|---|---|---|
|
||
| `mk-stream-in` | opacity,900ms `cubic-bezier(0.16,1,0.3,1)` | 流式内容进场(可按 token 加延迟) |
|
||
| `mk-rise-in` | fade + translateY(4px),180ms | 列表行/卡片进入 |
|
||
| `mk-waterfall` | clip-path + translateY(−12px),260ms `cubic-bezier(0.22,1,0.36,1)` | 建议列表逐条瀑布 |
|
||
| `mk-col` / `mk-col-inner` | 高度 grid-rows 300ms ease-in-out + 内层 fade | 折叠/展开(@ui Collapsible) |
|
||
| `mk-sweep` | 文字扫光,300% 渐变 4s linear | **运行态指示(不用 spinner)** |
|
||
| `mk-breathe` | opacity .4↔1,1.2s | 状态点呼吸 |
|
||
| `mk-pop` | 450ms `cubic-bezier(0.34,1.56,0.64,1)` | 点赞/完成过冲反馈(唯一弹性) |
|
||
| `mk-shimmer` | 背景扫光 1.8s linear | 加载占位 |
|
||
| `mk-overlay-in` / `mk-modal-in` | 140ms fade / 160ms fade+translateY(6px)+scale(.99) | 弹层进入 |
|
||
| `mk-panel-grow` | flex-grow 过渡 200ms ease-out(用时挂、transitionend 摘) | 面板开合 |
|
||
|
||
## 9. 组件范式
|
||
|
||
### 9.1 工具调用块(ToolBlock 契约,参照 ZCode ToolLayout)
|
||
|
||
单行摘要:`[图标][工具名][主文本][副文本][状态词]`。
|
||
- 运行中:工具名文字扫光(`mk-sweep`),状态词最弱色;**不用旋转图标**(长流式期省渲染);
|
||
- 完成默认收起;`autoOpen`(如 edit/read 类)运行时自动展开一次,用户可再收起;
|
||
- 完成边沿(running→completed)自动收起一次,不阻止用户手动展开;
|
||
- 展开态按 id 记忆,切回不丢;
|
||
- 失败不强制展开:状态词虚线下划线,hover tooltip 给报错,支持一键复制;
|
||
- 内容懒渲染,收起后延迟卸载(300ms,配合高度动画)。
|
||
|
||
### 9.2 折叠(@ui Collapsible 原语)
|
||
|
||
一切折叠区(过程输出、长回复、任务卡)用它:外壳高度动画 + 内容 fade 两层分离、
|
||
300ms 延迟卸载、展开态记忆。禁止再写 `<details>` 折叠。
|
||
|
||
### 9.3 一个动作一个入口
|
||
|
||
同一对象只允许一个主要操作路径:一个工件 = 一个预览落位(对话右侧预览区)+ 预览区标题栏上的一个下载。
|
||
对话里的文件卡片负责打开这个预览区;卡片菜单里的下载是同一下载动作的就近入口,不另开预览器。
|
||
全屏 overlay 是预览区的放大,不是第二落位。禁止弹窗套弹窗。
|
||
|
||
### 9.4 按钮
|
||
|
||
Primary(`--primary` 反色)、Ghost(透明,hover 出表面)、Danger(语义红)。
|
||
同一面板内保持动作层级,不把每个动作都升为 primary。
|
||
|
||
### 9.5 菜单与浮层
|
||
|
||
菜单壳 `--radius`(8) + `--shadow-md` + 紧凑行(`--radius-sm` 6 的行、`--fs-ui-base`);
|
||
菜单是紧凑动作行,不是迷你按钮。交互浮层必须盖过被动 tooltip。
|
||
|
||
### 9.6 工作时间线与标签条
|
||
|
||
助手消息在运行中按时间线逐行展开,终轮结束后折成一行。
|
||
|
||
- 运行中始终展开:思考行显示「思考中」并带 `mk-sweep`;对用户的解说按正文样式直接显示;
|
||
同类工具合并成一行(查阅、搜索、已运行命令、写入、卡片、委派、计划)。
|
||
- 终轮(没有后续工具调用)结束后,过程段收进 Collapsible,触发行为「已工作 X 分 Y 秒」。
|
||
最终回复留在折叠行下面。不在每一轮 `responding` 时来回折叠。
|
||
- 文件卡片:图标、名称、「类型 · 大小」、右侧「预览」。正文里的 `art_` 编号若对得上工件,在正文后补一张卡片;
|
||
对不上则显示「未找到该文件」,不伪装成可打开的文件。
|
||
- 标签条用 `@ui` `TabStrip`:点击激活、× 关闭、中键关闭,溢出横向滚动。只消费令牌与 `mk-*`。
|
||
|
||
## 10. 信息架构与文案
|
||
|
||
- 普通用户界面只暴露任务与对话;插件/代理/治理类能力归系统管理区(管理员可见)。
|
||
- 右栏收起时功能零缺失(D31:弹层不承载唯一步骤,每个操作另有对话内路径)。
|
||
- 中文文案:动宾结构、不带句点结尾;快捷键用 `⌘`/kbd 标注。
|
||
- 布局容忍长文本与翻译膨胀,不依赖截断作为唯一生存手段。
|
||
|
||
## 11. 禁止清单(守护测试覆盖项)
|
||
|
||
1. 组件/样式文件里新增裸色值(hex/rgb 字面量)——走令牌;
|
||
2. 组件文件里私有 `@keyframes`——走 MotionKit;
|
||
3. TSX 行内 `font-size`——走字号标尺;
|
||
4. 运行态用旋转 spinner——用 `mk-sweep`/`mk-breathe`;
|
||
5. 弹窗套弹窗;
|
||
6. 同一对象出现第二个预览落位(预览只在预览区,全屏是它的放大);
|
||
7. `<details>` 折叠——用 Collapsible。
|
||
|
||
## 12. 演进规则
|
||
|
||
改风格 = `DESIGN.md` 与 `tokens.css`(必要时 `motion.css`)**同 PR 成对修改**,附前后值对照;
|
||
不允许只改代码不改文档。新增视觉规则先问:它属于结构、表面、交互还是状态?
|
||
拿不准时,选更安静的方案、用更强的信息层级。
|