Kimi Web 设计系统
+Kimi Web Design System
- 本文定义 Kimi Web 的视觉语言与组件规范——设计令牌、组件基元、聊天界面、主题系统与样式规则。 - 所有 UI 工作以此为基准:统一、克制、token 驱动、可主题化。 + This document defines the visual language and component specification for Kimi Web — design tokens, component primitives, the chat interface, theming, and style rules. + All UI work is grounded in it: unified, restrained, token-driven, and themeable.
设计原则
+Design Principles
- 所有 UI 决策回指以下原则。Kimi Web 是给开发者用的本地 Agent 工具:快速扫读、长时间注视、经常在暗色下——设计服务于任务,克制、临床、信息密度优先。 + Every UI decision traces back to the following principles. Kimi Web is a local Agent tool for developers: quick scanning, long stretches of staring, often in the dark — the design serves the task, and is restrained, clinical, and density-first.
-
-
- 一致性 Consistency —— 同一语义用同一组件。主按钮、弹窗、输入、徽标在全站只应各有「一种」正确写法。 -
- 视觉层级 Hierarchy —— 通过字号、字重、色彩与留白建立清晰层级;用「克制」而非「加粗加大」来强调。 -
- 亲密性 Proximity —— 相关元素归组,无关元素留白。卡片的内边距、行间与分组间距来自同一间距刻度。 -
- 反馈 Feedback —— hover / active / focus / loading / success / error 都有可见状态,且状态语言统一。 -
- 留白 Breathing room —— 用间距刻度而非随机像素控制密度;宁可克制留白,不让控件互相挤压。 -
- 可访问性 A11y —— 文本对比度 ≥ 4.5:1,焦点环可见,触摸目标 ≥ 32px,状态不只依赖颜色。 -
- 少即是多 Reduction —— 颜色数量、圆角数量、阴影层级、字号阶梯都收敛到有限 token,删除游离值。 +
- Consistency —— The same semantics use the same component. The primary button, dialog, input, and badge should each have exactly "one" correct way to be written across the entire site. +
- Hierarchy —— Build a clear hierarchy through size, weight, color, and whitespace; emphasize through "restraint" rather than "bolder and bigger". +
- Proximity —— Group related elements, leave whitespace between unrelated ones. A card's padding, line spacing, and group spacing all come from the same spacing scale. +
- Feedback —— hover / active / focus / loading / success / error all have visible states, and the state language is unified. +
- Breathing room —— Control density with the spacing scale rather than arbitrary pixels; prefer restrained whitespace over cramming controls together. +
- Accessibility (A11y) —— Text contrast ≥ 4.5:1, visible focus rings, touch targets ≥ 32px, and states that don't rely on color alone. +
- Reduction —— The number of colors, radii, shadow levels, and type sizes all converge to a finite set of tokens; delete stray values.
设计令牌 Design Tokens
+Design Tokens
- 把所有视觉决策收敛为 token。颜色 token 沿用现有短名并补全语义(降低迁移成本), - 间距、层级、动效、字重则补齐目前缺失的刻度。每个 token 都有:名称、浅色值、深色值、用途。 + Collapse every visual decision into tokens. Color tokens keep the existing short names and fill out the semantics (lowering migration cost), + while spacing, z-index, motion, and font-weight fill in the scales that are currently missing. Every token has: name, light value, dark value, and usage.
--<类别>-<角色>-<状态>。例如 --color-text-muted、--radius-md、--space-4。
- 为减少改动,现有短名(--bg / --ink / --line / --blue …)作为兼容别名保留一个版本周期。
+ Naming convention: --<category>-<role>-<state>. For example --color-text-muted, --radius-md, --space-4.
+ To reduce churn, the existing short names (--bg / --ink / --line / --blue …) are kept as compatibility aliases for one release cycle.
颜色 Color
-语义优先、三层递进:背景 / 文字 / 描边 + 强调色 + 状态色。所有色值在浅色 / 深色下成对定义,对比度均 ≥ 4.5:1。
---color-accent 取自 --accent-primary,--color-bg 取自当前亮 / 暗面。语义状态色(success / warning / danger / info)是与种子配套的独立调色板,亮 / 暗各一套,不自动从种子派生;日常换肤通常只需调 4 个种子,状态色按需微调。Color
+Semantic-first, in three layers: background / text / border + accent + status colors. All colors are defined in light / dark pairs, with contrast ≥ 4.5:1.
+--color-accent comes from --accent-primary, and --color-bg comes from the current light / dark surface. The semantic status colors (success / warning / danger / info) are independent palettes paired with the seeds, one set each for light / dark; they are not auto-derived from the seeds. Day-to-day reskinning usually only needs the 4 seeds, with the status colors fine-tuned as needed.| Token | 浅色 | 深色 | 用途 |
|---|---|---|---|
| Token | Light | Dark | Usage |
| --color-bg | #ffffff | #0d1117 | 页面底色 |
| --color-surface | #fafbfc | #161b22 | 面板 / 侧栏 / 卡片头 |
| --color-surface-raised | #ffffff | #1c2128 | 浮起卡片 / 弹窗 / 输入 |
| --color-text | #14171c | #e8eaed | 正文 / 标题 |
| --color-text-muted | #6b7280 | #9aa0a8 | 次级文字 / 占位符 |
| --color-line | #e7eaee | #2d333b | 分割线 / 卡片描边 |
| --color-accent | #1783ff | #58a6ff | 主操作 / 链接 / 焦点 |
| --color-success | #0e7a38 | #3fb950 | 成功 / 通过 |
| --color-warning | #a9610a | #d29922 | 警告 / 待确认 |
| --color-danger | #c0392b | #f85149 | 危险 / 错误 / 中止 |
| --color-bg | #ffffff | #0d1117 | Page background |
| --color-surface | #fafbfc | #161b22 | Panel / sidebar / card head |
| --color-surface-raised | #ffffff | #1c2128 | Raised card / dialog / input |
| --color-text | #14171c | #e8eaed | Body text / headings |
| --color-text-muted | #6b7280 | #9aa0a8 | Secondary text / placeholder |
| --color-line | #e7eaee | #2d333b | Divider / card border |
| --color-accent | #1783ff | #58a6ff | Primary action / link / focus |
| --color-success | #0e7a38 | #3fb950 | Success / pass |
| --color-warning | #a9610a | #d29922 | Warning / pending |
| --color-danger | #c0392b | #f85149 | Danger / error / abort |
表面用法 Surface usage
-四层表面各司其职,按「要抬起的层 / 默认平层 / 下沉层 / 页面底色」选用,避免把 --p-surface-raised 当成万能背景。
Surface usage
+The four surface layers each have a role — choose by "raised layer / default flat layer / sunken layer / page background", and avoid treating --p-surface-raised as a universal background.
| Token | 浅色 | 深色 | 用途 |
|---|---|---|---|
| Token | Light | Dark | Usage |
| --p-surface-raised | #ffffff | #1c2128 | 浮起卡片 / 弹窗 / 输入(要抬起的层) |
| --p-surface | #fafbfc | #161b22 | 面板 / 侧栏 / 卡片头(默认平层) |
| --p-surface-sunken | #f3f5f8 | #0d1117 | 代码块 / 输入内嵌 / 凹陷区(下沉层) |
| --p-bg | #ffffff | #0d1117 | 页面底色 |
| --p-surface-raised | #ffffff | #1c2128 | Raised card / dialog / input (raised layer) |
| --p-surface | #fafbfc | #161b22 | Panel / sidebar / card head (default flat layer) |
| --p-surface-sunken | #f3f5f8 | #0d1117 | Code block / inline input / recessed area (sunken layer) |
| --p-bg | #ffffff | #0d1117 | Page background |
焦点环 Focus ring
-所有可聚焦控件(按钮、输入、链接、菜单项、开关、复选框)统一使用焦点环 token,禁止各自手写 box-shadow 焦点环。
Focus ring
+All focusable controls (button, input, link, menu item, switch, checkbox) use the focus-ring token uniformly; do not hand-write a box-shadow focus ring.
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --p-focus-ring | 0 0 0 3px var(--p-accent-soft) | 默认焦点环(链接、菜单项、开关、复选框) |
| --p-focus-ring-strong | 0 0 0 3px var(--p-accent-soft), 0 0 0 1px var(--p-accent) | 强焦点环(按钮、主操作) |
| --p-focus-ring | 0 0 0 3px var(--p-accent-soft) | Default focus ring (link, menu item, switch, checkbox) |
| --p-focus-ring-strong | 0 0 0 3px var(--p-accent-soft), 0 0 0 1px var(--p-accent) | Strong focus ring (button, primary action) |
选中文本 Selection
-文本选中色统一走 --p-selection(浅色 rgba(23,131,255,.18) / 深色 rgba(88,166,255,.32)),由全局 ::selection 规则套用,不另设高亮背景。
Text selection
+The text-selection color uses --p-selection uniformly (light rgba(23,131,255,.18) / dark rgba(88,166,255,.32)), applied by the global ::selection rule; do not set a separate highlight background.
禁用态 Disabled
-所有禁用控件统一 opacity:.5 + cursor:not-allowed,不再单独调灰或改色。
Disabled state
+All disabled controls use opacity:.5 + cursor:not-allowed uniformly; do not separately grey out or recolor.
字体族 Font families
-Kimi Web 使用两套字体族:--font-ui(UI 与正文,系统字体优先)与 --font-mono(代码与等宽)。组件一律通过变量引用,禁止硬编码字体名。
+Font families
+Kimi Web uses two font families: --font-ui (UI and body, system fonts first) and --font-mono (code and monospace). Components always reference the variables; do not hard-code font names.
---font-ui · UI 与正文(系统字体优先)
-正文与 UI 采用各平台原生 UI 字体,观感接近系统、长文与中文更舒适。回退链:
+--font-ui · UI & body (system fonts first)
+Body and UI use each platform's native UI font — close to the system feel, comfortable for long text and CJK. Fallback chain:
--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", "Noto Sans SC", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
-
-
- 系统 UI 字体在前:macOS / iOS 用 SF Pro,Windows 用 Segoe UI。 -
- CJK 紧随:PingFang SC(macOS)/ Microsoft YaHei(Windows)/ Noto Sans SC(Linux)。 -
- Helvetica Neue / Arial / sans-serif 通用兜底;末尾补 emoji 字体。 +
- System UI fonts first: SF Pro on macOS / iOS, Segoe UI on Windows. +
- CJK next: PingFang SC (macOS) / Microsoft YaHei (Windows) / Noto Sans SC (Linux). +
- Helvetica Neue / Arial / sans-serif as generic fallbacks; emoji fonts at the end.
--font-mono · 代码与等宽
-代码、工具名、行号、diff 等使用 JetBrains Mono(自托管可变字体),回退到系统等宽:
+--font-mono · Code & monospace
+Code, tool names, line numbers, diffs, etc. use JetBrains Mono (a self-hosted variable font), falling back to the system monospace:
--font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
加载策略
+Loading strategy
| 字体 | 来源 | 打包 | 用途 |
|---|---|---|---|
| Font | Source | Bundled | Usage |
| JetBrains Mono | @fontsource-variable/jetbrains-mono | ✓ 自托管 | 等宽 / 代码(--font-mono) |
| Inter | @fontsource-variable/inter | ✓ 自托管 | 可选:页面标题 / 品牌字样(--font-display) |
| 系统 UI / CJK 字体 | 操作系统 | — | 正文 / UI(--font-ui),不打包 |
| JetBrains Mono | @fontsource-variable/jetbrains-mono | ✓ self-hosted | monospace / code (--font-mono) |
| Inter | @fontsource-variable/inter | ✓ self-hosted | optional: page titles / brand wordmark (--font-display) |
| System UI / CJK fonts | operating system | — | body / UI (--font-ui), not bundled |
使用规则
+Usage rules
-
-
- 组件一律用
var(--font-ui)/var(--font-mono),禁止硬编码'Inter'/'JetBrains Mono'等字体名。
- - 正文 / UI 走
--font-ui(系统字体优先);代码 / 等宽走--font-mono(JetBrains Mono)。
- - Inter 仅用于需要统一观感的标题 / 品牌场景(可选
--font-display),不再作为正文默认。
+ - Components always use
var(--font-ui)/var(--font-mono); do not hard-code font names like'Inter'/'JetBrains Mono'.
+ - Body / UI use
--font-ui(system fonts first); code / monospace use--font-mono(JetBrains Mono).
+ - Inter is used only for headings / brand scenarios that need a unified look (optional
--font-display); it is no longer the body default.
字号与字重 Type scale & weight
-字号阶梯沿用并规范现有的 --ui-font-size(UI,默认 14px)/ --content-font-size(正文,16px)双轨:UI 控件 / 按钮 / 表单用 --text-base(14px);阅读型正文——包括聊天 Markdown、消息气泡等为提升可读性用 --text-lg(16px,行高 relaxed);侧栏会话列表为信息密度用 calc(var(--ui-font-size) - 1px)(15px,比侧栏 16px 基底小一档)。
- 删除游离的 font-weight: 650 / 750,统一到 400 / 500 两档(常规 / 强调)。
Type scale & weight
+The type scale keeps and formalizes the existing --ui-font-size (UI, default 14px) / --content-font-size (body, 16px) dual tracks: UI controls / buttons / forms use --text-base (14px); reading body — including chat Markdown, message bubbles, etc. uses --text-lg (16px, relaxed line-height) for readability; the sidebar session list uses calc(var(--ui-font-size) - 1px) (15px, one step below the sidebar's 16px base) for density.
+ Drop stray font-weight: 650 / 750; converge on two weights, 400 / 500 (regular / emphasis).
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --font-ui | -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC"… | UI 与正文(系统字体优先) |
| --font-mono | JetBrains Mono… | 代码、工具名、行号、diff |
| --leading-tight/normal/relaxed | 1.25 / 1.5 / 1.7 | 标题 / UI / 长文 |
| --weight-regular/medium | 400 / 500 | 正文 / 强调 |
| --font-ui | -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC"… | UI & body (system fonts first) |
| --font-mono | JetBrains Mono… | code, tool names, line numbers, diffs |
| --leading-tight/normal/relaxed | 1.25 / 1.5 / 1.7 | headings / UI / long text |
| --weight-regular/medium | 400 / 500 | body / emphasis |
图标尺寸 Icon size
-图标统一使用三档尺寸 token,全局 .p-ic 默认 16px(--p-ic-md);各组件按需选用,禁止手写随机像素。
Icon size
+Icons use three size tokens uniformly. The global .p-ic default is 16px (--p-ic-md); components pick as needed, and random pixel sizes are forbidden.
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --p-ic-sm | 14px | 小按钮、徽标、菜单项、链接内嵌图标 |
| --p-ic-md | 16px | 默认(按钮、图标按钮、工具条) |
| --p-ic-lg | 20px | Toast 状态图标、空状态插图 |
| --p-ic-sm | 14px | small button, badge, menu item, inline link icon |
| --p-ic-md | 16px | default (button, icon button, toolbar) |
| --p-ic-lg | 20px | Toast status icon, empty-state illustration |
图标 Icon
-图标一律从集中注册表 lib/icons.ts 取用:模板中用 <Icon name size /> 组件(components/ui/Icon.vue),v-html 场景(如工具 glyph)用 iconSvg(name, size)。禁止手写 <svg>——scripts/check-style.mjs 的 icon-from-registry 规则会对游离 SVG 告警。图标来自 Remix Icon(Apache-2.0),统一为 fill 风格(fill="currentColor"、24×24 源网格),颜色跟随文字;尺寸走下方三档 token。注册表由 scripts/gen-icon-data.mjs 从 @iconify-json/ri 按需生成,离线且 tree-shaken。
Icon
+Icons always come from the centralized registry lib/icons.ts: in templates use the <Icon name size /> component (components/ui/Icon.vue); for v-html contexts (such as a tool glyph) use iconSvg(name, size). Do not hand-write <svg> — the scripts/check-style.mjs icon-from-registry rule flags stray SVGs. Icons come from Remix Icon (Apache-2.0), uniformly in a fill style (fill="currentColor", 24×24 source grid), with color following the text; size uses the three tokens below. The registry is generated on demand by scripts/gen-icon-data.mjs from @iconify-json/ri, offline and tree-shaken. The whole site uses only this one icon family; do not mix in other icon libraries, and never hand-write SVG paths. When an icon is missing, add it to the registry (edit the mapping in gen-icon-data.mjs and regenerate) rather than drawing it in a component.
尺寸阶梯 Size scale
+Size scale
图标库 Icon library
-当前注册的图标(按用途分组)。图标数据由 scripts/gen-icon-data.mjs 中的 NAME_TO_REMIX 映射决定,运行 pnpm gen:icons 生成 lib/icon-data.ts;本目录由 node --experimental-strip-types scripts/gen-icon-catalog.mjs 重新生成,保证注册表与文档不漂移。
Icon library
+Currently registered icons, grouped by purpose. The icon data is determined by the NAME_TO_REMIX mapping in scripts/gen-icon-data.mjs; running pnpm gen:icons generates lib/icon-data.ts. This catalog is regenerated with node --experimental-strip-types scripts/gen-icon-catalog.mjs so the registry and the document never drift.
禁止用 emoji 充当功能图标(唯一例外:月相 🌑…🌘,仅用于「等待 Agent 响应」聊天态)。Kimi 品牌标记(32×22 的眼睛 logo)属于品牌资产,不在此图标体系内。
-少数特殊图形不进注册表,各有专属组件统一维护,禁止复制手写:<ContextRing :pct />(Composer 上下文进度环,数据驱动)、<AuthStateIcon kind />(登录流程的成功 / 过期 / 错误彩色插图)、<Spinner />(加载态)。状态小圆点(如 Provider 列表)一律用 CSS 圆点(border-radius:50%),不再用 SVG。scripts/check-style.mjs 的 icon-from-registry 规则对以上与品牌标记豁免,其余手写 <svg> 一律告警。
Do not use emoji as functional icons (the sole exception is the moon phases 🌑…🌘, used only in the "waiting for the Agent to respond" chat state). The Kimi brand mark (the 32×22 eye logo) is a brand asset and is not part of this icon system.
+A few special graphics are not in the registry; each has a dedicated component maintained in one place, and must not be copied by hand: <ContextRing :pct /> (the Composer context progress ring, data-driven), <AuthStateIcon kind /> (the success / expired / error colored illustrations in the login flow), <Spinner /> (loading state). Status dots (such as in the Provider list) always use CSS dots (border-radius:50%), not SVG. The scripts/check-style.mjs icon-from-registry rule exempts the above and the brand mark; all other hand-written <svg> is flagged.
间距 Spacing
-4px 基础网格,组件内外所有间距、间隙、内边距都来自此刻度,杜绝随机像素。
+Spacing
+A 4px base grid. All spacing, gaps, and padding inside and outside components come from this scale — no arbitrary pixels.
密集列表 Dense list(侧栏 / 文件树)
-侧栏这类高密度导航列表共用一套节奏,全部落在 4px 网格:行内纵向内距 --space-1(4px),行间 无外边距(hover 圆角 pill 自身提供分隔);区段间距(logo / 搜索 / 操作钮 / 分组标题 / 列表之间)统一 --space-2(8px);分组之间 --space-2;品牌页头顶部略松(--space-3)。新建同类列表时复用此刻度,不要手写 1/6/7/10px。
Dense list (sidebar / file tree)
+High-density navigation lists like the sidebar share one rhythm, all on the 4px grid: in-row vertical padding --space-1 (4px), no margin between rows (the hover pill provides the separation); section gap (between logo / search / action buttons / group title / list) uniformly --space-2 (8px); between groups --space-2; the brand header is slightly looser at the top (--space-3). When building similar lists, reuse this scale — do not hand-write 1/6/7/10px.
圆角 Radius
-把现有 14 个值就近归并到 7 档刻度。规则:组件类型决定圆角,而非作者手感。
+Radius
+Merge the existing 14 values into the nearest of 7 scale steps. Rule: the component type determines the radius, not the author's feel.
| Token | 值 | 用途 | 归并来源 |
|---|---|---|---|
| Token | Value | Usage | Merged from |
| --radius-xs | 4px | 小徽标、内嵌标签 | 2/3/4px → |
| --radius-sm | 6px | 小按钮、图标按钮、菜单项 | 5/6px → |
| --radius-md | 8px | 按钮、输入、徽标、卡片 | 7/8/9px → |
| --radius-lg | 12px | 下拉面板 | 10/12px → |
| --radius-xl | 16px | 弹窗、底部 Sheet、Composer | 14/16px → |
| --radius-2xl | 20px | 强调容器 / 大面板 | 20px |
| --radius-full | 999px | 药丸徽标、头像、发送钮 | 999px / 50% |
| --radius-xs | 4px | small badge, inline tag | 2/3/4px → |
| --radius-sm | 6px | small button, icon button, menu item | 5/6px → |
| --radius-md | 8px | button, input, badge, card | 7/8/9px → |
| --radius-lg | 12px | dropdown panel | 10/12px → |
| --radius-xl | 16px | dialog, bottom Sheet, Composer | 14/16px → |
| --radius-2xl | 20px | accent container / large panel | 20px |
| --radius-full | 999px | pill badge, avatar, send button | 999px / 50% |
层级与阴影 Elevation & Z-index
-阴影只表达「层级」,不用作装饰(无彩色 glow)。z-index 统一成阶梯,根除 9999 式的互相压盖。
Elevation & z-index
+Shadows express only "elevation", never decoration (no colored glow). z-index is unified into a scale, eradicating 9999-style one-upping.
| Z-index Token | 值 | 用途 |
|---|---|---|
| Z-index Token | Value | Usage |
| --z-base | 0 | 常规流 |
| --z-sticky | 100 | 吸顶表头 / 侧栏 |
| --z-dropdown | 200 | 下拉菜单 / 工具提示 |
| --z-overlay | 300 | 遮罩 / 底部 Sheet |
| --z-modal | 400 | 弹窗 |
| --z-toast | 600 | 轻提示 |
| --z-max | 9999 | 保留:仅此一档用于极端兜底 |
| --z-base | 0 | normal flow |
| --z-sticky | 100 | sticky header / sidebar |
| --z-dropdown | 200 | dropdown menu / tooltip |
| --z-overlay | 300 | overlay / bottom Sheet |
| --z-modal | 400 | dialog |
| --z-toast | 600 | toast |
| --z-max | 9999 | reserved: only this tier for extreme fallback |
动效 Motion
+Motion
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --ease-out | cubic-bezier(0.16, 1, 0.3, 1) | 进入、悬停、展开 |
| --ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | 面板宽度、布局变化 |
| --duration-fast | 120ms | 按下、焦点 |
| --duration-base | 160ms | 悬停、显隐 |
| --duration-slow | 260ms | 弹窗、Sheet、布局 |
| --ease-out | cubic-bezier(0.16, 1, 0.3, 1) | enter, hover, expand |
| --ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | panel width, layout changes |
| --duration-fast | 120ms | press, focus |
| --duration-base | 160ms | hover, show/hide |
| --duration-slow | 260ms | dialog, Sheet, layout |
减少动态效果 Reduced motion
+Reduced motion
@media (prefers-reduced-motion: reduce) 下,所有动画与过渡时长降到约 0.001ms(即关闭),MoonSpinner 月相暂停在当前帧。组件不应各自判断,统一在全局样式中处理。
+ Under @media (prefers-reduced-motion: reduce), all animation and transition durations drop to about 0.001ms (effectively off), and the MoonSpinner moon phase pauses on the current frame. Components should not check this individually; it is handled uniformly in the global styles.
布局与断点 Layout & breakpoints
-布局尺寸与响应式断点同样 token 化:侧栏宽度、内容阅读栏宽度、两个全局断点。组件不应各自写死像素。
+Layout & breakpoints
+Layout sizes and responsive breakpoints are tokenized too: sidebar width, content reading-column width, and two global breakpoints. Components should not hard-code pixels.
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --p-sidebar-w | 264px | 左侧会话侧栏宽度 |
| --p-content-max | 760px | 聊天阅读栏最大宽度 |
| --p-content-wide | 920px | 宽内容(设置 / 面板) |
| --p-bp-sm | 640px | 手机 / 桌面分界 |
| --p-bp-md | 980px | 窄屏 / 宽屏分界 |
| --p-sidebar-w | 264px | left session sidebar width |
| --p-content-max | 760px | chat reading-column max width |
| --p-content-wide | 920px | wide content (settings / panel) |
| --p-bp-sm | 640px | mobile / desktop boundary |
| --p-bp-md | 980px | narrow / wide screen boundary |
组件基元 Primitives
+Primitives
- 组件基元是全站 UI 的「最小正确单元」。
- 每个基元只暴露 variant / size 两个维度的变体,外观由 token 驱动,
- 从而天然支持亮 / 暗模式与可定制主题色。
+ Component primitives are the "smallest correct units" of the site UI.
+ Each primitive exposes variants along only two dimensions — variant / size — with appearance driven by tokens,
+ so it naturally supports light / dark mode and customizable theme colors.
组件选型指南
+ +Component selection guide
| 场景 | 用什么 |
|---|---|
| Scenario | Use |
| 主操作(提交 / 确认) | Button variant=primary |
| 次操作 / 取消 | Button secondary / ghost |
| 危险操作(删除 / 中止) | Button danger / danger-soft |
| 状态标记 | Badge |
| 工具条筛选 / 模型切换 | Pill |
| 2–4 项互斥切换 | SegmentedControl |
| 顶部标签页 | Tabs |
| 开关 / 多选 | Switch / Checkbox |
| 浮起内容卡 / 列表动作菜单 | Card / Menu |
| 内联通知 / 全局轻提示 | Banner / Toast |
| 弹窗 / 确认 · 底部面板(移动) | Dialog / Sheet |
| Primary action (submit / confirm) | Button variant=primary |
| Secondary action / cancel | Button secondary / ghost |
| Destructive action (delete / abort) | Button danger / danger-soft |
| Status marker | Badge |
| Toolbar filter / model switch | Pill |
| 2–4 mutually exclusive options | SegmentedControl |
| Top tabs | Tabs |
| Switch / multi-select | Switch / Checkbox |
| Floating content card / list action menu | Card / Menu |
| Inline notice / global toast | Banner / Toast |
| Dialog / confirmation · bottom panel (mobile) | Dialog / Sheet |
Button · 按钮
-4 个语义变体 × 3 个尺寸。主操作 primary 的颜色取自当前主题色(§05 可在蓝色系 / 黑色系间切换)。圆角统一走 --radius-md(小尺寸 --radius-sm),字重 600,带可见 focus 环。
Button
+4 semantic variants × 3 sizes. The primary action primary takes its color from the current theme color (§05 can switch between the blue and black families). Radius uses --radius-md uniformly (small size --radius-sm), weight 600, with a visible focus ring.
API
<Button variant="primary" size="md" :loading="submitting">保存</Button> + +<Button variant="primary" size="md" :loading="submitting">Save</Button> // variant: primary | secondary | ghost | danger | danger-soft // size: sm | md | lg
IconButton · 图标按钮
-统一为 26 / 32 / 44px 三档,hover 浅灰底,focus 环可见。替代当前各组件里散落的图标 + 点击区。
+IconButton
+Unified into three sizes — 26 / 32 / 44px — with a light-grey hover background and a visible focus ring. Replaces the ad-hoc icon + click areas scattered across components today.
sm 26 / md 32 两档;在触摸设备上点击目标应 ≥ 44px,用 lg 44px,满足 §01 的可访问性原则(移动端三件套即使用 lg)。
+ The desktop IconButton comes in sm 26 / md 32; on touch devices the tap target should be ≥ 44px, so use lg 44px, satisfying the §01 accessibility principle (the mobile three-piece set uses lg).
Badge · Chip · Pill
-收敛为两类:Badge(状态徽标,带可选状态点)与 Pill(composer 工具条的可点击药丸)。圆角、字号、内边距全部统一。
+Badge · Chip · Pill
+Collapsed into two kinds: Badge (status badge, with an optional status dot) and Pill (the clickable pill in the composer toolbar). Radius, font size, and padding are all unified.
Card / Surface · 卡片与表面
-全站卡片共用一种外壳:扁平、1px 描边、圆角 --radius-md、无阴影。结构上分为 head / body / foot 三段。卡片之间的区别只在头部——按视觉权重分两档,外壳始终保持一致:
Card / Surface
+All cards across the site share one shell: flat, 1px border, --radius-md radius, no shadow. The structure is split into three parts — head / body / foot. Cards differ only in the head — in two tiers by visual weight, while the shell stays consistent:
-
-
- 操作卡 Operation —— 工具调用、Agent、Todo 等「过程」内容。头部紧凑 mono、无底色,默认低权重,不抢对话。 -
- 注意卡 Attention —— Question / Approval 等需要用户决策的内容。头部带语义色带(accent / warning),从消息流中凸显。 +
- Operation card —— "process" content such as tool calls, Agent, Todo. The head is compact mono with no fill, low weight by default, not competing with the conversation. +
- Attention card —— content that needs a user decision, such as Question / Approval. The head carries a semantic color band (accent / warning) to stand out from the message stream.
accent-soft / warning-soft),从消息流中凸显,提示用户必须介入。外壳与操作卡完全相同。accent-soft / warning-soft) to stand out from the message stream, signaling that the user must step in. The shell is exactly the same as the operation card.-
-
- 统一外壳:所有卡片扁平 + 1px 描边 + radius-md,不投射阴影。 -
- 差异有意为之:仅头部区分类型(mono 紧凑 vs 语义色带),外壳始终保持一致。 -
- 分组:外层容器拥有边框与圆角,内部行用
border-top发丝分隔,不再让每行各自成卡。
- - 状态点:运行中(脉冲蓝)/ 完成(绿)/ 失败(红),共用同一套颜色词汇(详见 §04 工具调用)。 +
- Unified shell: all cards are flat + 1px border + radius-md, casting no shadow. +
- Differences are intentional: only the head distinguishes the type (compact mono vs semantic color band); the shell stays consistent. +
- Grouping: the outer container owns the border and radius; inner rows are separated by
border-tophairlines, rather than each row being its own card.
+ - Status dots: running (pulsing blue) / done (green) / failed (red), sharing one color vocabulary (see §04 tool calls).
Input / Select / Textarea · 表单输入
-统一高度 38px(小尺寸 32px)、圆角 --radius-md、--color-surface-raised 底、统一蓝色焦点环(0 0 0 3px accent-soft)。
Input / Select / Textarea
+Unified 38px height (32px small), --radius-md radius, --color-surface-raised background, and a unified blue focus ring (0 0 0 3px accent-soft).
Code / Diff · 代码与差异
-inline code、代码块、diff 三档均使用等宽字体(--p-font-mono);代码块带文件名标题条与复制按钮;diff 用 + / - 行色表达增删——新增用成功浅底、删除用危险浅底,无渐变。
Code / Diff
+Inline code, code blocks, and diffs all use the monospace font (--p-font-mono). Code blocks have a filename title bar and a copy button. Diffs use + / - row colors to express additions and deletions — additions use a success light background, deletions use a danger light background, with no gradients.
jwt.verify(token) 校验签名,失败返回 401。jwt.verify(token) to verify the signature, returning 401 on failure.import { verify } from './jwt';
@@ -1476,154 +1486,154 @@ export function auth(token: string) {
Dialog · 弹窗
-一套弹窗基元替代 6 套手写实现:统一圆角 --radius-xl、阴影 --shadow-xl、头部 20px、底部操作右对齐、关闭按钮用 IconButton。
Dialog
+One dialog primitive replaces 6 hand-written implementations: unified --radius-xl radius, --shadow-xl shadow, 20px head padding, right-aligned footer actions, and an IconButton close button.
md 440 / lg 640 / xl 760(--p-content-max),按内容分量选择。高度分两种:auto(默认,随内容至 max-height)与 fixed(恒定高度 min(680px, 100vh - 64px),内容超出由 body 内部滚动)。内容型 / 多 tab 弹窗(设置、模型选择、提供方管理、文件夹浏览)一律用 fixed,使框体尺寸恒定、不随切换 tab 或内容多少而跳动;内容少的确认类弹窗保持 auto。
+ Size & height: Dialog offers three widths — md 440 / lg 640 / xl 760 (--p-content-max) — chosen by content weight. Height comes in two kinds: auto (default, grows with content up to max-height) and fixed (constant height min(680px, 100vh - 64px), with overflow scrolled inside the body). Content / multi-tab dialogs (settings, model picker, provider manager, folder browser) always use fixed so the frame size stays constant and doesn't jump when switching tabs or content length; short confirmation dialogs keep auto.
Toast · 轻提示
-统一信息架构:状态图标 + 标题 + 描述。状态色只出现在图标上,避免大面积彩色造成视觉噪音。
+Toast
+Unified information architecture: status icon + title + description. The status color appears only on the icon, avoiding large colored areas that create visual noise.
Spinner · 加载指示器
-加载器按场景分两类,不要混用:
+Spinner
+Loaders fall into two categories by scenario — do not mix them:
-
-
- Spinner(普通 · SVG 环形)—— 默认加载器。用于按钮 loading、应用启动(GlobalLoading)、通用内联等待等「其他所有情况」。 -
- MoonSpinner(月相 · 品牌特色)—— 仅用于「发出消息、等待 Agent 首条响应」这一聊天等待态(ChatPane 的 sending 占位、SideChatPanel、ActivityNotice)。 +
- Spinner (plain · SVG ring) —— the default loader. Used for button loading, app startup (GlobalLoading), and general inline waits — "everything else". +
- MoonSpinner (moon phase · brand signature) —— used only for the chat waiting state of "message sent, waiting for the Agent's first response" (the sending placeholder in ChatPane, SideChatPanel, ActivityNotice).
Spinner · 普通加载器(默认)
+Spinner · plain loader (default)
MoonSpinner · 月相(仅「等待 Agent 响应」)
+MoonSpinner · moon phase (only "waiting for the Agent")
MoonSpinner.vue 与 ActivityNotice.vue 各实现了一遍,应合并为单个 MoonSpinner 组件,尺寸走 token、支持 prefers-reduced-motion。其余所有加载态一律用普通 Spinner。MoonSpinner.vue and ActivityNotice.vue — and should be merged into a single MoonSpinner component, sized via tokens and supporting prefers-reduced-motion. All other loading states use the plain Spinner.Link · 文字链接
-行内文本链接:默认主色、无下划线,hover 显示下划线并加深;.muted 变体用次级文字色。用于文本内跳转、外链、「查看全部」等轻量操作。
Link
+Inline text link: the default is the accent color with no underline; on hover it shows an underline and darkens. The .muted variant uses the secondary text color. Used for in-text jumps, external links, "view all", and other lightweight actions.
Menu / Dropdown · 菜单
-下拉菜单面板:浮起表面 + 描边 + 轻阴影(--shadow-sm,扁平化取向)。菜单项支持图标、当前态(active)、危险态(danger)、禁用态,项与项之间用分隔线分组。触摸 / 移动端用 lg(≥44px 行高)作为菜单项。
Menu / Dropdown
+Dropdown menu panel: raised surface + border + light shadow (--shadow-sm, flat-leaning). Menu items support icons, the current (active) state, the danger state, and the disabled state, with separators grouping items. On touch / mobile, use lg (≥44px row height) for menu items.
SegmentedControl · 分段控件
-互斥的短选项组,常见于「浅色 / 深色 / 跟随系统」这类 2–4 项切换。当前项以浮起表面 + 微阴影突出。
+SegmentedControl
+Mutually exclusive short option groups, commonly used for 2–4 option switches such as "light / dark / follow system". The current item is highlighted with a raised surface + subtle shadow.
Tabs · 标签页
-带底部细线的标签页,用于同级内容的分组切换。当前标签以主色文字 + 主色下划线标示。
+Tabs
+Tabs with a bottom hairline, used for grouping and switching sibling content. The current tab is marked with accent text + an accent underline.
Switch · 开关
-二态开关,用于即时生效的设置项。轨道 36×20、圆角全圆,滑块 16px;开启时轨道变主色、滑块右移,过渡走 token。
+Switch
+A two-state switch for settings that take effect immediately. 36×20 track with full radius, 16px knob; when on, the track turns accent and the knob slides right, with the transition driven by tokens.
Checkbox · 复选框
-17×17 复选框,选中时填充主色并显示白色对勾(inline SVG)。常配合文本标签使用。
+Checkbox
+A 17×17 checkbox. When checked it fills with the accent color and shows a white tick (inline SVG). Often paired with a text label.
Avatar · 头像
-32px 默认头像,圆角 md;.sm 24px。可放首字母或图标,无图片时落回此占位。
Avatar
+A 32px default avatar with md radius; .sm is 24px. Can hold an initial or an icon; falls back to this placeholder when there is no image.
EmptyState · 空状态
-列表 / 面板无内容时的居中占位:48px 淡色图标 + 标题 + 提示,避免空白页。
+EmptyState
+A centered placeholder for empty lists / panels: a 48px faint icon + title + hint, avoiding blank pages.
Divider · 分隔线
-1px 水平分隔线(--p-line);.p-divider-v 为垂直分隔,用于行内元素之间。
Divider
+A 1px horizontal divider (--p-line); .p-divider-v is the vertical divider, used between inline elements.
-
Tooltip · 工具提示
-CSS-only 悬停提示,包在 .p-tip 内。反色底(--p-text / --p-bg),单行不换行,仅承载简短说明。
Tooltip
+A CSS-only hover hint, wrapped in .p-tip. Inverted background (--p-text / --p-bg), single line, no wrapping — carries only short notes.
Banner · 横幅通知
-内联通知条,置于内容区顶部。三态 .info / .warning / .danger,各配同色 18px 图标。
Banner
+An inline notice bar placed at the top of a content area. Three states — .info / .warning / .danger — each with a matching 18px icon.
Sheet / BottomSheet · 底部面板
-移动端底部上滑面板:顶部圆角 xl + drag handle,阴影 xl。≤640px 时弹窗改为锚定底部成 Sheet。
+Sheet / BottomSheet
+A mobile bottom slide-up panel: xl top radius + drag handle, xl shadow. At ≤640px, dialogs become bottom-anchored Sheets.
Skeleton · 骨架屏
-内容加载中的占位,使用呼吸式透明度动画(无渐变),遵守 no-gradient-text 规则。组合成标题 / 文本行 / 头像。
Skeleton
+A placeholder for loading content, using a breathing opacity animation (no gradients), following the no-gradient-text rule. Composed into titles / text lines / avatars.
Command Bar · 命令条
-「主操作 + 命令文本 + 复制」的内联组合,介于按钮与代码块之间,用于安装 / 引导 / 一键执行。主操作复用 Button primary,命令区用 mono 浅灰底。
Command Bar
+An inline combination of "primary action + command text + copy", sitting between a button and a code block — used for install / onboarding / one-click execution. The primary action reuses Button primary; the command area uses a mono light-grey background.
TopBar · 顶部栏
-应用顶部条。默认实色;.frost 变体为半透 + 背景模糊,仅用于吸顶导航栏,是 no-glassmorphism 规则的唯一例外(见 §06)。
TopBar
+The application top bar. Solid by default; the .frost variant is translucent + background blur, used only for sticky navigation bars, and is the sole exception to the no-glassmorphism rule (see §06).
SectionLabel · 分组标题
-侧栏列表的分组小标题,用于为下方内容分区(如侧栏的 Workspaces)。规范:13px / 700 / 大写 / 字距 .08em,色取 --color-fg-faint;左对齐到行的起始内边距(--sb-pad-x),与下方分组行保持同一缩进。中文等无大小写文字下 text-transform:uppercase 自动失效,无需特殊处理。
SectionLabel
+A small group title for sidebar lists, used to section the content below (such as Workspaces in the sidebar). Spec: 13px / 700 / uppercase / letter-spacing .08em, color --color-fg-faint; left-aligned to the row's starting padding (--sb-pad-x), keeping the same indent as the group rows below. For scripts without case (such as Chinese), text-transform:uppercase simply has no effect — no special handling needed.
聊天界面重构
+Chat Interface Overhaul
- 消息流是 Kimi Web 的核心。改造目标:让 6 类卡片(Agent / Tool / Question / Approval / Swarm / Todo) - 共享同一套卡片骨架,仅靠头部图标与语义色区分类型;Composer 收敛为单一圆润容器。 + The message stream is the core of Kimi Web. The goal of the overhaul: have the 6 card types (Agent / Tool / Question / Approval / Swarm / Todo) + share one card skeleton, distinguished only by the head icon and semantic color; and collapse the Composer into a single rounded container.
-统一后的消息流
+Unified message stream
我看了一下 src/auth 的结构,当前是基于 session cookie 的实现。改动范围如下,你确认后我开始动手。
I looked at the structure of src/auth; it is currently based on a session cookie. The scope of the change is below — once you confirm, I'll start.
src/auth/middleware.ts,共 42 行变更。是否允许?src/auth/middleware.ts, 42 lines changed. Allow?工具调用:默认紧凑、分组、按需展开
-read_file / bash / grep 这类高频调用是「操作噪音」——若每条都占一张大卡,并行触发时会迅速淹没对话。
- 新策略按视觉权重分三档,把工具调用压到最轻:
Tool calls: compact by default, grouped, expand on demand
+High-frequency calls like read_file / bash / grep are "operational noise" — if each one took a full card, parallel triggers would quickly drown out the conversation.
+ The new strategy splits tool calls into three tiers by visual weight, pushing them as light as possible:
src/auth/middleware.ts,共 42 行变更。src/auth/middleware.ts, 42 lines changed.-
-
- 工具调用默认渲染为紧凑行(30px 单行 mono + 状态点 + 关键参数),不再有头 / 身 / 阴影。 -
- 连续或并行的调用自动归为一个工具组,折叠时整组只占一行(
N 个工具调用 · 状态)。
- - 点击行就地展开细节(代码 / 输出),再点收起——细节默认不抢视觉。 -
- 状态用颜色点表达:运行中(脉冲蓝)/ 完成(绿)/ 失败(红),不占额外空间。 -
- 仅两类保留完整卡片:
Question(需回答)、Approval(需授权)——它们才真正需要用户注意力。
+ - Tool calls render as compact rows by default (30px single-line mono + status dot + key argument); no head / body / shadow. +
- Consecutive or parallel calls auto-merge into one tool group; when collapsed, the whole group takes one line (
N tool calls · status).
+ - Clicking a row expands it in place to show details (code / output); click again to collapse — details don't grab attention by default. +
- Status is expressed with a colored dot: running (pulsing blue) / done (green) / failed (red), taking no extra space. +
- Only two types keep a full card:
Question(needs an answer) andApproval(needs authorization) — they genuinely need the user's attention.
Composer · 输入框
-统一为单一圆润容器:--radius-xl,聚焦时整体描边变蓝 + 软焦点环。工具条控件全部用 Pill / IconButton 基元,发送按钮 32px 圆形。
Composer
+Unified into a single rounded container: --radius-xl, with the whole border turning blue + a soft focus ring on focus. Toolbar controls all use the Pill / IconButton primitives, and the send button is a 32px circle.
--radius-xl · 16px)与一种高度,工具条控件全部用 Pill / IconButton 基元,发送按钮 32px 圆形——不再随主题漂移。
+ Site-wide consistency: the composer has only one radius (--radius-xl · 16px) and one height; toolbar controls all use the Pill / IconButton primitives, and the send button is a 32px circle — it no longer drifts with the theme.
响应式 Responsive
-断点见 §02 --p-bp-sm。此处仅给出聊天界面的移动端适配指针,完整移动端 mockup 不在本规范范围。
Responsive
+See §02 --p-bp-sm for the breakpoint. This section only gives mobile-adaptation pointers for the chat interface; a full mobile mockup is out of scope for this spec.
主题系统
+Theming
- Kimi Web 使用一套统一主题:同一套组件、字体、圆角、阴影与表面,「换肤」只换颜色。 - 颜色收敛为 4 个种子 token——两个主题色 + 一个亮面 + 一个暗面;中性色与强调色由它们派生, - 语义状态色(success / warning / danger)作为独立调色板与种子配套,亮 / 暗各一套。 + Kimi Web uses one unified theme: the same components, fonts, radii, shadows, and surfaces — "reskinning" only changes colors. + Colors are collapsed into 4 seed tokens — two theme colors + one light surface + one dark surface; the neutrals and accent are derived from them, + and the semantic status colors (success / warning / danger) ship as independent palettes paired with the seeds, one set each for light / dark.
-颜色种子 Color seeds
-日常定制只需调整这 4 个种子,整站的中性色与强调色随之变化:
+Color seeds
+Day-to-day customization only needs these 4 seeds; the whole site's neutrals and accent change with them:
色系切换 Accent families
-一套主题之内,主题色(accent)可在多套色系间切换。当前提供两套并列色系:蓝色系(默认,品牌蓝,承载语义强调)与黑色系(中性黑,承载克制的最强操作)。两套共用同一套组件、字体、圆角与表面——切换色系只换 accent 一组 token,结构零变化;后续可继续扩展(绿 / 紫等)。下面两卡是同一个 primary 按钮在两种色系下的呈现。
Accent families
+Within one theme, the theme color (accent) can switch among several color families. Two parallel families are provided today: blue (default, brand blue, carrying semantic emphasis) and black (neutral black, carrying the most restrained strong action). Both share the same components, fonts, radii, and surfaces — switching families only swaps the accent token set, with zero structural change; more families (green / purple, etc.) can be added later. The two cards below show the same primary button under the two families.
主题控制台 · 改 4 个色,亮/暗一起变
+Theme console · change 4 colors, light & dark change together
亮 / 暗模式
-由 --surface-light / --surface-dark 两个表面驱动:当前用哪个表面,就派生出对应的前景、描边、阴影与状态色。亮 / 暗切换只是在这两组派生 token 之间切换,结构零变化。
Light / dark mode
+Driven by the two surfaces --surface-light / --surface-dark: whichever surface is current derives the corresponding foreground, border, shadow, and status colors. Switching light / dark simply swaps between these two sets of derived tokens, with zero structural change.
样式规则
+Style Rules
- 所有 UI 代码必须遵守的反模式规则。这些规则也是 check-style 检测脚本的依据,逐条对应一条告警。 + Anti-pattern rules that all UI code must follow. These rules are also the basis of the check-style detection script, one-to-one with a warning.
| 规则 ID | 检测内容 | 处置 |
|---|---|---|
| Rule ID | What it detects | Action |
| no-gradient-text | 渐变文字 / 渐变背景 | 禁止 |
| no-glassmorphism | backdrop-filter: blur(TopBar 吸顶导航栏 为唯一例外) | TopBar 除外 |
| no-color-glow | 彩色 / 大半径 box-shadow 发光 | 禁止 |
| no-emoji-icon | 用 emoji 充当功能性图标(月相 🌑…🌘 为唯一豁免,且仅限「等待 Agent 响应」的聊天态;其余加载态用普通 Spinner) | 月相除外 |
| no-hardcoded-hex | 组件 <style> 内出现未登记十六进制色 | 警告 |
| no-hardcoded-font | 组件内硬编码 font-family(如 'Inter')而非 var(--font-ui) | 警告 |
| radius-from-scale | 圆角值不在 {4,6,8,12,16,20,999} 内 | 警告 |
| z-from-scale | z-index 使用未登记的大数字 | 警告 |
| weight-from-scale | font-weight 不在 {400,500} 内 | 警告 |
| no-gradient-text | gradient text / gradient background | Forbidden |
| no-glassmorphism | backdrop-filter: blur (TopBar sticky nav bar is the sole exception) | TopBar exempt |
| no-color-glow | colored / large-radius box-shadow glow | Forbidden |
| no-emoji-icon | using emoji as a functional icon (the moon phases 🌑…🌘 are the sole exception, and only in the "waiting for the Agent to respond" chat state; all other loading states use the plain Spinner) | Moon phase exempt |
| no-hardcoded-hex | unregistered hex color inside a component <style> | Warning |
| no-hardcoded-font | hard-coded font-family in a component (e.g. 'Inter') instead of var(--font-ui) | Warning |
| radius-from-scale | radius value not in {4,6,8,12,16,20,999} | Warning |
| z-from-scale | z-index using an unregistered large number | Warning |
| weight-from-scale | font-weight not in {400,500} | Warning |
状态矩阵 State matrix
-每个可交互基元都应在适用处定义以下状态,缺失即按样式规则告警。focus-visible 一律走 --p-focus-ring(只在键盘聚焦时出现,详见 §08),disabled 统一 opacity:.5。
State matrix
+Every interactive primitive should define the following states where applicable; missing ones are flagged by the style rules. focus-visible always uses --p-focus-ring (appears only on keyboard focus, see §08); disabled is uniformly opacity:.5.
| 状态 State | Button | Input | Card | Menu item | Switch |
|---|---|---|---|---|---|
| State | Button | Input | Card | Menu item | Switch |
| default | ✓ | ✓ | ✓ | ✓ | ✓ |
| hover | ✓ | ✓ | ✓ | ✓ | — |
月相豁免
+Moon phase exemption
MoonSpinner 组件渲染;ActivityNotice 等等待态复用它,不再各自实现月相。
- 它是 no-emoji-icon 规则的唯一例外;其余所有加载态一律用普通 Spinner。
+ The "🌑…🌘" moon-phase emoji are a brand signature of Kimi Web, used only in the chat state of "message sent, waiting for the Agent's first response", and are rendered uniformly by the MoonSpinner component; waiting states such as ActivityNotice reuse it rather than implementing their own moon phase.
+ It is the sole exception to the no-emoji-icon rule; all other loading states use the plain Spinner.
毛玻璃豁免
+Glassmorphism exemption
backdrop-filter: blur 全站禁用,唯一例外是 TopBar 的 .frost 变体——且仅限「吸顶导航栏」这一处,用于在滚动内容上方保持可读。其余任何组件(卡片、弹窗、Toast、面板)一律不得使用毛玻璃,违者按 no-glassmorphism 告警。
+ backdrop-filter: blur is banned site-wide, with the sole exception of the .frost variant of TopBar — and only in the one place of the "sticky navigation bar", used to stay readable over scrolling content. No other component (card, dialog, Toast, panel) may use glassmorphism; violations are flagged under no-glassmorphism.
应用壳与侧栏 App Shell & Sidebar
+App Shell & Sidebar
- 应用壳(三栏网格 + 右侧预览面板)与左侧会话侧栏的结构规范。这些是与具体业务无关的「骨架」, - 组件、字体、圆角、表面都复用 §02 / §03,但布局与对齐有自己的一套约定。 + The structural spec for the app shell (three-column grid + right preview panel) and the left session sidebar. These are business-agnostic "skeletons" — + components, fonts, radii, and surfaces are reused from §02 / §03, but layout and alignment have their own conventions.
-布局网格 Layout grid
-桌面端是一行 5 轨网格,侧栏与右侧面板各占一条永久轨道,中间是会话栏;两条 0 宽轨道给 ResizeHandle 用。
+Layout grid
+On desktop it is a single-row 5-track grid: the sidebar and the right panel each occupy a permanent track, with the conversation column in the middle; two 0-width tracks are for the ResizeHandles.
grid-template-columns: var(--side-w) 0 minmax(0, 1fr) 0 auto; -/* 侧栏 ↑ ↑handle ↑会话栏 ↑handle ↑右面板(auto) */
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --side-w | 248px(可调) | 左侧会话栏宽度,ResizeHandle 拖动改变;应趋近 §02 的 --p-sidebar-w(264px) |
| --preview-w | 460px | 右侧预览面板打开时的宽度 |
| --panel-head-h | 48px | 所有右侧面板头 + 会话栏头部统一高度,使 hairline 连成一线 |
| --p-bp-sm | 640px | ≤640 切为移动端单列(顶栏 + 会话栏),无侧栏/手柄/右面板 |
| --side-w | 248px (adjustable) | left conversation column width, changed by dragging the ResizeHandle; should approach §02's --p-sidebar-w (264px) |
| --preview-w | 460px | width of the right preview panel when open |
| --panel-head-h | 48px | unified height for all right panel heads + the conversation column head, so the hairline runs as one line |
| --p-bp-sm | 640px | ≤640 switches to a mobile single column (top bar + conversation), no sidebar / handle / right panel |
-
-
- 右侧面板轨道永久存在,宽度在
0 ↔ var(--preview-w)间过渡(打开时挤压会话栏,而非切换模板)。
- - 侧栏折叠时,轨道 1 变成一条细「rail」,只放一个展开 IconButton,避免压住会话栏头部。 -
- 所有网格子项须
min-height:0; min-width:0,确保只有内部滚动容器滚动,整页不跟着滚。
+ - The right panel track exists permanently, with its width transitioning between
0 ↔ var(--preview-w)(when open it squeezes the conversation column, rather than switching templates).
+ - When the sidebar is collapsed, track 1 becomes a thin "rail" holding only an expand IconButton, avoiding crushing the conversation column head. +
- All grid children must have
min-height:0; min-width:0, so only the inner scroll containers scroll and the page itself does not scroll.
侧栏对齐系统 Sidebar alignment(--sb-*)
- 侧栏所有行(分组头、会话行、New chat 按钮)共用 3 个自定义属性,让「会话标题」精确对齐到「工作区名称」下方。
+Sidebar alignment system (--sb-*)
+ All sidebar rows (group head, session row, New chat button) share 3 custom properties, so the "session title" aligns precisely under the "workspace name".
| Token | 值 | 用途 |
|---|---|---|
| Token | Value | Usage |
| --sb-pad-x | 16px | 行的水平内边距 |
| --sb-gutter | 20px | 行首图标槽宽(14px 图标 + 6px 留白) |
| --sb-gap | 6px | 图标槽与文字之间的 gap |
| --sb-pad-x | 16px | row horizontal padding |
| --sb-gutter | 20px | leading icon slot width (14px icon + 6px whitespace) |
| --sb-gap | 6px | gap between the icon slot and the text |
--sb-pad-x + --sb-gutter + --sb-gap。分组头有文件夹图标,会话行有状态槽,二者图标同宽、同位,所以标题天然对齐。
+ The session title's starting x = --sb-pad-x + --sb-gutter + --sb-gap. The group head has a folder icon and the session row has a status slot; both icons are the same width and position, so the titles align naturally.
侧栏结构 Sidebar structure
-侧栏自上而下:品牌头 → 搜索 → New chat → 分组列表(工作区头 + 会话行)。控件尽量复用 §03 基元。
+Sidebar structure
+The sidebar from top to bottom: brand header → search → New chat → grouped list (workspace head + session rows). Controls reuse the §03 primitives as much as possible.
| 区块 | 用什么 | 说明 |
|---|---|---|
| Block | Use | Note |
| 品牌头 brand header | logo + 名称 + IconButton | 折叠 / 设置用 IconButton sm;logo 带动画(眼睛眨动) |
| 搜索 search | 裸搜索行(custom) | 无边框、hover/focus 出 sunken 底;图标 + input + 清除 IconButton。不用 Input(38px 带边框太重) |
| New chat | 全宽左对齐按钮(custom) | 与同列表会话行同节奏(左对齐、hover sunken)。不用 Button(居中,破坏节奏) |
| 分组标题 section label | .p-section-label | 「Workspaces」这类大写 muted 小标题 |
| 工作区头 / 会话行 | 见下两节 | 共享 --sb-* 对齐 |
| Brand header | logo + name + IconButton | collapse / settings use IconButton sm; the logo is animated (a blinking eye) |
| Search | bare search row (custom) | no border, hover/focus shows a sunken background; icon + input + clear IconButton. Do not use Input (the 38px bordered version is too heavy) |
| New chat | full-width left-aligned button (custom) | same rhythm as the session rows in the list (left-aligned, hover sunken). Do not use Button (centered, breaks the rhythm) |
| Section label | .p-section-label | uppercase muted small titles like "Workspaces" |
| Workspace head / session row | see next two sections | share --sb-* alignment |
会话行 Session row
-会话行是一个 inset 圆角 pill,结构:状态槽 → 标题 → 时间 → 注意力 Badge → kebab。
Session row
+A session row is an inset rounded pill, structured as: status slot → title → time → attention Badge → kebab.
| 部位 | 规则 |
|---|---|
| Part | Rule |
| 容器 | margin: 1px 6px; padding: 7px 10px; radius-md;hover = surface-sunken;active = accent-soft + inset 0 0 0 1px accent-bd |
| 状态槽 lead | 固定 --sb-gutter 宽;运行中 = Spinner sm,否则未读 = 7px accent 圆点 |
| 标题 title | flex:1 截断;双击进入行间改名(紧凑 input,不用 Input) |
| 时间 time | mono xs、fg-faint;hover 时让位给 kebab |
| 注意力 Badge | Badge sm:info(待回答)/ warning(待审批)/ danger(已中止) |
| kebab | IconButton sm,hover 才显示;下拉用 Menu/MenuItem |
| 归档确认 | 替换标题区,Button sm(danger 确认 / secondary 取消) |
| Container | margin: 1px 6px; padding: 7px 10px; radius-md; hover = surface-sunken; active = accent-soft + inset 0 0 0 1px accent-bd |
| Status slot (lead) | fixed --sb-gutter width; running = Spinner sm, otherwise unread = 7px accent dot |
| Title | flex:1 with truncation; double-click enters inline rename (compact input, not Input) |
| Time | mono xs, fg-faint; yields to the kebab on hover |
| Attention Badge | Badge sm: info (needs answer) / warning (needs approval) / danger (aborted) |
| kebab | IconButton sm, shown on hover; dropdown uses Menu/MenuItem |
| Archive confirmation | replaces the title area, Button sm (danger confirm / secondary cancel) |
工作区分组 Workspace group
-分组头与会话行共用 --sb-*:文件夹图标(开/合)→ 名称 → 路径副标题,hover 露出 kebab 与「+」。
Workspace group
+The group head and session rows share --sb-*: folder icon (open/closed) → name → path subtitle, with the kebab and "+" revealed on hover.
-
-
- 文件夹图标放在
--sb-gutter槽里,开合态切换图标。
- - 名称下方一行
fg-muted的小字路径。
- - kebab(菜单)与「+」(在该工作区新建)都用
IconButtonsm,hover 或键盘聚焦时显示(不 hover 时以opacity:0保留在 tab 序里,保持键盘可达)。
- - 分组可折叠;折叠时隐藏其会话列表。 +
- The folder icon sits in the
--sb-gutterslot, switching icons between open and closed states.
+ - A small
fg-mutedpath line sits below the name.
+ - The kebab (menu) and "+" (new chat in this workspace) both use
IconButtonsm, shown on hover or keyboard focus (when not hovered they stay in the tab order viaopacity:0, keeping them keyboard-reachable).
+ - The group is collapsible; when collapsed its session list is hidden.
拖拽手柄 ResizeHandle
-一条 4px 的竖向拖拽条,叠在 1px 列边框上(margin: 0 -2px 让 4px 整条可抓),hover / 拖拽时变 accent。
ResizeHandle
+A 4px vertical drag bar, layered over the 1px column border (margin: 0 -2px makes the whole 4px grabbable), turning accent on hover / drag.
| 规则 | 值 |
|---|---|
| Rule | Value |
| 宽度 / 光标 | 4px / col-resize |
| 常态 / 激活 | 透明 / accent 填充 |
| 层级 | --z-sticky,盖在列边框上 |
| 行为 | 拖拽时面板宽度 1:1 跟随指针(父级关掉过渡避免 lag);松开后持久化到 localStorage |
| Width / cursor | 4px / col-resize |
| Normal / active | transparent / accent fill |
| Layer | --z-sticky, over the column border |
| Behavior | panel width follows the pointer 1:1 while dragging (the parent disables transitions to avoid lag); on release it is persisted to localStorage |
右侧面板 Right panel
-右侧面板(文件预览 / Diff / 思考 / 子 Agent / 侧聊)共用同一条轨道与同一个头部基元。
+Right panel
+The right panels (file preview / Diff / thinking / sub-agent / side chat) share one track and one head primitive.
-
-
- 面板头用
PanelHeader基元(48px =--panel-head-h),与会话栏头部等高,hairline 连成一线。
- - 面板头:粗体 mono 标题 + 可选 muted 副标题 + 中间 slot(Badge / 控件 / 路径)+ 右侧关闭 IconButton。 -
- 打开时面板宽度从
0 → var(--preview-w),会话栏被平滑挤压。
- - ≤640px 时面板变为全屏覆盖(
position:fixed; inset:0)。
+ - The panel head uses the
PanelHeaderprimitive (48px =--panel-head-h), the same height as the conversation column head, so the hairline runs as one line.
+ - Panel head: bold mono title + optional muted subtitle + middle slot (Badge / control / path) + close IconButton on the right. +
- When opened, the panel width goes from
0 → var(--preview-w), smoothly squeezing the conversation column.
+ - At ≤640px the panel becomes a full-screen overlay (
position:fixed; inset:0).
可访问性 A11y(务实版)
+Accessibility (pragmatic edition)
- Kimi Web 是本地开发者工具,不以 WCAG 某一 conformance 级别为目标,也不维护完整的读屏 QA 矩阵。 - 本节只收「低成本、不损观感、对键盘重度用户也有直接好处」的规则,作为各基元的底线契约; - 其余昂贵且 ROI 偏低的部分(如对流式输出的实时播报编排)暂不作为强制要求。 + Kimi Web is a local developer tool; it does not target a specific WCAG conformance level, nor maintain a full screen-reader QA matrix. + This section collects only the rules that are "low-cost, don't hurt the look, and directly benefit keyboard-heavy users", as the baseline contract for each primitive; + the more expensive, lower-ROI parts (such as real-time announcement orchestration for streaming output) are not mandatory for now.
:focus-visible(而非 :focus)。
- 它只在键盘聚焦时出现,鼠标点击不会触发,因此不会污染鼠标驱动的视觉;环的强弱用 --p-focus-ring 统一调,不逐处覆盖。
+ On the "ugly" focus ring: the focus visibility required below always uses :focus-visible (not :focus).
+ It appears only on keyboard focus; mouse clicks don't trigger it, so it doesn't pollute the mouse-driven visual; the ring's strength is tuned uniformly with --p-focus-ring, not overridden per place.
1. 对比度与颜色 Contrast & color
+1. Contrast & color
-
-
- 正文文本与背景对比度 ≥ 4.5:1;控件边框、图标、关键图形 ≥ 3:1。换主题色 / 暗色模式时按 §05 一起核对。 -
- 状态不只靠颜色传达。错误、选中、禁用等状态要同时有文字、图标或形态变化(例如错误态不只红,还带文案或图标)。 +
- Body text vs. background contrast ≥ 4.5:1; control borders, icons, and key graphics ≥ 3:1. When changing theme colors / dark mode, verify against §05 together. +
- Button text vs. button background, and form controls (input, placeholder, helper / error text) vs. their section background must all have contrast ≥ 4.5:1 (large text ≥ 3:1). White-on-white text, a transparent borderless button floating over the page background, and a light placeholder on a near-white background are all flagged by the style rules. +
- State is not conveyed by color alone. Error, selected, and disabled states also carry text, an icon, or a shape change (for example an error state is not just red, but also carries text or an icon).
2. 键盘可操作 Keyboard operable
-鼠标能完成的操作,键盘必须也能完成;Tab 顺序跟随 DOM,不另造跳序。复合控件按下表定义键盘模型,缺失即视为不完整:
+2. Keyboard operable
+Anything doable with a mouse must also be doable with a keyboard; Tab order follows the DOM, with no invented skipping. Composite controls define their keyboard model per the table below; a missing model is treated as incomplete:
| 控件 | 键盘行为 |
|---|---|
| Control | Keyboard behavior |
| Dialog | Tab 在弹窗内循环(焦点锁);Esc 关闭;关闭后焦点回到触发元素。 |
| Menu | ↑ / ↓ 移动高亮,Enter 选中,Esc 关闭。 |
| Tabs | ← / → 切换标签(roving tabindex),只有当前标签在 Tab 序列里。 |
| Switch / Segmented | ← / → 或 Space / Enter 切换。 |
| Dialog | Tab cycles within the dialog (focus trap); Esc closes; focus returns to the trigger element after closing. |
| Menu | ↑ / ↓ move the highlight, Enter selects, Esc closes. |
| Tabs | ← / → switch tabs (roving tabindex); only the current tab is in the Tab sequence. |
| Switch / Segmented | ← / → or Space / Enter to toggle. |
3. 焦点可见 Focus visibility
+3. Focus visibility
-
-
- 每个可交互元素在键盘聚焦时必须有可见焦点指示,统一走
:focus-visible+--p-focus-ring(主操作可用--p-focus-ring-strong)。
- - 禁止裸
outline: none。要去掉默认轮廓,必须同时给出等价的替代样式。
+ - Every interactive element must have a visible focus indicator on keyboard focus, uniformly via
:focus-visible+--p-focus-ring(primary actions may use--p-focus-ring-strong).
+ - Bare
outline: noneis forbidden. To remove the default outline, you must provide an equivalent replacement style.
4. 命名与语义 Labels & semantics
+4. Labels & semantics
-
-
- 语义 HTML 优先(button / a / input / dialog…),ARIA 只在原生语义不够时补。 -
- 只有图标的按钮必须有
aria-label——IconButton已用必填的labelprop 强制。
- - 弹窗:
role="dialog"+aria-modal="true",标题作为对话框的可访问名称。
- - 纯装饰性 SVG / 图标加
aria-hidden="true",避免被读屏念出。
+ - Semantic HTML first (button / a / input / dialog…); ARIA is added only when native semantics fall short. +
- Icon-only buttons must have an
aria-label—IconButtonalready enforces this with a requiredlabelprop.
+ - Dialog:
role="dialog"+aria-modal="true", with the title as the dialog's accessible name.
+ - Purely decorative SVG / icons get
aria-hidden="true"to avoid being read out by screen readers.
5. 目标尺寸 Target size
-桌面可点击目标 ≥ 32px;触摸设备 ≥ 44px(与 §01 原则、IconButton 的 lg 档一致)。
5. Target size
+Desktop click targets ≥ 32px; touch devices ≥ 44px (consistent with the §01 principle and the IconButton lg tier).
6. 减少动态效果 Reduced motion
-统一在全局样式按 §02 的 @media (prefers-reduced-motion: reduce) 处理,组件不各自判断;MoonSpinner 月相在当前帧暂停。
6. Reduced motion
+Handled uniformly in the global styles per §02's @media (prefers-reduced-motion: reduce); components do not check this individually. The MoonSpinner moon phase pauses on the current frame.
7. 动态内容播报 Live announcements(非强制)
-读屏播报在本产品里不做强制契约。Toast 这类短提示用 role="status" / aria-live 即可;聊天流式输出当前不做逐字播报,属可接受取舍,后续如有真实需求再补。
7. Live announcements (non-mandatory)
+Screen-reader announcements are not a mandatory contract in this product. Short hints like Toast can use role="status" / aria-live; chat streaming output is currently not announced word-by-word, which is an acceptable trade-off, to be added later if a real need arises.