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` -