From acaac507b17176f730495dc71656475aa50d9169 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:23:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=B3=BB=E7=BB=9F=E6=B7=B1?= =?UTF-8?q?=E6=B5=85=E8=87=AA=E9=80=82=E5=BA=94=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 31 ++++++++++++++++++++++--------- src/pages/SettingsPage.tsx | 15 +++++++++++++-- src/services/config.ts | 6 +++--- src/stores/themeStore.ts | 2 +- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 6bbf9dc..af5fcdf 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -25,7 +25,7 @@ import NotificationWindow from './pages/NotificationWindow' import AIChatPage from './pages/AIChatPage' import { useAppStore } from './stores/appStore' -import { themes, useThemeStore, type ThemeId } from './stores/themeStore' +import { themes, useThemeStore, type ThemeId, type ThemeMode } from './stores/themeStore' import * as configService from './services/config' import { Download, X, Shield } from 'lucide-react' import './App.scss' @@ -101,14 +101,27 @@ function App() { // 应用主题 useEffect(() => { - document.documentElement.setAttribute('data-theme', currentTheme) - document.documentElement.setAttribute('data-mode', themeMode) - - // 更新窗口控件颜色以适配主题 - const symbolColor = themeMode === 'dark' ? '#ffffff' : '#1a1a1a' - if (!isOnboardingWindow && !isNotificationWindow) { - window.electronAPI.window.setTitleBarOverlay({ symbolColor }) + const mq = window.matchMedia('(prefers-color-scheme: dark)') + const applyMode = (mode: ThemeMode, systemDark?: boolean) => { + const effectiveMode = mode === 'system' ? (systemDark ?? mq.matches ? 'dark' : 'light') : mode + document.documentElement.setAttribute('data-theme', currentTheme) + document.documentElement.setAttribute('data-mode', effectiveMode) + const symbolColor = effectiveMode === 'dark' ? '#ffffff' : '#1a1a1a' + if (!isOnboardingWindow && !isNotificationWindow) { + window.electronAPI.window.setTitleBarOverlay({ symbolColor }) + } } + + applyMode(themeMode) + + // 监听系统主题变化 + const handler = (e: MediaQueryListEvent) => { + if (useThemeStore.getState().themeMode === 'system') { + applyMode('system', e.matches) + } + } + mq.addEventListener('change', handler) + return () => mq.removeEventListener('change', handler) }, [currentTheme, themeMode, isOnboardingWindow, isNotificationWindow]) // 读取已保存的主题设置 @@ -122,7 +135,7 @@ function App() { if (savedThemeId && themes.some((theme) => theme.id === savedThemeId)) { setTheme(savedThemeId as ThemeId) } - if (savedThemeMode === 'light' || savedThemeMode === 'dark') { + if (savedThemeMode === 'light' || savedThemeMode === 'dark' || savedThemeMode === 'system') { setThemeMode(savedThemeMode) } } catch (e) { diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 1911acd..d2210e6 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -7,7 +7,7 @@ import { dialog } from '../services/ipc' import * as configService from '../services/config' import { Eye, EyeOff, FolderSearch, FolderOpen, Search, Copy, - RotateCcw, Trash2, Plug, Check, Sun, Moon, + RotateCcw, Trash2, Plug, Check, Sun, Moon, Monitor, Palette, Database, Download, HardDrive, Info, RefreshCw, ChevronDown, Mic, ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe, BarChart2 } from 'lucide-react' @@ -55,6 +55,14 @@ function SettingsPage() { const resetChatStore = useChatStore((state) => state.reset) const { currentTheme, themeMode, setTheme, setThemeMode } = useThemeStore() + const [systemDark, setSystemDark] = useState(() => window.matchMedia('(prefers-color-scheme: dark)').matches) + useEffect(() => { + const mq = window.matchMedia('(prefers-color-scheme: dark)') + const handler = (e: MediaQueryListEvent) => setSystemDark(e.matches) + mq.addEventListener('change', handler) + return () => mq.removeEventListener('change', handler) + }, []) + const effectiveMode = themeMode === 'system' ? (systemDark ? 'dark' : 'light') : themeMode const clearAnalyticsStoreCache = useAnalyticsStore((state) => state.clearCache) const [activeTab, setActiveTab] = useState('appearance') @@ -993,11 +1001,14 @@ function SettingsPage() { +
{themes.map((theme) => (
setTheme(theme.id)}> -
+
diff --git a/src/services/config.ts b/src/services/config.ts index 089a78e..6b5ddc7 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -118,13 +118,13 @@ export async function setWxidConfig(wxid: string, configValue: WxidConfig): Prom } // 获取主题 -export async function getTheme(): Promise<'light' | 'dark'> { +export async function getTheme(): Promise<'light' | 'dark' | 'system'> { const value = await config.get(CONFIG_KEYS.THEME) - return (value as 'light' | 'dark') || 'light' + return (value as 'light' | 'dark' | 'system') || 'light' } // 设置主题 -export async function setTheme(theme: 'light' | 'dark'): Promise { +export async function setTheme(theme: 'light' | 'dark' | 'system'): Promise { await config.set(CONFIG_KEYS.THEME, theme) } diff --git a/src/stores/themeStore.ts b/src/stores/themeStore.ts index 55e0947..df2bd9d 100644 --- a/src/stores/themeStore.ts +++ b/src/stores/themeStore.ts @@ -2,7 +2,7 @@ import { create } from 'zustand' import { persist } from 'zustand/middleware' export type ThemeId = 'cloud-dancer' | 'corundum-blue' | 'kiwi-green' | 'spicy-red' | 'teal-water' -export type ThemeMode = 'light' | 'dark' +export type ThemeMode = 'light' | 'dark' | 'system' export interface ThemeInfo { id: ThemeId