diff --git a/docs/theme.md b/docs/theme.md
index 0eb785deb..93bf770ff 100644
--- a/docs/theme.md
+++ b/docs/theme.md
@@ -90,12 +90,12 @@
```mermaid
flowchart LR
- A[Pinia 持久化配置] --> B[resolveTheme]
+ A[Pinia 持久化配置] --> B[createTheme]
B --> C[Seed Token]
C --> D[Map Token]
D --> E[Alias Token]
E --> F[Component Token]
- F --> G[#cp-runtime-theme]
+ F --> G[#z-runtime-theme]
G --> H[Vue / Tailwind / ECharts]
B --> I[Theme Editor 草稿]
@@ -119,7 +119,7 @@ flowchart LR
[SDK 页面与宿主桥](../backend/crates/gateway-plugin/sdk/docs/capabilities.md#页面宿主桥-v2)。
`theme/` 根目录只保留公开入口 `index.ts` 和唯一类型文件 `types.ts`;内部实现按 `core/`、`derive/`、`runtime/` 分层,不增加嵌套 barrel。
纯派生模块不访问 DOM,`theme/runtime/browser.ts` 不包含派生规则,Theme Store 不复制算法。
-普通 Map 字段按 camelCase → kebab-case 统一生成 `--cp-*`;Semantic 与 Preset Color 仅维护各自的短角色表。
+普通 Map 字段按 camelCase → kebab-case 统一生成 `--z-*`;Semantic 与 Preset Color 仅维护各自的短角色表。
`ThemeTokenName` 在 `types.ts` 中由 Map 契约推导,无需手写重复的联合类型和对象映射
下文未带宿主路径的 `theme/`、`styles/` 均指 `codex-proxy-ui/src/` 下的目录,联调入口见[开发文档](development.md#源码联调)
@@ -215,20 +215,20 @@ Quaternary;主按钮白字与功能色文字遵循各自的容器配对规则
### Alias Token
-Alias 按视觉角色命名,使用 `--cp-` 命名空间;整体分层对齐 Ant Design,并以 Container / On Container 表达成对的
+Alias 按视觉角色命名,使用 `--z-` 命名空间;整体分层对齐 Ant Design,并以 Container / On Container 表达成对的
语义表面与前景:
| 角色 | CSS Token | 主要消费者 |
| --- | --- | --- |
-| 品牌交互 | `--cp-color-primary*` | 主操作、选中态、焦点与强调 |
-| 链接 | `--cp-color-link*` | 普通文本链接 |
-| 表面 | `--cp-color-bg-*` | 页面、容器、浮层和遮罩 |
-| 填充 | `--cp-color-fill-*` | 轨道、弱背景和静态层级 |
-| 文字 | `--cp-color-text*` | 标题、正文和辅助信息 |
-| 选择 | `--cp-control-item-bg-active*` | Segmented、Select 和选择控件 |
-| 焦点 | `--cp-control-outline` | 键盘焦点和输入反馈 |
-| 功能色 | `--cp-color-info / success / warning / error-*` | 系统反馈与状态 |
-| 预设彩色 | `--cp-color-{blue,cyan,green,orange,purple,red}-{container,container-strong,border,solid,text,on-container}` | 分类标签与数据强调 |
+| 品牌交互 | `--z-color-primary*` | 主操作、选中态、焦点与强调 |
+| 链接 | `--z-color-link*` | 普通文本链接 |
+| 表面 | `--z-color-bg-*` | 页面、容器、浮层和遮罩 |
+| 填充 | `--z-color-fill-*` | 轨道、弱背景和静态层级 |
+| 文字 | `--z-color-text*` | 标题、正文和辅助信息 |
+| 选择 | `--z-control-item-bg-active*` | Segmented、Select 和选择控件 |
+| 焦点 | `--z-control-outline` | 键盘焦点和输入反馈 |
+| 功能色 | `--z-color-info / success / warning / error-*` | 系统反馈与状态 |
+| 预设彩色 | `--z-color-{blue,cyan,green,orange,purple,red}-{container,container-strong,border,solid,text,on-container}` | 分类标签与数据强调 |
Alias 不在页面中追加修色;中性与彩色文字在派生层执行各自的背景配对约束。Component
Token 直接覆盖时不会自动重算同组件的其他状态;需要保持梯度关系时应修改 Seed,而不是逐个覆盖 Map Token
@@ -239,16 +239,16 @@ Token 直接覆盖时不会自动重算同组件的其他状态;需要保持
| 组件 | 代表 Token |
| --- | --- |
-| Button | `--cp-button-primary-color / bg / hover-bg / active-bg`、`--cp-button-secondary-bg / hover-bg / active-bg` |
-| IconButton | `--cp-icon-button-secondary-bg / hover-bg / active-bg` |
-| Input | `--cp-input-bg / hover-bg / active-bg / error-active-bg` 与对应 Shadow |
-| Menu | `--cp-menu-item-selected-bg` |
-| Popover | `--cp-popover-header-bg` |
-| Table | `--cp-table-row-bg / stripe-bg / hover-bg / selected-bg / selected-hover-bg / height` |
-| Card | `--cp-card-bg / border-radius / shadow` |
-| Layout | `--cp-layout-sider-bg / shadow` |
-| Scrollbar | `--cp-scrollbar-thumb-bg / hover-bg` |
-| BrandMark | `--cp-brand-mark-bg` |
+| Button | `--z-button-primary-color / bg / hover-bg / active-bg`、`--z-button-secondary-bg / hover-bg / active-bg` |
+| IconButton | `--z-icon-button-secondary-bg / hover-bg / active-bg` |
+| Input | `--z-input-bg / hover-bg / active-bg / error-active-bg` 与对应 Shadow |
+| Menu | `--z-menu-item-selected-bg` |
+| Popover | `--z-popover-header-bg` |
+| Table | `--z-table-row-bg / stripe-bg / hover-bg / selected-bg / selected-hover-bg / height` |
+| Card | `--z-card-bg / border-radius / shadow` |
+| Layout | `--z-layout-sider-bg / shadow` |
+| Scrollbar | `--z-scrollbar-thumb-bg / hover-bg` |
+| BrandMark | `--z-brand-mark-bg` |
组件状态由 UI 库的 Component 派生层统一生成,页面不维护混色系数:
@@ -308,13 +308,17 @@ Theme Store 统一读取持久化配置并初始化主题,首个 Vue 组件渲
### CSS Variables 提交
+主题内部和持久化配置使用 `color-primary`、`input-bg` 等语义 Token 名,不包含 CSS 前缀。
+UI 构建插件 `CodexProxyUI({ themePrefix: 'z' })` 同时配置变量生成与样式引用,默认前缀为 `z`;
+它与组件导出名、DOM 类名和 utility 类名独立,修改后需重新构建。配置方式见 UI 的[主题定制](../modules/ui/playground/guide/theme.md#自定义主题前缀)
+
全局主题由 `
` 中唯一的运行时样式节点承载:
```html
-
@@ -324,14 +328,15 @@ Theme Store 统一读取持久化配置并初始化主题,首个 Vue 组件渲
全局弹窗通过 Teleport 挂到 `body` 后仍继承根变量
> [!NOTE]
-> Theme Editor 预览是例外:草稿 Token 以内联变量写在影子环境的局部根节点上,仅影响预览,不污染已保存主题
+> Theme Editor 预览是例外:草稿 Token 经 `createThemeVars()` 转换后以内联变量写在影子环境的局部根节点上,仅影响预览,不污染已保存主题
### 切换与图表
- 用户主动切换时,以点击位置为圆心运行 View Transition;不支持时使用 180ms 颜色过渡
- 初始化、系统主题变化或减少动态效果时直接提交,不播放扩散动画
- 每次有效提交只增加一次 `themeRevision`,相同签名不会重复刷新
-- `useThemeColor()` 在正式页面读取根 CSS Variables,在影子预览中优先读取注入的局部 Token
+- `useThemeColor()` 接收语义 Token 名,通过 `getThemeVarName()` 读取当前前缀下的 CSS Variables;影子预览优先读取注入的局部变量
+- 插件桥接传递语义 Token,由插件构建元数据指定的前缀生成 CSS 变量,宿主与插件可独立配置
- 图表 Option 在主题 revision 或预览 Token 改变后重算,`BaseChart` 通过 `setOption` 更新现有 Canvas
## 主题编辑器
@@ -381,24 +386,24 @@ Store 在其他入口发生变化时更新保存基线;没有未保存修改
### CSS Token
-- 全局 Token:`--cp-color-bg-container`、`--cp-font-size`
-- Component Token:`--cp-table-row-hover-bg`、`--cp-input-active-shadow`
-- Preset Color Token:`--cp-color-purple-container-strong`、`--cp-color-cyan-on-container`
+- 全局 Token:`--z-color-bg-container`、`--z-font-size`
+- Component Token:`--z-table-row-hover-bg`、`--z-input-active-shadow`
+- Preset Color Token:`--z-color-purple-container-strong`、`--z-color-cyan-on-container`
- 业务组件按[通用颜色消费](#通用颜色消费)选择角色,不在主题层声明业务域名称
-- Map 与 Component 字段由 `theme/core/tokens.ts` 统一生成 CSS Token;禁止在解析器中再写平行的逐项映射表
+- Map 与 Component 字段由 `theme/core/tokens.ts` 统一生成语义 Token,运行时通过 `createThemeVars()` 输出 CSS 变量;禁止在解析器中再写平行的逐项映射表
- 不使用 `accent`、`soft`、`current`、`subtle` 等与现有角色重叠的平行词汇
### Vue 与 Tailwind CSS 4
-组件优先使用 `bg-cp-*`、`text-cp-*`、`shadow-cp-*`、`rounded-cp-*` 等由 `@theme inline` 暴露的 utility:
+组件优先使用 `bg-z-*`、`text-z-*`、`shadow-z-*`、`rounded-z-*` 等由 `@theme inline` 暴露的 utility:
```vue
-
+
```
-仅当值需要在 CSS 函数、SVG 或局部派生中参与计算时,直接读取 `var(--cp-*)`。不在页面组件中重新实现色阶、
+仅当值需要在 CSS 函数、SVG 或局部派生中参与计算时,CSS 中直接读取 `var(--z-*)`,JavaScript 中通过 `getThemeVarName()` 生成变量名。不在页面组件中重新实现色阶、
对比度或明暗算法
共享包的 `styles/tailwind.css` 是唯一 `@theme inline` 注册表,只注册 Tailwind 名称,不保存主题值。注册表按基础、排版、颜色、圆角、阴影、间距与尺寸排序;
@@ -426,8 +431,8 @@ utility / arbitrary variant;Vue Transition、跨浏览器 Range、动态富文
### 增加预置主题
1. 在 `ThemeColorPresetId` 增加稳定 ID
-2. 在 `THEME_COLOR_PRESETS` 声明名称、描述与主色 Seed
-3. 不新增页面特判,确认预置可通过同一 `resolveTheme()` 派生
+2. 在 `themeColorPresets` 声明名称、描述与主色 Seed
+3. 不新增页面特判,确认预置可通过同一 `createTheme()` 派生
4. 在浅色、深色和系统模式下检查文本、浮层、Input、表格与图表
### 增加全局 Seed 或 Alias
diff --git a/frontend/package.json b/frontend/package.json
index 9ddc437ac..5aaeb181d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -17,7 +17,7 @@
},
"dependencies": {
"@boxicons/vue": "1.0.1",
- "@codex-proxy/ui": "github:zyycn/codex-proxy-ui#v0.7.0",
+ "@codex-proxy/ui": "github:zyycn/codex-proxy-ui#v0.8.0",
"@fontsource-variable/inter": "^5.3.0",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@lucide/vue": "^1.61.0",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 956fd02c7..a8671814a 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -195,8 +195,8 @@ importers:
specifier: 1.0.1
version: 1.0.1(vue@3.5.44(typescript@6.0.3))
'@codex-proxy/ui':
- specifier: github:zyycn/codex-proxy-ui#v0.7.0
- version: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/0692ca034be88de6faf88bc76f1a6e9e7ad65225(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.44(typescript@6.0.3))
+ specifier: github:zyycn/codex-proxy-ui#v0.8.0
+ version: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/d6100447010715c1203e67a4195fc6d875ff6249(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(jiti@2.7.0)(postcss@8.5.30)(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.44(typescript@6.0.3))(yaml@2.9.0)
'@fontsource-variable/inter':
specifier: ^5.3.0
version: 5.3.0
@@ -443,9 +443,9 @@ packages:
resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==}
engines: {node: '>= 20.12.0'}
- '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/0692ca034be88de6faf88bc76f1a6e9e7ad65225':
- resolution: {gitHosted: true, integrity: sha512-JJesyJ1Y/QcdXhBtmKX6k0GyUgOSxiV8sJrUymvLyKjC8NhHLmtpXWt/evZcjYBDyJEIRll85bmSmtMF9/Wpqw==, tarball: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/0692ca034be88de6faf88bc76f1a6e9e7ad65225}
- version: 0.7.0
+ '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/d6100447010715c1203e67a4195fc6d875ff6249':
+ resolution: {gitHosted: true, integrity: sha512-XNPErDXqq9OxvgLgSb0gVRGmI9Yf+Vx0dTjoZKzaAaCOX9exSirU5kEr9mJBeuo9E1DDw8817xV0B5Od9zH+5A==, tarball: https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/d6100447010715c1203e67a4195fc6d875ff6249}
+ version: 0.8.0
engines: {node: '>=24'}
peerDependencies:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -2618,6 +2618,10 @@ packages:
resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
engines: {node: '>= 12.0.0'}
+ lilconfig@3.1.4:
+ resolution: {integrity: sha512-zJZyBmQhArDRefuWTypZxwDpFDIYmrj8ypSBvwGD5P13Y95s6DjzKgu4DVdGbeQa5PDEsAOCAPNk4X+QOR006w==}
+ engines: {node: '>=14'}
+
local-pkg@1.2.1:
resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==}
engines: {node: '>=14'}
@@ -2645,6 +2649,11 @@ packages:
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
+ marked-alert@2.1.2:
+ resolution: {integrity: sha512-EFNRZ08d8L/iEIPLTlQMDjvwIsj03gxWCczYTht6DCiHJIZhMk4NK5gtPY9UqAYb09eV5VGT+jD4lp396E0I+w==}
+ peerDependencies:
+ marked: '>=7.0.0'
+
marked@18.1.0:
resolution: {integrity: sha512-PamYXWWWg2nboG3oX5Ffzpy3EFZROqZJK9hSlMmUnekp7TxPs5DcT95vwd46m73/exfKCRVMtgXoPMI4FEJL6w==}
engines: {node: '>= 20'}
@@ -2973,6 +2982,24 @@ packages:
pnpm-workspace-yaml@1.9.1:
resolution: {integrity: sha512-Xj/T2X6DNAWbtk/9UQ0/TJRswltiHZevmcMjqoL7WrpJi67lu3qaslU4+I+zJ8wtwqmuvAE0KkB8rbv2ZdogBg==}
+ postcss-load-config@6.0.1:
+ resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ jiti: '>=1.21.0'
+ postcss: '>=8.0.9'
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ postcss:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
postcss-selector-parser@7.1.6:
resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==}
engines: {node: '>=4'}
@@ -3525,7 +3552,7 @@ snapshots:
fast-wrap-ansi: 0.2.2
sisteransi: 1.0.5
- '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/0692ca034be88de6faf88bc76f1a6e9e7ad65225(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.44(typescript@6.0.3))':
+ '@codex-proxy/ui@https://codeload.github.com/zyycn/codex-proxy-ui/tar.gz/d6100447010715c1203e67a4195fc6d875ff6249(axios@1.20.0(debug@4.4.3))(change-case@5.4.4)(jiti@2.7.0)(postcss@8.5.30)(vite@8.3.5(@types/node@26.6.5)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.44(typescript@6.0.3))(yaml@2.9.0)':
dependencies:
'@ant-design/colors': 8.0.1
'@ant-design/fast-color': 3.0.1
@@ -3538,6 +3565,8 @@ snapshots:
es-toolkit: 1.53.0
gsap: 3.15.0
marked: 18.1.0
+ marked-alert: 2.1.2(marked@18.1.0)
+ postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.30)(yaml@2.9.0)
sortablejs: 1.15.7
vue: 3.5.44(typescript@6.0.3)
optionalDependencies:
@@ -3550,10 +3579,14 @@ snapshots:
- focus-trap
- fuse.js
- idb-keyval
+ - jiti
- jwt-decode
- nprogress
+ - postcss
- qrcode
+ - tsx
- universal-cookie
+ - yaml
'@dprint/formatter@0.5.1': {}
@@ -5486,6 +5519,8 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.33.0
lightningcss-win32-x64-msvc: 1.33.0
+ lilconfig@3.1.4: {}
+
local-pkg@1.2.1:
dependencies:
mlly: 1.8.2
@@ -5514,6 +5549,10 @@ snapshots:
markdown-table@3.0.4: {}
+ marked-alert@2.1.2(marked@18.1.0):
+ dependencies:
+ marked: 18.1.0
+
marked@18.1.0: {}
math-intrinsics@1.1.0: {}
@@ -6053,6 +6092,14 @@ snapshots:
dependencies:
yaml: 2.9.0
+ postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.30)(yaml@2.9.0):
+ dependencies:
+ lilconfig: 3.1.4
+ optionalDependencies:
+ jiti: 2.7.0
+ postcss: 8.5.30
+ yaml: 2.9.0
+
postcss-selector-parser@7.1.6:
dependencies:
cssesc: 3.0.0
diff --git a/frontend/src/components/AccountGroupCheckboxGrid.vue b/frontend/src/components/AccountGroupCheckboxGrid.vue
index c62488f8f..c44e6e42c 100644
--- a/frontend/src/components/AccountGroupCheckboxGrid.vue
+++ b/frontend/src/components/AccountGroupCheckboxGrid.vue
@@ -35,7 +35,7 @@ function updateGroup(groupId: string, selected: boolean) {
@@ -46,10 +46,10 @@ function updateGroup(groupId: string, selected: boolean) {
@update:model-value="updateGroup(group.id, $event)"
/>
- {{ t('common.status.disabled') }}
+ {{ t('common.status.disabled') }}
-
+
{{ loading ? t('groups.selector.loading') : t('groups.selector.empty') }}
diff --git a/frontend/src/components/AccountGroupMarks.vue b/frontend/src/components/AccountGroupMarks.vue
index 026034bd3..7dd6cc735 100644
--- a/frontend/src/components/AccountGroupMarks.vue
+++ b/frontend/src/components/AccountGroupMarks.vue
@@ -32,5 +32,5 @@ const fullNames = computed(() =>
:title="group.name"
/>
- —
+ —
diff --git a/frontend/src/components/ApiKeyConfigModal.vue b/frontend/src/components/ApiKeyConfigModal.vue
index a214aafc2..960fa6a1f 100644
--- a/frontend/src/components/ApiKeyConfigModal.vue
+++ b/frontend/src/components/ApiKeyConfigModal.vue
@@ -79,10 +79,10 @@ function importToClient() {
/>
-
+
{{ configPath }}
@@ -96,9 +96,9 @@ function importToClient() {
-
+
diff --git a/frontend/src/components/AppBrandMark.vue b/frontend/src/components/AppBrandMark.vue
index 678e79fed..d3ba648c5 100644
--- a/frontend/src/components/AppBrandMark.vue
+++ b/frontend/src/components/AppBrandMark.vue
@@ -12,7 +12,7 @@ const mistGradientId = `${id}-brand-mist`
-