Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# DESIGN.md — Qoder 网关看板 界面方向

> 全站唯一 token 契约。任何页面复用同一套 `--*` 变量、同一字族、同一部件语言;
> 新增 token 先加到这里,不在页面里发明一次性颜色 / 圆角 / 阴影 / 间距。
> 依据团队的设计纪律与交付清单:先立契约、再写界面、最后逐条自查。

## 产品语义与方向

- 产品一句话:管理本机 Qoder 反代网关的运行面板——给运维/自用者看账号、密钥、路由与用量。
- 它世界里已有的物件:账号卡片(昵称 / UID / 区域 / 积分)、API Key 行、路由优先层、
用量桶(10 分钟粒度)、日志行、签到流水、兑换码。
- 因此方向是「**运维台账**」:纸面底色、细线分格、数据表与字段对齐是第一公民,
页头像一张单据的抬头;一屏能看到「现在是否正常、哪一项动了」。
- 它明确不是:营销首页、SaaS 控制台 cosplay、玻璃拟态仪表盘。
- 参考与取舍:CPAMC 官方管理中心(暖纸浅色 / 暖灰深色、数据密度)取其纸面与密度;
旧版 shadcn 风格层取其表格结构。不抄 hex、版式坐标与插画。

## 色板(角色固定,值可调)

| 角色 | 浅色 | 深色 | 用途 | 对 ground 对比度(浅 / 深) |
| --- | --- | --- | --- | --- |
| ground | `#faf9f5` | `#151412` | 页面底 | — |
| surface | `#f0eee8` | `#1d1b18` | 卡片 / 面板 / 表格容器 | 1.07 / 1.16(非文字) |
| surface-2 | `#f6f4ee` | `#191714` | 表头、输入底、次级面 | — |
| ink | `#2d2a26` | `#f6f4f1` | 主文字与主按钮底 | 13.6 / 15.1 |
| muted | `#6d6760` | `#c9c3bb` | 次要文字、表头、说明 | 5.3 / 10.5 |
| line | `#e3e1db` | `#3a3530` | 1px 分格线 | 非文字 |
| pass | 文 `#0f7a55` · 图 `#10b981` | 文 `#3fcf9f` · 图 `#0fae78` | 只表示「通过 / 成功」 | 4.6 / 9.8 |
| fail | 文 `#a53a2b` · 图 `#c65746` | 文 `#e6796a` · 图 `#cf4b3a` | 只表示「失败 / 故障」 | 5.6 / 6.4 |
| warn | 文 `#8a5a12` | 文 `#e6b45f` | 只表示「需要注意」 | 5.1 / 9.4 |
| accent | `#5f5a54` | `#d8d2ca` | 唯一职责:选中 / 当前项 | 6.5 / 11.9 |

- 动作色 = ink(主按钮是墨色块),accent 不再兼任按钮色;状态色(pass/fail/warn)
只表达状态,不用于 CTA。
- 图表:成功率/失败用 pass/fail 图形色;其余序列用 ink 与 muted 的明度台阶,
不再引入独立色相(旧的 `#38bdf8`、`#3b82f6` 已移除)。
- 文字对比度全部按上表算过;muted 不低于 4.5:1,`--text-quaternary` 只给线与禁用态,
不承载正文。

## 字体与数据

- 唯一字族:`--font-ui` = Segoe UI Variable / Segoe UI + PingFang SC / 微软雅黑。
这是本机运维面板,**不发布 webfont**(离线优先、首屏零字体请求),所以选系统脸而不是
声明一个装不上的字族;标题同族,靠字重与字阶拉开层级。
- 等宽 `--font-mono` 只给代码、模型 ID、日志、路径与要对齐的数字。
- 数字:`font-variant-numeric: tabular-nums`;金额/百分比列 `white-space: nowrap`。
- 字阶:页面标题 22–28 / 650;区块标题 15 / 650;面板标题 16 / 650;正文 13.5 / 400;
元信息 12 / 400。不做全大写眉标、不做字距 1.6px 的 mono 小标签。

## 布局与部件

- 骨架:吸顶页头(标题 + 页签同排,≥861px 不换行;更窄时页签变成可横滑的一行)
→ 内容区 `max-width:1440px` → 每页一个 `.admin-page-heading` 抬头,下方是区块。
- 侧栏:宽屏每页左侧页内导航 186px(标题 2/12 留白、项距 8px、项内 10/12、收起按钮与
「回到顶部」之间 4px),可收起;窄屏变成横向胶囊行。
- 吸附:账号页筛选栏吸附时贴着页头底边(`top = 页头高`,通栏、无圆角),
与页头之间不留缝;左栏导航吸附则留 14px 呼吸(两者不是同一个东西)。
- Hero 脉搏线只画在左侧判词下方(右侧 42% 起让位),不横穿到数字卡下面被压住。
- 表格:表头 11.5px / muted / 无全大写;行高 36–44px;数字列右对齐 + tabular-nums;
宽表外包 `.table-wrap` 只在数据区内部横向滚动。
- 徽标:`.badge` 胶囊(状态/标签专用);卡片、面板、区块 = 10/12px 圆角;
控件 = 6px 圆角;浮层(弹窗)= 14px 圆角。圆角表达层级,不是一套到底。
- 阴影:平层不用阴影(只留 1px 线);只有浮层(弹窗、下拉菜单)用 `--elev-overlay`。
- 交互:按钮 hover 只变底色/描边,不缩放、不抬升、不发光;`prefers-reduced-motion`
全局豁免;焦点用 2px 实色 `:focus-visible` 轮廓(offset 2px)。

## 统一组件(本轮替换原生 HTML 的部分)

- `.modal-mask > .modal`(含 `.modal-hd/.modal-bd/.modal-ft`):唯一弹窗。
统一控制器 `uiOpenModal(id)` / `uiCloseModal(id)`:
焦点入窗、Tab 圈定、Esc 与遮罩关闭、关闭后焦点还给触发者、`body` 锁滚动。
原生 `<dialog>` 已全部改成这一套。
- `.ui-select`:唯一下拉。原生 `<select>` 保留为状态与取值来源(`select.value`、
`onchange` 均照旧),外面套一层 listbox 触发器 + 菜单,键盘支持
↑/↓/Home/End/Enter/Esc/首字母跳选。原生 `<select>` 弹出层不再露脸。
- `uiConfirm()` / `uiPrompt()`:替代原生 `confirm()` / `prompt()`,返回 Promise,
外观与弹窗一致,并在调用处用 `await`。
- 右上主题/语言菜单沿用 `.theme-dropdown` 的部件语言(与 `.ui-select` 同圆角与间距)。
- 统计区间 `.seg`:选中态底色由**按钮自己**承载(墨色块 + 纸色字),不再依赖 JS 把滑动药丸
定位到按钮下方——首帧、取数失败、`prefers-reduced-motion` 下选中的标签都读得见。
- 路由编排的层编号改回文档流(编号 + 层名 + 优先级 + 状态同一基线),不再用绝对定位压在层名输入框上。

## 三态契约

- 取数区块:`正在读取…` 骨架 / 空态一句原因 / 失败一句原因 + 重试按钮,互斥;
状态区 `role="status"` + `aria-live="polite"`,错误再包 `role="alert"`。
- 过期响应不得覆盖新状态:页内已有 `seq`/失效旗标或 `CP_OVERVIEW_INFLIGHT` 的沿用。
- **轮询只表达变化**:5s / 15s 定时刷新走 `uiSetHTML()` 差异更新——算出的 HTML 与上次相同就
不碰 DOM(表格不重建、行内入场动画不重放、滚动位置不被拽走、卡片不闪);数据真变了才替换。
页内表格行不再挂一次性入场动画的循环版本(账号表的 `acctRowIn` 已撤)。

## 动效语言

- 只有两类:页面/弹窗一次性入场(190ms,ease-out),以及真实变化(图表高度、进度条)。
- 全部 `cubic-bezier(.23,1,.32,1)` 类无过冲缓动;删掉 hover 抬升/缩放、彩色辉光、
全站 transition 长尾。
- 例外:hero 的「已处理请求」保留官方 CPAMC 的 900ms 计数值过渡
(`tests/_test_admin_overview.py` 把这条节奏当成契约)。它只作用于这一个元素,
不做全站 count-up;`prefers-reduced-motion` 下直接落值。
- 所有动效都在 `prefers-reduced-motion: reduce` 下停用。

## 禁用清单(生成时逐条自查)

- Inter / JetBrains Mono / 未发布的 webfont;全大写眉标与 mono 小标签;
- 紫/蓝渐变、渐变文字、彩色辉光阴影、彩色侧边条;
- `border-radius` 一套到底、`shadow-lg` 满地、`backdrop-filter` 满地
(只留吸顶页头这一处真实层叠);
- 居中 hero + 徽章、三张同宽图标卡、emoji / unicode 字形当图标、CTA 焊 `→`;
- 卡片 hover 抬升、`scale` 按压、count-up 数字、bounce/elastic;
- 原生 `<dialog>` / `<select>` / `confirm()` / `prompt()`(一律走统一组件);
- 页面内一次性颜色/圆角/间距;`body{overflow-x:hidden}` 掩盖破版。

## 可访问性底线

- `:focus-visible` 全局 2px 实色轮廓、offset 2px;弹窗焦点圈定 + 归还;
- muted 正文 ≥ 4.5:1;状态不只靠颜色(徽标带文字);表格表头与单元格同轴;
- 表单 label 在控件上方或 `aria-label`;图标按钮有 `aria-label`;
- 触控目标 ≥ 32px(桌面面板),窄屏按钮不并排挤压到 28px 以下。

## 尺寸与响应式

- 375 / 768 / 1280 三宽度与 80%–200% 缩放:页面级 `scrollWidth - clientWidth ≤ 0`;
横向滚动只出现在 `.table-wrap` 内部;栅格 `minmax(0,·)`,flex 子项 `min-width:0`。

## 保留的 4 处视觉取舍(逐条看过,理由是内容而不是默认)

自查结果:约定项全部落实。剩下 4 处是有意保留的取舍:

- **选中 / 焦点环的细圈**:只保留选中态、焦点环与图表端点的 `0 0 0 Npx` 圈(表达层级与位置),
装饰性辉光(状态点发光、画面泛光)已全部去掉。
- **中点元信息**:`v1.9.5 · 已连接 · 16:05`、`滚动窗口 6 小时 · 每桶 10 分钟` 这类
「值 · 值 · 值」是数据分隔,拆成句子反而更难扫读;不是标题里的装饰性 `A · B · C`。
- **等宽小标签**:mono 只出现在账号 UID / API Key id / 路径 / 日志行这些真数据上,
正文与标签已全部回到 `--font-ui`。
- **状态绿**:绿色只表示「成功 / 可用」状态,主行动是墨色、accent 是选中色;
没有把绿当全站唯一强调色。
Loading