diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6cf54f..5db1ed6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`. ### English +- Restyle the console on HeroUI v3 default tokens and compound primitives, replacing the ivory overlay, custom 32px chrome, and hand-rolled alerts, search, pagination, and empty states +- Lock console selection, radii, and type to one language: accent-soft selected chrome, Outfit + IBM Plex Mono, and ink-plus-cyan brand marks instead of mixed blue / white / violet fills +- Show HeroUI skeletons on first page load and on refresh or filter fetches, instead of a session spinner or leftover dashes +- Replace the hand-drawn Overview traffic SVG with a Recharts area chart on HeroUI tokens, and keep the GSAP line-draw entrance +- Strip leftover marketing chrome: login kickers, always-on status dots, colored left bars, and uppercase micro-labels - Replace native Logs and Models filter dropdowns with compact HeroUI Select controls that match the 32px toolbar - Add named client API keys with optional provider allowlists, and show the console administrator key on System - Store an empty client-key provider allowlist as `[]` instead of JSON `null` @@ -15,6 +20,11 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`. ### 中文 +- 控制台改走 HeroUI v3 默认 token 和复合原语,去掉象牙色覆盖、自定义 32px 控件,以及手写的提示、搜索、分页和空状态 +- 选中态、圆角和字体锁成一套:选中走 accent-soft,界面 Outfit + IBM Plex Mono,品牌 mark 改为墨色闪电加青点,不再混用蓝 / 白 / 紫填充 +- 第一次进入页面、刷新和打接口的筛选改走 HeroUI 骨架,不再用登录转圈或留下一排破折号 +- 总览流量图改用 Recharts 面积图,颜色走 HeroUI token,入场仍用 GSAP 描线 +- 去掉登录页 kicker、常亮状态点、彩色左边条和全大写微标签 - Logs 和模型页的筛选下拉改用紧凑 HeroUI Select,高度对齐 32px 工具栏 - 新增可限制供应商的客户端 API 密钥,并在系统页显示控制台管理员密钥 - 客户端密钥未限制供应商时写入 `[]`,不再存成 JSON `null` diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 0fc06dc8..5d79b373 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -1,214 +1,229 @@ # CLI2API 前端设计规范 -本项目是纯已登录控制台应用(登录页 + 内部页面),基于 React、Vite、HeroUI v3、Tailwind v4 和 Phosphor 图标。前端改动应保持现有安静、功能导向、暖白象牙色的界面风格。不要为单个功能引入新的视觉语言。 +本项目是纯已登录控制台应用(登录页 + 内部页面),基于 React、Vite、**HeroUI v3**、Tailwind v4 和 Phosphor 图标。前端视觉以 [HeroUI](https://www.heroui.com/docs/react/components) 的默认主题、语义 token 和复合原语为准。不要为单个功能发明第二套颜色、圆角、字体或控件高度。 -## 唯一真相来源 +Reading this as: self-hosted ops console for operators, with a HeroUI-default product language, cold gray surfaces, one blue accent, Outfit + IBM Plex Mono. -- 全局主题 token 在 [frontend/src/index.css](../frontend/src/index.css)。 -- 对话框、提示、卡片、Chip、Drawer、表单等可访问 UI 场景,**强制**用 `@heroui/react` 的 HeroUI 原语。没有对应组件时,再查 shadcn MCP / 官方目录找等价物;最后才允许手写。 -- 当前项目直接使用 `@heroui/react` 原语;布局与复用组件位于 `frontend/src/components/`。 -- 主题 token 与视觉变量统一维护在 [frontend/src/index.css](../frontend/src/index.css)。 +## 唯一真相来源 -- 图标用 `@phosphor-icons/react`,不要混入其他图标库,除非项目中没有等效图标。 +- 主题来自 `@heroui/styles` 的 default light/dark。只允许在 [frontend/src/index.css](../frontend/src/index.css) 里设字体、控制台特有的状态点 / 运行时柱 / 发行说明排版,以及下文「选中态」那两处胶水。不要覆盖 `--accent`、`--background`、`--radius` 或按钮高度。 +- 对话框、提示、卡片、Chip、Drawer、表单、搜索、分页、空状态、开关、Meter 等可访问 UI **必须**用 `@heroui/react`。没有对应组件时,再查 [HeroUI 组件目录](https://www.heroui.com/docs/react/components);最后才允许手写,并在 PR 里写明缺的是哪个原语。 +- 图标用 `@phosphor-icons/react`,不要混入其他图标库。 +- 颜色、圆角、字号一律走语义 token / Tailwind 映射(`bg-surface`、`text-muted`、`rounded-lg`)。禁止 `text-[var(--muted)]`、一次性 hex、页面私有色板。 ## 视觉方向 -应用整体应给人以下感觉: +控制台对齐 HeroUI 文档站点的产品 UI,而不是营销页: -- 安静、紧凑、功能导向 -- 暖白底色,而非冷灰 -- 默认低对比度,直到需要聚焦/操作时才提升 -- 实用优先于装饰 -- 通过阴影微微抬升层次,而非用粗边框 +- 冷中性灰表面(`--background` / `--surface`),不是暖象牙色、不是紫 +- 唯一交互强调色是 `--accent`(HeroUI 默认蓝,约 `#0485F7`) +- 成功 / 就绪走 `--success`,警告走 `--warning`,破坏走 `--danger` +- 圆角跟下面的四档尺度,不要页面各画一套 +- 控件用 HeroUI 默认尺寸:按钮 `size="sm"` 在桌面约 32px,默认 `md` 约 36px +- 实用优先于装饰;不要毛玻璃、光斑、彩色堆叠面板或套娃卡片 避免: -- 在应用壳里搞营销页式布局 -- 彩色堆叠面板 -- 套娃卡片 -- 无意义的渐变 -- 在 dashboard 界面里放大号标题排版 -- 毛玻璃、光斑/球体、装饰性色块 -- 为每个功能都加一个新强调色 +- 在应用壳里搞营销页式大标题 +- 自定义 `--app-*` 色板盖住 HeroUI token +- 手写红框、手写进度条、手写分页,而 HeroUI 已有 `Alert` / `Meter` / `Pagination` +- 原生 `type="number"`、原生 ` - - + + {({ defaultChildren, isPlaceholder }) => { const selected = typeOptions.find((option) => option.value === accountType) @@ -464,10 +465,10 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) { - + {typeOptions.map((option) => ( - + {option.icon}
@@ -481,7 +482,7 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) { ) : ( <> - {t('accountType')} + {t('accountType')} )} - {typesReady && hint ?

{hint}

: null} + {typesReady && hint ?

{hint}

: null}
@@ -506,16 +507,16 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) { type="button" onClick={() => setAdvancedOpen((open) => !open)} aria-expanded={advancedOpen} - className="inline-flex items-center gap-1 text-xs font-medium text-[var(--app-muted)] transition-colors hover:text-[var(--app-ink)]" + className="inline-flex items-center gap-1 text-xs font-medium text-muted transition-colors hover:text-foreground" > {t('wizardAdvanced')} {advancedOpen ? ( -
+
{showDropSystem ? (
-
{t('dropSystemPrompt')}
-

{t('dropSystemPromptCreateHint')}

+
{t('dropSystemPrompt')}
+

{t('dropSystemPromptCreateHint')}

) : ( <> -
+
-
{activeOption ? optionLabel(activeOption, t) : t('accountType')}
-
{name.trim() || t('account')}
+
{activeOption ? optionLabel(activeOption, t) : t('accountType')}
+
{name.trim() || t('account')}
-
- {methodOptions.map((option) => ( - - ))} -
- -

{tabLead}

+ { + if (!busy && next !== tab) { + setTab(next as TabKey) + setMessage('') + setAuthUrl('') + } + }} + ariaLabel={t('authentication')} + options={methodOptions.map((option) => ({ + id: option.value, + label: option.label, + icon: option.icon, + }))} + /> + +

{tabLead}

{tab === 'browser' ? ( <> {authUrl ? ( -
+
- {message || t('loginOpenMsg')} + {message || t('loginOpenMsg')}
-
) : null} {message && !authUrl ? ( -

{message}

+

{message}

) : null} {showCallbackPaste ? (
-

{t('wizardCallbackLead')}

+

{t('wizardCallbackLead')}