diff --git a/frontend/src/components/layout/ThemePicker.tsx b/frontend/src/components/layout/ThemePicker.tsx
index bedf400..2f9b3b8 100644
--- a/frontend/src/components/layout/ThemePicker.tsx
+++ b/frontend/src/components/layout/ThemePicker.tsx
@@ -1,12 +1,8 @@
-// 全局主题选择器 — Header / Login 共用,分组展示主流与开发者主题 // Logan.Li
+// 全局主题选择器 — Header / Login 共用,双主题 + 跟随系统 // Logan.Li
import { Check } from 'lucide-react';
import { cn } from '@/lib/utils';
-import {
- DropdownMenuItem,
- DropdownMenuLabel,
- DropdownMenuSeparator,
-} from '@/components/ui/dropdown-menu';
-import { THEME_GROUPS, type ThemePreference } from '@/utils/theme';
+import { DropdownMenuItem } from '@/components/ui/dropdown-menu';
+import { THEME_OPTIONS, type ThemePreference } from '@/utils/theme';
interface ThemePickerProps {
value: ThemePreference;
@@ -16,46 +12,36 @@ interface ThemePickerProps {
export function ThemePicker({ value, onChange }: ThemePickerProps) {
return (
<>
- {THEME_GROUPS.map((group, gi) => (
-
- {gi > 0 &&
}
-
- {group.label}
-
- {group.options.map((option) => (
-
onChange(option.id)}
- >
-
-
- {option.name}
-
- {option.description}
-
-
- {value === option.id && (
-
- )}
-
- ))}
-
+ {THEME_OPTIONS.map((option) => (
+ onChange(option.id)}
+ >
+
+
+ {option.name}
+
+ {option.description}
+
+
+ {value === option.id && (
+
+ )}
+
))}
>
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 1bcca8c..b175a4f 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -136,339 +136,6 @@
--skeleton-base: #f0f1f5;
--skeleton-highlight: #e8eaef;
}
-
- /* ===== Theme 3: One Dark — Atom 暖灰 IDE(刻意与深海蓝蓝黑区分) // Logan.Li ===== */
- [data-theme="one-dark"] {
- --background: 220 9% 22%;
- --foreground: 220 8% 82%;
- --card: 220 8% 26%;
- --card-foreground: 220 8% 82%;
- --popover: 220 8% 24%;
- --popover-foreground: 220 8% 82%;
- --primary: 207 82% 66%;
- --primary-foreground: 220 9% 18%;
- --secondary: 220 8% 30%;
- --secondary-foreground: 220 8% 82%;
- --muted: 220 8% 30%;
- --muted-foreground: 220 6% 52%;
- --accent: 220 8% 30%;
- --accent-foreground: 220 8% 82%;
- --destructive: 355 65% 65%;
- --destructive-foreground: 220 9% 18%;
- --border: 220 7% 34%;
- --input: 220 8% 28%;
- --ring: 286 60% 67%;
- --radius: 0.625rem;
- --sidebar-background: 220 9% 17%;
- --sidebar-foreground: 220 8% 78%;
- --sidebar-primary: 207 82% 66%;
- --sidebar-primary-foreground: 220 9% 18%;
- --sidebar-accent: 220 8% 26%;
- --sidebar-accent-foreground: 220 8% 82%;
- --sidebar-border: 220 7% 28%;
- --sidebar-ring: 286 60% 67%;
- /* 更亮暖灰底 + 侧栏压暗,贴近 Atom 编辑器层次 */
- --dg-bg-primary: #282c34;
- --dg-bg-secondary: #2f343e;
- --dg-bg-tertiary: #383e4a;
- --dg-bg-hover: #3e4451;
- --dg-bg-active: #4b5263;
- --dg-border: #4b5263;
- --dg-border-light: #353b45;
- --dg-border-hover: #5c6370;
- --dg-text-primary: #d7dae0;
- --dg-text-secondary: #9da5b4;
- --dg-text-muted: #6b7285;
- /* Atom 语法高亮色 — 品牌渐变用紫→绿,非深海蓝 */
- --dg-blue: #61afef;
- --dg-green: #98c379;
- --dg-red: #e06c75;
- --dg-orange: #d19a66;
- --dg-purple: #c678dd;
- --dg-cyan: #56b6c2;
- --dg-yellow: #e5c07b;
- --dg-card-hover-border: rgba(198, 120, 221, 0.42);
- --dg-gradient-start: #c678dd;
- --dg-gradient-end: #98c379;
- --dg-gradient-text-start: #c678dd;
- --dg-gradient-text-end: #61afef;
- --dg-input-focus-ring: rgba(198, 120, 221, 0.22);
- --chart-grid: #4b5263;
- --chart-axis: #6b7285;
- --chart-tooltip-bg: #2f343e;
- --chart-tooltip-border: #4b5263;
- --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(198, 120, 221, 0.06);
- --shadow-card-hover: 0 8px 28px rgba(0, 0, 0, 0.32), 0 0 0 1px rgba(152, 195, 121, 0.18);
- --shadow-dropdown: 0 10px 36px rgba(0, 0, 0, 0.45);
- --skeleton-base: #383e4a;
- --skeleton-highlight: #4b5263;
- --dg-overlay: color-mix(in srgb, #21252b 52%, transparent);
- }
-
- /* ===== Theme 4: Catppuccin Mocha ===== */
- [data-theme="catppuccin"] {
- --background: 240 21% 15%;
- --foreground: 226 64% 88%;
- --card: 240 21% 12%;
- --card-foreground: 226 64% 88%;
- --popover: 240 21% 12%;
- --popover-foreground: 226 64% 88%;
- --primary: 217 92% 76%;
- --primary-foreground: 240 21% 15%;
- --secondary: 237 16% 23%;
- --secondary-foreground: 226 64% 88%;
- --muted: 237 16% 23%;
- --muted-foreground: 228 24% 72%;
- --accent: 237 16% 23%;
- --accent-foreground: 226 64% 88%;
- --destructive: 343 81% 75%;
- --destructive-foreground: 240 21% 15%;
- --border: 237 16% 23%;
- --input: 237 16% 23%;
- --ring: 217 92% 76%;
- --radius: 0.625rem;
- --sidebar-background: 240 23% 9%;
- --sidebar-foreground: 226 64% 85%;
- --sidebar-primary: 217 92% 76%;
- --sidebar-primary-foreground: 240 21% 15%;
- --sidebar-accent: 237 16% 23%;
- --sidebar-accent-foreground: 226 64% 88%;
- --sidebar-border: 237 16% 23%;
- --sidebar-ring: 217 92% 76%;
- --dg-bg-primary: #1e1e2e;
- --dg-bg-secondary: #181825;
- --dg-bg-tertiary: #313244;
- --dg-bg-hover: #45475a;
- --dg-bg-active: #585b70;
- --dg-border: #45475a;
- --dg-border-light: #313244;
- --dg-border-hover: #585b70;
- --dg-text-primary: #cdd6f4;
- --dg-text-secondary: #a6adc8;
- --dg-text-muted: #7f849c;
- --dg-blue: #89b4fa;
- --dg-green: #a6e3a1;
- --dg-red: #f38ba8;
- --dg-orange: #fab387;
- --dg-purple: #cba6f7;
- --dg-cyan: #89dceb;
- --dg-yellow: #f9e2af;
- --dg-card-hover-border: rgba(137, 180, 250, 0.45);
- --dg-gradient-start: #74c7ec;
- --dg-gradient-end: #cba6f7;
- --dg-gradient-text-start: #89b4fa;
- --dg-gradient-text-end: #cba6f7;
- --dg-input-focus-ring: rgba(137, 180, 250, 0.2);
- --chart-grid: #45475a;
- --chart-axis: #7f849c;
- --chart-tooltip-bg: #181825;
- --chart-tooltip-border: #45475a;
- --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(137, 180, 250, 0.05);
- --shadow-card-hover: 0 8px 32px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(137, 180, 250, 0.15);
- --shadow-dropdown: 0 10px 40px rgba(0, 0, 0, 0.5);
- --skeleton-base: #313244;
- --skeleton-highlight: #45475a;
- --dg-overlay: color-mix(in srgb, #11111b 55%, transparent);
- }
-
- /* ===== Theme 5: Dracula — 紫粉经典(高辨识度) // Logan.Li ===== */
- [data-theme="dracula"] {
- --background: 231 15% 18%;
- --foreground: 60 30% 96%;
- --card: 231 15% 20%;
- --card-foreground: 60 30% 96%;
- --popover: 231 15% 20%;
- --popover-foreground: 60 30% 96%;
- --primary: 265 89% 78%;
- --primary-foreground: 231 15% 18%;
- --secondary: 232 14% 31%;
- --secondary-foreground: 60 30% 96%;
- --muted: 232 14% 31%;
- --muted-foreground: 231 8% 68%;
- --accent: 232 14% 31%;
- --accent-foreground: 60 30% 96%;
- --destructive: 0 100% 67%;
- --destructive-foreground: 231 15% 18%;
- --border: 232 14% 31%;
- --input: 232 14% 31%;
- --ring: 265 89% 78%;
- --radius: 0.625rem;
- --sidebar-background: 231 16% 16%;
- --sidebar-foreground: 60 25% 92%;
- --sidebar-primary: 265 89% 78%;
- --sidebar-primary-foreground: 231 15% 18%;
- --sidebar-accent: 232 14% 28%;
- --sidebar-accent-foreground: 60 30% 96%;
- --sidebar-border: 232 14% 28%;
- --sidebar-ring: 265 89% 78%;
- --dg-bg-primary: #282a36;
- --dg-bg-secondary: #313341;
- --dg-bg-tertiary: #44475a;
- --dg-bg-hover: #4d5066;
- --dg-bg-active: #5a5d78;
- --dg-border: #44475a;
- --dg-border-light: #383a4a;
- --dg-border-hover: #6272a4;
- --dg-text-primary: #f8f8f2;
- --dg-text-secondary: #bfbfb5;
- --dg-text-muted: #8b8b80;
- --dg-blue: #8be9fd;
- --dg-green: #50fa7b;
- --dg-red: #ff5555;
- --dg-orange: #ffb86c;
- --dg-purple: #bd93f9;
- --dg-cyan: #8be9fd;
- --dg-yellow: #f1fa8c;
- --dg-card-hover-border: rgba(189, 147, 249, 0.5);
- --dg-gradient-start: #bd93f9;
- --dg-gradient-end: #ff79c6;
- --dg-gradient-text-start: #bd93f9;
- --dg-gradient-text-end: #ff79c6;
- --dg-input-focus-ring: rgba(189, 147, 249, 0.25);
- --chart-grid: #44475a;
- --chart-axis: #8b8b80;
- --chart-tooltip-bg: #313341;
- --chart-tooltip-border: #44475a;
- --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(189, 147, 249, 0.08);
- --shadow-card-hover: 0 8px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 121, 198, 0.2);
- --shadow-dropdown: 0 10px 40px rgba(0, 0, 0, 0.55);
- --skeleton-base: #44475a;
- --skeleton-highlight: #4d5066;
- --dg-overlay: color-mix(in srgb, #191a21 58%, transparent);
- }
-
- /* ===== Theme 6: Tokyo Night — 深蓝紫霓虹 // Logan.Li ===== */
- [data-theme="tokyo-night"] {
- --background: 235 25% 12%;
- --foreground: 226 48% 86%;
- --card: 234 26% 16%;
- --card-foreground: 226 48% 86%;
- --popover: 234 26% 16%;
- --popover-foreground: 226 48% 86%;
- --primary: 221 70% 72%;
- --primary-foreground: 235 25% 12%;
- --secondary: 233 23% 22%;
- --secondary-foreground: 226 48% 86%;
- --muted: 233 23% 22%;
- --muted-foreground: 225 15% 58%;
- --accent: 233 23% 22%;
- --accent-foreground: 226 48% 86%;
- --destructive: 350 65% 72%;
- --destructive-foreground: 235 25% 12%;
- --border: 233 20% 26%;
- --input: 233 23% 22%;
- --ring: 221 70% 72%;
- --radius: 0.625rem;
- --sidebar-background: 235 28% 10%;
- --sidebar-foreground: 226 45% 84%;
- --sidebar-primary: 221 70% 72%;
- --sidebar-primary-foreground: 235 25% 12%;
- --sidebar-accent: 233 23% 20%;
- --sidebar-accent-foreground: 226 48% 86%;
- --sidebar-border: 233 20% 24%;
- --sidebar-ring: 221 70% 72%;
- --dg-bg-primary: #1a1b26;
- --dg-bg-secondary: #24283b;
- --dg-bg-tertiary: #2f3549;
- --dg-bg-hover: #3b4261;
- --dg-bg-active: #414868;
- --dg-border: #3b4261;
- --dg-border-light: #292e42;
- --dg-border-hover: #565f89;
- --dg-text-primary: #c0caf5;
- --dg-text-secondary: #9aa5ce;
- --dg-text-muted: #737aa2;
- --dg-blue: #7aa2f7;
- --dg-green: #9ece6a;
- --dg-red: #f7768e;
- --dg-orange: #ff9e64;
- --dg-purple: #bb9af7;
- --dg-cyan: #7dcfff;
- --dg-yellow: #e0af68;
- --dg-card-hover-border: rgba(122, 162, 247, 0.45);
- --dg-gradient-start: #7aa2f7;
- --dg-gradient-end: #bb9af7;
- --dg-gradient-text-start: #7aa2f7;
- --dg-gradient-text-end: #7dcfff;
- --dg-input-focus-ring: rgba(122, 162, 247, 0.22);
- --chart-grid: #3b4261;
- --chart-axis: #737aa2;
- --chart-tooltip-bg: #24283b;
- --chart-tooltip-border: #3b4261;
- --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(122, 162, 247, 0.06);
- --shadow-card-hover: 0 8px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(187, 154, 247, 0.18);
- --shadow-dropdown: 0 10px 40px rgba(0, 0, 0, 0.55);
- --skeleton-base: #2f3549;
- --skeleton-highlight: #3b4261;
- --dg-overlay: color-mix(in srgb, #15161e 58%, transparent);
- }
-
- /* ===== Theme 7: Nord(保留兼容,已从选择器下架) // Logan.Li ===== */
- [data-theme="nord"] {
- --background: 220 16% 22%;
- --foreground: 218 27% 92%;
- --card: 220 16% 19%;
- --card-foreground: 218 27% 92%;
- --popover: 220 16% 19%;
- --popover-foreground: 218 27% 92%;
- --primary: 193 43% 67%;
- --primary-foreground: 220 16% 22%;
- --secondary: 220 16% 28%;
- --secondary-foreground: 218 27% 92%;
- --muted: 220 16% 28%;
- --muted-foreground: 220 16% 56%;
- --accent: 220 16% 28%;
- --accent-foreground: 218 27% 92%;
- --destructive: 354 42% 56%;
- --destructive-foreground: 218 27% 92%;
- --border: 220 16% 28%;
- --input: 220 16% 28%;
- --ring: 193 43% 67%;
- --radius: 0.625rem;
- --sidebar-background: 220 16% 18%;
- --sidebar-foreground: 218 27% 88%;
- --sidebar-primary: 193 43% 67%;
- --sidebar-primary-foreground: 220 16% 22%;
- --sidebar-accent: 220 16% 28%;
- --sidebar-accent-foreground: 218 27% 92%;
- --sidebar-border: 220 16% 28%;
- --sidebar-ring: 193 43% 67%;
- --dg-bg-primary: #2e3440;
- --dg-bg-secondary: #3b4252;
- --dg-bg-tertiary: #434c5e;
- --dg-bg-hover: #4c566a;
- --dg-bg-active: #5e6a7e;
- --dg-border: #4c566a;
- --dg-border-light: #434c5e;
- --dg-border-hover: #5e6a7e;
- --dg-text-primary: #eceff4;
- --dg-text-secondary: #d8dee9;
- --dg-text-muted: #a0a8b8;
- --dg-blue: #81a1c1;
- --dg-green: #a3be8c;
- --dg-red: #bf616a;
- --dg-orange: #d08770;
- --dg-purple: #b48ead;
- --dg-cyan: #88c0d0;
- --dg-yellow: #ebcb8b;
- --dg-card-hover-border: rgba(136, 192, 208, 0.45);
- --dg-gradient-start: #5e81ac;
- --dg-gradient-end: #88c0d0;
- --dg-gradient-text-start: #88c0d0;
- --dg-gradient-text-end: #81a1c1;
- --dg-input-focus-ring: rgba(136, 192, 208, 0.2);
- --chart-grid: #4c566a;
- --chart-axis: #a0a8b8;
- --chart-tooltip-bg: #3b4252;
- --chart-tooltip-border: #4c566a;
- --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(136, 192, 208, 0.05);
- --shadow-card-hover: 0 8px 32px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(136, 192, 208, 0.15);
- --shadow-dropdown: 0 10px 40px rgba(0, 0, 0, 0.5);
- --skeleton-base: #434c5e;
- --skeleton-highlight: #4c566a;
- --dg-overlay: color-mix(in srgb, #2e3440 55%, transparent);
- }
-
/*
* ===== AIOps 设计令牌(Design Tokens)// Logan.Li =====
*
@@ -482,8 +149,7 @@
* 布局:--space-page 页面区块 | --layout-* 应用壳(侧栏/顶栏/内边距)
* 告警:--alert-warning-* / --alert-error-* 横幅语义色
* 主题:data-theme-preference 用户选择 | data-theme 实际生效主题
- * 主流:system / ocean-deep(蓝黑) / light-professional
- * 开发者:one-dark(暖灰) / dracula(紫粉) / tokyo-night(霓虹) / catppuccin
+ * 仅保留 双主题:ocean-deep(深海蓝暗色) / light-professional(明亮白浅色) + system 跟随系统
*
* 布局层级:dg-app-shell → dg-app-content → PageShell(.dg-page) → ContentPanel
*/
diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts
index ff68c58..b8bcfed 100644
--- a/frontend/src/utils/theme.ts
+++ b/frontend/src/utils/theme.ts
@@ -1,4 +1,4 @@
-// 主题常量与持久化 — 主流主题 + 开发者主题 + 跟随系统 // Logan.Li
+// 主题常量与持久化 — 双主题(深海蓝暗色 / 明亮白浅色)+ 跟随系统 // Logan.Li
import { getItem, setItem, STORAGE_KEYS } from './storage';
import i18n from '@/i18n';
@@ -7,12 +7,7 @@ import i18n from '@/i18n';
export type ThemePreference =
| 'system'
| 'ocean-deep'
- | 'light-professional'
- | 'one-dark'
- | 'catppuccin'
- | 'dracula'
- | 'tokyo-night'
- | 'nord';
+ | 'light-professional';
/** 实际应用到 data-theme 的具体主题 */
export type ResolvedTheme = Exclude;
@@ -30,30 +25,18 @@ export interface ThemeGroup {
options: ThemeOption[];
}
-/** 主流主题 — 默认推荐 */
+/** 主题清单 — 仅保留一暗一亮,避免多个暗色主题视觉重复 // Logan.Li */
const MAINSTREAM_THEMES: ThemeOption[] = [
{ id: 'system', name: i18n.t('common.lightDark'), description: i18n.t('common.themets.s17d84295'), isDark: false, primaryColor: 'linear-gradient(135deg, #2563eb 50%, #0d1117 50%)' },
{ id: 'ocean-deep', name: i18n.t('common.themets.s2f82cbb2'), description: i18n.t('common.themets.s29ee972b'), isDark: true, primaryColor: '#0d1117' },
{ id: 'light-professional', name: i18n.t('common.themets.s2d43cc04'), description: i18n.t('common.themets.s37e76182'), isDark: false, primaryColor: '#2563eb' },
];
-/** 开发者主题 — 高辨识度扩展 */
-const DEVELOPER_THEMES: ThemeOption[] = [
- { id: 'one-dark', name: 'One Dark', description: i18n.t('common.themets.s02b08e05'), isDark: true, primaryColor: '#c678dd' },
- { id: 'dracula', name: 'Dracula', description: i18n.t('common.themets.s525ce260'), isDark: true, primaryColor: '#bd93f9' },
- { id: 'tokyo-night', name: 'Tokyo Night', description: i18n.t('common.themets.s6f40fb5e'), isDark: true, primaryColor: '#7aa2f7' },
- { id: 'catppuccin', name: 'Catppuccin', description: i18n.t('common.themets.s571aa09d'), isDark: true, primaryColor: '#89b4fa' },
-];
-
export const THEME_GROUPS: ThemeGroup[] = [
{ label: i18n.t('common.themets.s8392cae7'), options: MAINSTREAM_THEMES },
- { label: i18n.t('common.themets.sc2e48855'), options: DEVELOPER_THEMES },
];
-export const THEME_OPTIONS: ThemeOption[] = [
- ...MAINSTREAM_THEMES,
- ...DEVELOPER_THEMES,
-];
+export const THEME_OPTIONS: ThemeOption[] = [...MAINSTREAM_THEMES];
export const THEME_ORDER: ThemePreference[] = THEME_OPTIONS.map((o) => o.id);
export const DEFAULT_THEME: ThemePreference = 'system';
@@ -61,10 +44,15 @@ export const DEFAULT_THEME: ThemePreference = 'system';
const LEGACY_THEME_MAP: Record = {
dark: 'ocean-deep',
light: 'light-professional',
- 'midnight-purple': 'one-dark',
- 'pine-green': 'catppuccin',
- 'orange-vitality': 'tokyo-night',
- nord: 'tokyo-night',
+ // 已下架的旧主题与开发者主题统一迁移到深海蓝,保证存量用户不掉样式。 // Logan.Li
+ 'midnight-purple': 'ocean-deep',
+ 'pine-green': 'ocean-deep',
+ 'orange-vitality': 'ocean-deep',
+ nord: 'ocean-deep',
+ 'one-dark': 'ocean-deep',
+ dracula: 'ocean-deep',
+ 'tokyo-night': 'ocean-deep',
+ catppuccin: 'ocean-deep',
};
export function migrateLegacyTheme(value: string | null): ThemePreference | null {
@@ -103,11 +91,6 @@ export function getInitialTheme(): ThemePreference {
if (stored && THEME_ORDER.includes(stored as ThemePreference)) {
return stored as ThemePreference;
}
- /* nord 已下架,自动迁移到 Tokyo Night // Logan.Li */
- if (stored === 'nord') {
- setItem(STORAGE_KEYS.theme, 'tokyo-night');
- return 'tokyo-night';
- }
return DEFAULT_THEME;
}
@@ -126,4 +109,4 @@ export function applyThemeToDocument(pref: ThemePreference): void {
export function getNextTheme(current: ThemePreference): ThemePreference {
const idx = THEME_ORDER.indexOf(current);
return THEME_ORDER[(idx + 1) % THEME_ORDER.length];
-}
\ No newline at end of file
+}