From 84222409678958ddbafa3b8ce453618bc4e39084 Mon Sep 17 00:00:00 2001 From: Zyy Date: Mon, 24 Aug 2026 04:04:22 +0800 Subject: [PATCH] feat(theme): add runtime token theme editor Introduce Seed-to-Component token derivation, isolated live previews, semantic base component theming, and responsive theme controls. Co-authored-by: Codex --- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 16 + frontend/src/App.vue | 3 - .../components/AccountGroupCheckboxGrid.vue | 6 +- frontend/src/components/AccountGroupMarks.vue | 2 +- .../components/AccountGroupMultiSelect.vue | 20 +- frontend/src/components/AppBrandMark.vue | 117 ++ frontend/src/components/ProviderIconGroup.vue | 8 +- frontend/src/components/base/BaseButton.vue | 18 +- frontend/src/components/base/BaseCard.vue | 6 +- frontend/src/components/base/BaseCheckbox.vue | 14 +- .../components/base/BaseColorPicker/color.ts | 31 +- .../components/base/BaseColorPicker/index.vue | 110 +- .../src/components/base/BaseConfirmModal.vue | 2 +- frontend/src/components/base/BaseEmpty.vue | 8 +- .../src/components/base/BaseForm/FormItem.vue | 8 +- .../src/components/base/BaseIconButton.vue | 18 +- frontend/src/components/base/BaseInput.vue | 45 +- frontend/src/components/base/BaseMenuItem.vue | 10 +- .../src/components/base/BaseModal/index.vue | 16 +- .../src/components/base/BaseNumberInput.vue | 127 ++ .../src/components/base/BasePageHeader.vue | 6 +- frontend/src/components/base/BasePopover.vue | 2 +- frontend/src/components/base/BaseRadio.vue | 10 +- frontend/src/components/base/BaseRange.vue | 142 ++ .../src/components/base/BaseScrollbar.vue | 16 +- .../src/components/base/BaseSegmented.vue | 18 +- frontend/src/components/base/BaseSelect.vue | 44 +- frontend/src/components/base/BaseSkeleton.vue | 38 + frontend/src/components/base/BaseSwitch.vue | 12 +- .../base/BaseTable/BaseTablePagination.vue | 10 +- .../src/components/base/BaseTable/columns.ts | 10 +- .../src/components/base/BaseTable/index.vue | 46 +- frontend/src/components/base/BaseTextarea.vue | 12 +- .../components/base/BaseToast/BaseToast.vue | 14 +- frontend/src/components/charts/BaseChart.vue | 25 +- frontend/src/components/charts/tooltip.ts | 2 +- frontend/src/composables/useChartPalette.ts | 30 +- frontend/src/composables/useThemeColor.ts | 29 +- frontend/src/directives/loading.ts | 6 +- .../src/layout/components/AppAboutModal.vue | 18 +- frontend/src/layout/components/AppSidebar.vue | 55 +- .../components/FloatingSidebarToggle.vue | 4 +- .../components/SystemUpdateModal/index.vue | 66 +- .../components/SystemUpdateModal/presenter.ts | 12 +- frontend/src/layout/index.vue | 2 +- frontend/src/main.ts | 17 +- frontend/src/router/routes.ts | 12 +- frontend/src/stores/modules/theme.ts | 330 +++++ frontend/src/stores/modules/ui.ts | 200 +-- frontend/src/styles/base.css | 22 +- frontend/src/styles/index.css | 198 +-- frontend/src/styles/tokens.css | 227 +-- frontend/src/theme/browser.ts | 36 + frontend/src/theme/constants.ts | 215 +++ frontend/src/theme/index.ts | 1214 +++++++++++++++++ frontend/src/utils/color.ts | 12 +- .../components/AccountGroupActions.vue | 4 +- .../components/AccountGroupFilters.vue | 2 +- .../components/AccountGroupMetricsCell.vue | 6 +- frontend/src/views/account-groups/index.vue | 8 +- .../components/AccountBatchEditModal.vue | 2 +- .../components/AccountConnectionTestModal.vue | 56 +- .../AccountProviderChooser.vue | 4 +- .../components/AccountCreateModal/index.vue | 18 +- .../accounts/components/AccountEditModal.vue | 4 +- .../accounts/components/AccountFilters.vue | 10 +- .../components/AccountIdentityCell.vue | 16 +- .../components/AccountOverviewCards.vue | 8 +- .../accounts/components/AccountPlanBadge.vue | 10 +- .../accounts/components/AccountQuotaPanel.vue | 8 +- .../components/AccountQuotaPanelEntry.vue | 20 +- .../components/AccountQuotaSummaryEntry.vue | 34 +- .../components/AccountQuotaWindowGroup.vue | 4 +- .../components/AccountResetCredits.vue | 44 +- .../components/AccountStatusBadge/index.vue | 46 +- .../AccountStatusBadge/presenter.ts | 16 +- .../components/AccountTableActions.vue | 14 +- .../accounts/components/AccountUsagePanel.vue | 32 +- .../AccountRequestTimeline.vue | 2 +- .../components/AccountUsageWindow/index.vue | 12 +- .../AccountUsageWindow/presenter.ts | 28 +- .../composables/useAccountConnectionTest.ts | 8 +- frontend/src/views/accounts/constants.ts | 6 +- frontend/src/views/accounts/index.vue | 4 +- .../api-keys/components/ApiKeyActions.vue | 8 +- .../api-keys/components/ApiKeyCreateModal.vue | 8 +- .../api-keys/components/ApiKeyFilters.vue | 2 +- .../components/ApiKeyIdentityCell.vue | 4 +- .../api-keys/components/ApiKeyPrefixCell.vue | 2 +- .../api-keys/components/ApiKeyScopeCell.vue | 2 +- .../api-keys/components/ApiKeyStatusBadge.vue | 4 +- .../api-keys/components/ApiKeyUseModal.vue | 8 +- .../components/AccountOverviewCard.vue | 62 +- .../dashboard/components/DashboardContent.vue | 106 ++ .../components/HealthTimelinePointPopover.vue | 32 +- .../views/dashboard/components/MetricCard.vue | 16 +- .../components/RequestHealthTimelineCard.vue | 8 +- .../dashboard/components/RequestTrendCard.vue | 12 +- .../dashboard/components/WireProfileCard.vue | 40 +- .../dashboard/composables/useDashboard.ts | 24 +- .../composables/useRequestTrendChart.ts | 30 +- frontend/src/views/dashboard/constants.ts | 30 +- frontend/src/views/dashboard/index.vue | 85 +- .../login/components/LoginBackground.vue | 94 +- .../src/views/login/components/LoginPanel.vue | 123 +- frontend/src/views/login/index.vue | 239 ++-- .../settings/components/AdminApiKeyCard.vue | 12 +- .../settings/components/ModelAliasesCard.vue | 18 +- .../components/RotationStrategyCard.vue | 14 +- .../components/backup/BackupRecordsCard.vue | 12 +- .../components/backup/BackupStatusBadge.vue | 12 +- .../components/backup/BackupStorageCard.vue | 4 +- .../components/backup/R2GuideModal.vue | 24 +- frontend/src/views/settings/index.vue | 23 +- .../components/AppearanceSettingsSection.vue | 183 +++ .../theme/components/ThemeColorTokenField.vue | 65 + .../components/ThemeComponentPreview.vue | 460 +++++++ .../components/ThemeComponentTokenPanel.vue | 229 ++++ .../components/ThemeDashboardPreview.vue | 33 + .../theme/components/ThemeEditorPreview.vue | 44 + .../components/ThemeGlobalTokenPanel.vue | 316 +++++ .../components/ThemeNumberTokenField.vue | 66 + .../theme/components/ThemePreviewCanvas.vue | 133 ++ .../theme/components/ThemePreviewScope.vue | 65 + .../theme/components/ThemeTextTokenField.vue | 44 + .../views/theme/composables/useThemeEditor.ts | 326 +++++ .../composables/useThemePreviewCanvas.ts | 216 +++ .../src/views/theme/fixtures/dashboard.ts | 386 ++++++ frontend/src/views/theme/index.vue | 9 + .../usage/components/OpsErrorDetailModal.vue | 16 +- .../views/usage/components/OpsErrorPanel.vue | 6 +- .../usage/components/UsageBillingCell.vue | 8 +- .../usage/components/UsageClientIpCell.vue | 2 +- .../usage/components/UsageDetailCodePanel.vue | 6 +- .../usage/components/UsageDetailFieldGrid.vue | 2 +- .../usage/components/UsageDetailPopover.vue | 6 +- .../usage/components/UsageDiagnosticCard.vue | 14 +- .../views/usage/components/UsageFilters.vue | 2 +- .../usage/components/UsageLatencyCell.vue | 28 +- .../views/usage/components/UsageModelCell.vue | 6 +- .../components/UsageReasoningEffortCell.vue | 2 +- .../components/UsageRecordDetailModal.vue | 22 +- .../usage/components/UsageRecordsTable.vue | 8 +- .../usage/components/UsageStatusCodeBadge.vue | 6 +- .../usage/components/UsageSummaryCards.vue | 10 +- .../views/usage/components/UsageTokenCell.vue | 10 +- frontend/src/views/usage/index.vue | 4 +- frontend/src/views/usage/utils/detail.ts | 4 +- frontend/src/views/usage/utils/records.ts | 2 +- 150 files changed, 6281 insertions(+), 1640 deletions(-) create mode 100644 frontend/src/components/AppBrandMark.vue create mode 100644 frontend/src/components/base/BaseNumberInput.vue create mode 100644 frontend/src/components/base/BaseRange.vue create mode 100644 frontend/src/components/base/BaseSkeleton.vue create mode 100644 frontend/src/stores/modules/theme.ts create mode 100644 frontend/src/theme/browser.ts create mode 100644 frontend/src/theme/constants.ts create mode 100644 frontend/src/theme/index.ts create mode 100644 frontend/src/views/dashboard/components/DashboardContent.vue create mode 100644 frontend/src/views/theme/components/AppearanceSettingsSection.vue create mode 100644 frontend/src/views/theme/components/ThemeColorTokenField.vue create mode 100644 frontend/src/views/theme/components/ThemeComponentPreview.vue create mode 100644 frontend/src/views/theme/components/ThemeComponentTokenPanel.vue create mode 100644 frontend/src/views/theme/components/ThemeDashboardPreview.vue create mode 100644 frontend/src/views/theme/components/ThemeEditorPreview.vue create mode 100644 frontend/src/views/theme/components/ThemeGlobalTokenPanel.vue create mode 100644 frontend/src/views/theme/components/ThemeNumberTokenField.vue create mode 100644 frontend/src/views/theme/components/ThemePreviewCanvas.vue create mode 100644 frontend/src/views/theme/components/ThemePreviewScope.vue create mode 100644 frontend/src/views/theme/components/ThemeTextTokenField.vue create mode 100644 frontend/src/views/theme/composables/useThemeEditor.ts create mode 100644 frontend/src/views/theme/composables/useThemePreviewCanvas.ts create mode 100644 frontend/src/views/theme/fixtures/dashboard.ts create mode 100644 frontend/src/views/theme/index.vue diff --git a/frontend/package.json b/frontend/package.json index 518e1def4..704b47055 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "format:check": "pnpm run lint" }, "dependencies": { + "@ant-design/colors": "^8.0.1", "@boxicons/vue": "1.0.1", "@fontsource-variable/inter": "^5.3.0", "@fontsource-variable/jetbrains-mono": "^5.3.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 0f4035ed9..919e7ea55 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@ant-design/colors': + specifier: ^8.0.1 + version: 8.0.1 '@boxicons/vue': specifier: 1.0.1 version: 1.0.1(vue@3.5.41(typescript@6.0.3)) @@ -96,6 +99,13 @@ importers: packages: + '@ant-design/colors@8.0.1': + resolution: {integrity: sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==} + + '@ant-design/fast-color@3.0.1': + resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==} + engines: {node: '>=8.x'} + '@antfu/eslint-config@9.3.0': resolution: {integrity: sha512-+CIC4G6MowUl1RHiT01Ah9Obo/wwVynw7uNlN8ODwEn2opo9W1KzaatCrmu4WhGGJjOkOkyT5w7kKfQ//agHrQ==} hasBin: true @@ -2431,6 +2441,12 @@ packages: snapshots: + '@ant-design/colors@8.0.1': + dependencies: + '@ant-design/fast-color': 3.0.1 + + '@ant-design/fast-color@3.0.1': {} + '@antfu/eslint-config@9.3.0(@typescript-eslint/typescript-estree@8.66.0(typescript@6.0.3))(@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.41)(eslint-plugin-format@2.0.1(eslint@10.8.1(jiti@2.7.0)))(eslint-plugin-vuejs-accessibility@2.6.0(eslint@10.8.1(jiti@2.7.0))(globals@17.9.0))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@antfu/install-pkg': 2.0.1 diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 7825528b5..1dfbad621 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -2,9 +2,6 @@ import { RouterView } from 'vue-router' import { BaseToast } from '@/components/base/BaseToast' -import { useUiStore } from '@/stores/modules/ui' - -useUiStore().initializeTheme() diff --git a/frontend/src/components/AccountGroupMultiSelect.vue b/frontend/src/components/AccountGroupMultiSelect.vue index 41ad6f93e..bcf53f0c7 100644 --- a/frontend/src/components/AccountGroupMultiSelect.vue +++ b/frontend/src/components/AccountGroupMultiSelect.vue @@ -90,7 +90,7 @@ function providerSummary(group: AccountGroup) { :disabled="disabled || loading" > @@ -102,10 +102,10 @@ function providerSummary(group: AccountGroup) {
- + {{ group.name }} - + {{ group.memberCount }} 个账号 @@ -148,15 +148,15 @@ function providerSummary(group: AccountGroup) {
-

+

{{ emptyCopy.title }}

-

+

{{ emptyCopy.description }}

diff --git a/frontend/src/components/AppBrandMark.vue b/frontend/src/components/AppBrandMark.vue new file mode 100644 index 000000000..ab84e4b1e --- /dev/null +++ b/frontend/src/components/AppBrandMark.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/frontend/src/components/ProviderIconGroup.vue b/frontend/src/components/ProviderIconGroup.vue index b0b06f579..2ba7abd22 100644 --- a/frontend/src/components/ProviderIconGroup.vue +++ b/frontend/src/components/ProviderIconGroup.vue @@ -39,18 +39,18 @@ const authenticationLabel = computed(() => {