From 1472f25dbf22e0d10d17c956bb0b538b9c531dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E5=8F=8A?= <522caiji@gmail.com> Date: Sun, 30 Aug 2026 01:11:14 +0800 Subject: [PATCH 1/3] feat: restyle the console on HeroUI v3 default tokens and compound primitives --- CHANGELOG.md | 2 + docs/DESIGN.md | 279 +++----- frontend/index.html | 4 +- frontend/src/components/AddAccountModal.tsx | 98 +-- frontend/src/components/BrandMark.tsx | 2 +- frontend/src/components/ModelDetailsModal.tsx | 16 +- frontend/src/components/RequireAuth.tsx | 2 +- .../src/components/account/AccountCard.tsx | 85 ++- .../components/account/AccountModelsModal.tsx | 46 +- .../components/account/EditAccountModal.tsx | 16 +- .../src/components/account/QuotaMeter.tsx | 118 +--- frontend/src/components/layout/AppHeader.tsx | 10 +- frontend/src/components/layout/AppLayout.tsx | 3 +- frontend/src/components/layout/AppSidebar.tsx | 30 +- .../src/components/overview/TrafficChart.tsx | 28 +- frontend/src/components/ui/CompactSwitch.tsx | 99 +-- frontend/src/components/ui/ConfirmDialog.tsx | 54 ++ frontend/src/components/ui/EmptyPanel.tsx | 27 + frontend/src/components/ui/FilterSelect.tsx | 6 +- frontend/src/components/ui/FilterToggle.tsx | 44 ++ frontend/src/components/ui/ListPager.tsx | 107 ++- frontend/src/components/ui/OptionTiles.tsx | 82 +-- frontend/src/components/ui/PageAlert.tsx | 21 + frontend/src/components/ui/PageSkeletons.tsx | 44 +- frontend/src/components/ui/SearchBar.tsx | 30 + frontend/src/hooks/useTheme.tsx | 8 +- frontend/src/index.css | 657 ++---------------- frontend/src/pages/AccessPage.tsx | 103 ++- frontend/src/pages/AccountsPage.tsx | 141 ++-- frontend/src/pages/KeysPage.tsx | 112 ++- frontend/src/pages/LoginPage.tsx | 54 +- frontend/src/pages/LogsPage.tsx | 286 ++++---- frontend/src/pages/OverviewPage.tsx | 147 ++-- frontend/src/pages/ProvidersPage.tsx | 47 +- frontend/src/pages/SystemPage.tsx | 130 ++-- .../webui/static/assets/index-DcalnZVD.css | 2 + .../webui/static/assets/index-Do7_hBRL.js | 28 + .../webui/static/assets/index-DoZvvmrR.css | 2 - .../webui/static/assets/index-bG_dUq1A.js | 28 - internal/webui/static/index.html | 8 +- 40 files changed, 1208 insertions(+), 1798 deletions(-) create mode 100644 frontend/src/components/ui/ConfirmDialog.tsx create mode 100644 frontend/src/components/ui/EmptyPanel.tsx create mode 100644 frontend/src/components/ui/FilterToggle.tsx create mode 100644 frontend/src/components/ui/PageAlert.tsx create mode 100644 frontend/src/components/ui/SearchBar.tsx create mode 100644 internal/webui/static/assets/index-DcalnZVD.css create mode 100644 internal/webui/static/assets/index-Do7_hBRL.js delete mode 100644 internal/webui/static/assets/index-DoZvvmrR.css delete mode 100644 internal/webui/static/assets/index-bG_dUq1A.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6cf54f..c04ee1b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ 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 - 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 +16,7 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`. ### 中文 +- 控制台改走 HeroUI v3 默认 token 和复合原语,去掉象牙色覆盖、自定义 32px 控件,以及手写的提示、搜索、分页和空状态 - Logs 和模型页的筛选下拉改用紧凑 HeroUI Select,高度对齐 32px 工具栏 - 新增可限制供应商的客户端 API 密钥,并在系统页显示控制台管理员密钥 - 客户端密钥未限制供应商时写入 `[]`,不再存成 JSON `null` diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 0fc06dc8..97410d60 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -1,214 +1,156 @@ # CLI2API 前端设计规范 -本项目是纯已登录控制台应用(登录页 + 内部页面),基于 React、Vite、HeroUI v3、Tailwind v4 和 Phosphor 图标。前端改动应保持现有安静、功能导向、暖白象牙色的界面风格。不要为单个功能引入新的视觉语言。 +本项目是纯已登录控制台应用(登录页 + 内部页面),基于 React、Vite、**HeroUI v3**、Tailwind v4 和 Phosphor 图标。前端视觉以 [HeroUI](https://www.heroui.com/docs/react/components) 的默认主题、语义 token 和复合原语为准。不要为单个功能发明第二套颜色、圆角或控件高度。 ## 唯一真相来源 -- 全局主题 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`。只允许在 [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`,不要混入其他图标库。 ## 视觉方向 -应用整体应给人以下感觉: +控制台应对齐 HeroUI 文档站点的产品 UI,而不是营销页: -- 安静、紧凑、功能导向 -- 暖白底色,而非冷灰 -- 默认低对比度,直到需要聚焦/操作时才提升 -- 实用优先于装饰 -- 通过阴影微微抬升层次,而非用粗边框 +- 冷中性灰表面(`--background` / `--surface`),不是暖象牙色 +- 主操作走 `--accent`(HeroUI 默认蓝),不是墨色填充按钮 +- 成功 / 就绪走 `--success`,警告走 `--warning`,破坏走 `--danger` +- 圆角跟 HeroUI:按钮接近胶囊(`rounded-3xl`),卡片 `min(32px, var(--radius-3xl))`,字段 `--field-radius` +- 控件用 HeroUI 默认尺寸:按钮 `size="sm"` 在桌面约 32px,默认 `md` 约 36px;不要再压成自定义 32px 工具栏 +- 实用优先于装饰;不要毛玻璃、光斑、彩色堆叠面板或套娃卡片 避免: -- 在应用壳里搞营销页式布局 -- 彩色堆叠面板 -- 套娃卡片 -- 无意义的渐变 -- 在 dashboard 界面里放大号标题排版 -- 毛玻璃、光斑/球体、装饰性色块 -- 为每个功能都加一个新强调色 +- 在应用壳里搞营销页式大标题 +- 自定义 `--app-*` 色板盖住 HeroUI token +- 手写红框、手写进度条、手写分页,而 HeroUI 已有 `Alert` / `Meter` / `Pagination` +- 原生 `type="number"`、原生 ` - + {({ defaultChildren, isPlaceholder }) => { @@ -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')}