From 9f49ce6dc99b4159ad97e07b2413ea9cfe2e6218 Mon Sep 17 00:00:00 2001 From: beyondkmp Date: Fri, 30 May 2025 15:10:58 +0800 Subject: [PATCH] refactor: Theme improve (#6619) * refactor(IpcChannel): rename theme change event and streamline theme handling - Updated the IpcChannel enum to rename 'theme:change' to 'theme:updated' for clarity. - Refactored theme handling in ipc.ts to utilize a new ThemeService, simplifying theme updates and event broadcasting. - Adjusted various components to consistently use the updated theme variable naming convention. * refactor(Theme): standardize theme handling across components - Updated theme retrieval to use 'actualTheme' instead of 'theme' for consistency. - Changed default theme setting from 'auto' to 'system' in ConfigManager and related components. - Adjusted theme handling in various components to reflect the new naming convention and ensure proper theme application. * fix(Theme): improve theme handling and migration logic - Added a console log for debugging theme transitions in ThemeProvider. - Updated ThemeService to ensure theme is set correctly when changed. - Incremented version number in store configuration to reflect changes. - Enhanced migration logic to convert 'auto' theme setting to 'system' for better consistency. * feat(Theme): add getTheme IPC channel and improve theme management - Introduced a new IPC channel 'App_GetTheme' to retrieve the current theme. - Updated ThemeService to include a method for getting the current theme. - Refactored theme initialization in WindowService to ensure proper theme setup. - Enhanced theme handling in various components to utilize the new theme retrieval method. * fix(ThemeService): improve theme initialization and retrieval logic - Set default theme to 'system' and updated theme initialization to handle legacy versions. - Enhanced getTheme method to return both the current theme and the actual theme based on nativeTheme settings. - Removed redundant initTheme method from ThemeService and ensured themeService is imported in WindowService for proper initialization. - Updated ThemeProvider to handle the new structure of the theme retrieval response. * refactor(Settings): remove theme management from settings - Eliminated theme-related state and actions from the settings slice. - Updated useSettings hook to remove theme handling functionality. - Cleaned up imports by removing unused ThemeMode type. * refactor(Theme): update theme retrieval in GeneralSettings and HomeWindow - Restored theme retrieval in GeneralSettings and HomeWindow components. - Adjusted imports to ensure proper theme management. - Updated theme condition checks to utilize the ThemeMode enumeration for consistency. * refactor(Theme): update theme terminology and retrieval in Sidebar and DisplaySettings - Changed theme label from 'auto' to 'system' in multiple localization files for consistency. - Updated Sidebar component to reflect the new theme terminology. - Adjusted DisplaySettings to display the updated theme label. * refactor(ThemeProvider): initialize theme state from API response * refactor(ThemeProvider): reset theme state to default values and streamline initialization logic * refactor(Theme): enhance theme management by incorporating 'system' mode and updating state handling - Updated ThemeService to include 'system' as a valid theme option. - Refactored ThemeProvider to utilize useSettings for theme state management and ensure proper initialization. - Adjusted useSettings to include theme setting functionality. - Modified settings slice to manage theme state effectively. * refactor(WindowService, ThemeProvider, Messages, HomeWindow): streamline imports and clean up unused variables - Removed duplicate import of ThemeService in WindowService. - Adjusted import order in ThemeProvider for clarity. - Simplified useSettings destructuring in Messages component. - Cleaned up unused ThemeMode import in HomeWindow. * refactor(Theme): standardize theme usage across components by replacing 'actualTheme' with 'theme' - Updated components to consistently use 'theme' instead of 'actualTheme' for better clarity and maintainability. - Adjusted ThemeProvider to reflect changes in theme state management. - Ensured all relevant components are aligned with the new theme structure. * refactor(Theme): remove unused theme retrieval functionality - Eliminated the App_GetTheme channel and associated methods from ThemeService and IPC handling. - Updated components to use the new theme structure, replacing 'actualTheme' with 'settedTheme' for consistency. - Ensured all theme-related functionalities are streamlined and aligned with the latest changes. * refactor(Theme): update theme variable usage in ChatFlowHistory and GeneralSettings - Replaced 'theme' with 'settedTheme' in ChatFlowHistory for consistency with recent theme structure changes. - Simplified theme destructuring in GeneralSettings by removing unused 'themeMode' variable. - Ensured alignment with the latest theme management updates across components. * refactor(Theme): update theme variable in GeneralSettings component - Replaced 'themeMode' with 'theme' in GeneralSettings for consistency with recent theme structure changes. - Ensured alignment with the latest theme management updates across components. --------- Co-authored-by: beyondkmp --- packages/shared/IpcChannel.ts | 2 +- src/main/ipc.ts | 33 +------- src/main/services/ConfigManager.ts | 2 +- src/main/services/ThemeService.ts | 48 ++++++++++++ src/main/services/WindowService.ts | 11 +-- src/preload/index.ts | 4 +- src/renderer/src/components/app/Sidebar.tsx | 9 ++- src/renderer/src/context/ThemeProvider.tsx | 75 +++++++++---------- src/renderer/src/i18n/locales/en-us.json | 2 +- src/renderer/src/i18n/locales/ja-jp.json | 2 +- src/renderer/src/i18n/locales/ru-ru.json | 2 +- src/renderer/src/i18n/locales/zh-cn.json | 2 +- src/renderer/src/i18n/locales/zh-tw.json | 2 +- src/renderer/src/i18n/translate/el-gr.json | 2 +- src/renderer/src/i18n/translate/es-es.json | 2 +- src/renderer/src/i18n/translate/fr-fr.json | 2 +- src/renderer/src/i18n/translate/pt-pt.json | 2 +- .../pages/home/Messages/ChatFlowHistory.tsx | 4 +- .../DisplaySettings/DisplaySettings.tsx | 13 ++-- .../src/pages/settings/GeneralSettings.tsx | 5 +- src/renderer/src/store/settings.ts | 2 +- src/renderer/src/types/index.ts | 2 +- .../src/windows/mini/home/HomeWindow.tsx | 12 ++- 23 files changed, 125 insertions(+), 115 deletions(-) create mode 100644 src/main/services/ThemeService.ts diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index bf1d2236e1..8c74ffcaed 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -144,7 +144,7 @@ export enum IpcChannel { // events BackupProgress = 'backup-progress', - ThemeChange = 'theme:change', + ThemeUpdated = 'theme:updated', UpdateDownloadedCancelled = 'update-downloaded-cancelled', RestoreProgress = 'restore-progress', UpdateError = 'update-error', diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 7773589bed..2fd60377c8 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -6,11 +6,10 @@ import { getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/pro import { handleZoomFactor } from '@main/utils/zoom' import { IpcChannel } from '@shared/IpcChannel' import { Shortcut, ThemeMode } from '@types' -import { BrowserWindow, ipcMain, nativeTheme, session, shell } from 'electron' +import { BrowserWindow, ipcMain, session, shell } from 'electron' import log from 'electron-log' import { Notification } from 'src/renderer/src/types/notification' -import { titleBarOverlayDark, titleBarOverlayLight } from './config' import AppUpdater from './services/AppUpdater' import BackupManager from './services/BackupManager' import { configManager } from './services/ConfigManager' @@ -28,6 +27,7 @@ import { searchService } from './services/SearchService' import { SelectionService } from './services/SelectionService' import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService' import storeSyncService from './services/StoreSyncService' +import { themeService } from './services/ThemeService' import { setOpenLinkExternal } from './services/WebviewService' import { windowService } from './services/WindowService' import { calculateDirectorySize, getResourcePath } from './utils' @@ -122,34 +122,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { // theme ipcMain.handle(IpcChannel.App_SetTheme, (_, theme: ThemeMode) => { - const updateTitleBarOverlay = () => { - if (!mainWindow?.setTitleBarOverlay) return - const isDark = nativeTheme.shouldUseDarkColors - mainWindow.setTitleBarOverlay(isDark ? titleBarOverlayDark : titleBarOverlayLight) - } - - const broadcastThemeChange = () => { - const isDark = nativeTheme.shouldUseDarkColors - const effectiveTheme = isDark ? ThemeMode.dark : ThemeMode.light - BrowserWindow.getAllWindows().forEach((win) => win.webContents.send(IpcChannel.ThemeChange, effectiveTheme)) - } - - const notifyThemeChange = () => { - updateTitleBarOverlay() - broadcastThemeChange() - } - - if (theme === ThemeMode.auto) { - nativeTheme.themeSource = 'system' - nativeTheme.on('updated', notifyThemeChange) - } else { - nativeTheme.themeSource = theme - nativeTheme.off('updated', notifyThemeChange) - } - - updateTitleBarOverlay() - configManager.setTheme(theme) - notifyThemeChange() + themeService.setTheme(theme) }) ipcMain.handle(IpcChannel.App_HandleZoomFactor, (_, delta: number, reset: boolean = false) => { diff --git a/src/main/services/ConfigManager.ts b/src/main/services/ConfigManager.ts index 5327aebbf7..fbe871cbb4 100644 --- a/src/main/services/ConfigManager.ts +++ b/src/main/services/ConfigManager.ts @@ -43,7 +43,7 @@ export class ConfigManager { } getTheme(): ThemeMode { - return this.get(ConfigKeys.Theme, ThemeMode.auto) + return this.get(ConfigKeys.Theme, ThemeMode.system) } setTheme(theme: ThemeMode) { diff --git a/src/main/services/ThemeService.ts b/src/main/services/ThemeService.ts new file mode 100644 index 0000000000..7ccaf3bf9a --- /dev/null +++ b/src/main/services/ThemeService.ts @@ -0,0 +1,48 @@ +import { IpcChannel } from '@shared/IpcChannel' +import { ThemeMode } from '@types' +import { BrowserWindow, nativeTheme } from 'electron' + +import { titleBarOverlayDark, titleBarOverlayLight } from '../config' +import { configManager } from './ConfigManager' + +class ThemeService { + private theme: ThemeMode = ThemeMode.system + constructor() { + this.theme = configManager.getTheme() + + if (this.theme === ThemeMode.dark || this.theme === ThemeMode.light || this.theme === ThemeMode.system) { + nativeTheme.themeSource = this.theme + } else { + // 兼容旧版本 + configManager.setTheme(ThemeMode.system) + nativeTheme.themeSource = ThemeMode.system + } + nativeTheme.on('updated', this.themeUpdatadHandler.bind(this)) + } + + themeUpdatadHandler() { + BrowserWindow.getAllWindows().forEach((win) => { + if (win && !win.isDestroyed() && win.setTitleBarOverlay) { + try { + win.setTitleBarOverlay(nativeTheme.shouldUseDarkColors ? titleBarOverlayDark : titleBarOverlayLight) + } catch (error) { + // don't throw error if setTitleBarOverlay failed + // Because it may be called with some windows have some title bar + } + } + win.webContents.send(IpcChannel.ThemeUpdated, nativeTheme.shouldUseDarkColors ? ThemeMode.dark : ThemeMode.light) + }) + } + + setTheme(theme: ThemeMode) { + if (theme === this.theme) { + return + } + + this.theme = theme + nativeTheme.themeSource = theme + configManager.setTheme(theme) + } +} + +export const themeService = new ThemeService() diff --git a/src/main/services/WindowService.ts b/src/main/services/WindowService.ts index b67cac03d6..1cdcc2754d 100644 --- a/src/main/services/WindowService.ts +++ b/src/main/services/WindowService.ts @@ -1,8 +1,10 @@ +// just import the themeService to ensure the theme is initialized +import './ThemeService' + import { is } from '@electron-toolkit/utils' import { isDev, isLinux, isMac, isWin } from '@main/constant' import { getFilesDir } from '@main/utils/file' import { IpcChannel } from '@shared/IpcChannel' -import { ThemeMode } from '@types' import { app, BrowserWindow, nativeTheme, shell } from 'electron' import Logger from 'electron-log' import windowStateKeeper from 'electron-window-state' @@ -45,13 +47,6 @@ export class WindowService { maximize: false }) - const theme = configManager.getTheme() - if (theme === ThemeMode.auto) { - nativeTheme.themeSource = 'system' - } else { - nativeTheme.themeSource = theme - } - this.mainWindow = new BrowserWindow({ x: mainWindowState.x, y: mainWindowState.y, diff --git a/src/preload/index.ts b/src/preload/index.ts index 25b8bf8c7a..5e9f3681cc 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,7 +1,7 @@ import type { ExtractChunkData } from '@cherrystudio/embedjs-interfaces' import { electronAPI } from '@electron-toolkit/preload' import { IpcChannel } from '@shared/IpcChannel' -import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, WebDavConfig } from '@types' +import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, ThemeMode, WebDavConfig } from '@types' import { contextBridge, ipcRenderer, OpenDialogOptions, shell, webUtils } from 'electron' import { Notification } from 'src/renderer/src/types/notification' import { CreateDirectoryOptions } from 'webdav' @@ -20,7 +20,7 @@ const api = { setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchToTray, isActive), setTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTray, isActive), setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTrayOnClose, isActive), - setTheme: (theme: 'light' | 'dark' | 'auto') => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme), + setTheme: (theme: ThemeMode) => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme), handleZoomFactor: (delta: number, reset: boolean = false) => ipcRenderer.invoke(IpcChannel.App_HandleZoomFactor, delta, reset), setAutoUpdate: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetAutoUpdate, isActive), diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx index 1474b80c00..c85fdcd2c2 100644 --- a/src/renderer/src/components/app/Sidebar.tsx +++ b/src/renderer/src/components/app/Sidebar.tsx @@ -9,6 +9,7 @@ import { useMinapps } from '@renderer/hooks/useMinapps' import useNavBackgroundColor from '@renderer/hooks/useNavBackgroundColor' import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime' import { useSettings } from '@renderer/hooks/useSettings' +import { ThemeMode } from '@renderer/types' import { isEmoji } from '@renderer/utils' import type { MenuProps } from 'antd' import { Avatar, Dropdown, Tooltip } from 'antd' @@ -44,7 +45,7 @@ const Sidebar: FC = () => { const { pathname } = useLocation() const navigate = useNavigate() - const { theme, settingTheme, toggleTheme } = useTheme() + const { theme, settedTheme, toggleTheme } = useTheme() const avatar = useAvatar() const { t } = useTranslation() @@ -104,13 +105,13 @@ const Sidebar: FC = () => { toggleTheme()}> - {settingTheme === 'dark' ? ( + {settedTheme === ThemeMode.dark ? ( - ) : settingTheme === 'light' ? ( + ) : settedTheme === ThemeMode.light ? ( ) : ( diff --git a/src/renderer/src/context/ThemeProvider.tsx b/src/renderer/src/context/ThemeProvider.tsx index 968a0df81f..a1281983e4 100644 --- a/src/renderer/src/context/ThemeProvider.tsx +++ b/src/renderer/src/context/ThemeProvider.tsx @@ -7,13 +7,13 @@ import React, { createContext, PropsWithChildren, use, useEffect, useState } fro interface ThemeContextType { theme: ThemeMode - settingTheme: ThemeMode + settedTheme: ThemeMode toggleTheme: () => void } const ThemeContext = createContext({ - theme: ThemeMode.auto, - settingTheme: ThemeMode.auto, + theme: ThemeMode.system, + settedTheme: ThemeMode.dark, toggleTheme: () => {} }) @@ -21,53 +21,50 @@ interface ThemeProviderProps extends PropsWithChildren { defaultTheme?: ThemeMode } -export const ThemeProvider: React.FC = ({ children, defaultTheme }) => { - const { theme, setTheme } = useSettings() - const [effectiveTheme, setEffectiveTheme] = useState(theme) +export const ThemeProvider: React.FC = ({ children }) => { + // 用户设置的主题 + const { theme: settedTheme, setTheme: setSettedTheme } = useSettings() + const [actualTheme, setActualTheme] = useState( + window.matchMedia('(prefers-color-scheme: dark)').matches ? ThemeMode.dark : ThemeMode.light + ) const { initUserTheme } = useUserTheme() const toggleTheme = () => { - // 主题顺序是light, dark, auto, 所以需要先判断当前主题,然后取下一个主题 - switch (theme) { - case ThemeMode.light: - setTheme(ThemeMode.dark) - break - case ThemeMode.dark: - setTheme(ThemeMode.auto) - break - case ThemeMode.auto: - setTheme(ThemeMode.light) - break - } + const nextTheme = { + [ThemeMode.light]: ThemeMode.dark, + [ThemeMode.dark]: ThemeMode.system, + [ThemeMode.system]: ThemeMode.light + }[settedTheme] + setSettedTheme(nextTheme || ThemeMode.system) } useEffect(() => { - window.api?.setTheme(defaultTheme || theme) - }, [defaultTheme, theme]) - - useEffect(() => { - document.body.setAttribute('theme-mode', effectiveTheme) - }, [effectiveTheme]) - - useEffect(() => { + // Set initial theme and OS attributes on body document.body.setAttribute('os', isMac ? 'mac' : 'windows') - const themeChangeListenerRemover = window.electron.ipcRenderer.on( - IpcChannel.ThemeChange, - (_, realTheam: ThemeMode) => { - setEffectiveTheme(realTheam) - } - ) - return () => { - themeChangeListenerRemover() - } - }) + document.body.setAttribute('theme-mode', actualTheme) + + // if theme is old auto, then set theme to system + // we can delete this after next big release + if (settedTheme !== ThemeMode.dark && settedTheme !== ThemeMode.light && settedTheme !== ThemeMode.system) { + setSettedTheme(ThemeMode.system) + } - useEffect(() => { initUserTheme() - // eslint-disable-next-line react-hooks/exhaustive-deps + + // listen for theme updates from main process + const cleanup = window.electron.ipcRenderer.on(IpcChannel.ThemeUpdated, (_, actualTheme: ThemeMode) => { + document.body.setAttribute('theme-mode', actualTheme) + setActualTheme(actualTheme) + }) + + return cleanup }, []) - return {children} + useEffect(() => { + window.api.setTheme(settedTheme) + }, [settedTheme]) + + return {children} } export const useTheme = () => use(ThemeContext) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 0103dd54b7..cced18b132 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1692,7 +1692,7 @@ "zoom_out": "Zoom Out", "zoom_reset": "Reset Zoom" }, - "theme.auto": "Auto", + "theme.system": "System", "theme.dark": "Dark", "theme.light": "Light", "theme.title": "Theme", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 9deea01c9c..c96206a442 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1681,7 +1681,7 @@ "zoom_out": "ズームアウト", "zoom_reset": "ズームをリセット" }, - "theme.auto": "自動", + "theme.system": "システム", "theme.dark": "ダーク", "theme.light": "ライト", "theme.title": "テーマ", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index c21074200a..08c4c1b7a4 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1681,7 +1681,7 @@ "zoom_out": "Уменьшить", "zoom_reset": "Сбросить масштаб" }, - "theme.auto": "Автоматически", + "theme.system": "Системная", "theme.dark": "Темная", "theme.light": "Светлая", "theme.title": "Тема", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index ce3c764678..a7697b65f8 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1691,7 +1691,7 @@ "zoom_out": "缩小界面", "zoom_reset": "重置缩放" }, - "theme.auto": "自动", + "theme.system": "系统", "theme.dark": "深色", "theme.light": "浅色", "theme.title": "主题", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index b6f4a97d4e..342ee68267 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1684,7 +1684,7 @@ "zoom_reset": "重設縮放", "exit_fullscreen": "退出螢幕" }, - "theme.auto": "自動", + "theme.system": "系統", "theme.dark": "深色", "theme.light": "淺色", "theme.title": "主題", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index 6324944902..cc2ce04044 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -1478,7 +1478,7 @@ "zoom_out": "Σμικρύνση εμφάνισης", "zoom_reset": "Επαναφορά εμφάνισης" }, - "theme.auto": "Αυτόματο", + "theme.system": "Σύστημα", "theme.dark": "Σκοτεινό", "theme.light": "Φωτεινό", "theme.title": "Θέμα", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 201945e2f5..48b1c67d03 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -1477,7 +1477,7 @@ "zoom_out": "Reducir interfaz", "zoom_reset": "Restablecer zoom" }, - "theme.auto": "Automático", + "theme.system": "Sistema", "theme.dark": "Oscuro", "theme.light": "Claro", "theme.title": "Tema", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 3ae3ff0a97..9513c1dc94 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -1478,7 +1478,7 @@ "zoom_out": "Réduire l'interface", "zoom_reset": "Réinitialiser le zoom" }, - "theme.auto": "Automatique", + "theme.system": "Système", "theme.dark": "Sombre", "theme.light": "Clair", "theme.title": "Thème", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index f59ce49ddd..5c2bf82e67 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -1480,7 +1480,7 @@ "zoom_out": "Diminuir interface", "zoom_reset": "Redefinir zoom" }, - "theme.auto": "Automático", + "theme.system": "Sistema", "theme.dark": "Escuro", "theme.light": "Claro", "theme.title": "Tema", diff --git a/src/renderer/src/pages/home/Messages/ChatFlowHistory.tsx b/src/renderer/src/pages/home/Messages/ChatFlowHistory.tsx index 99d3c51193..1acf5cd284 100644 --- a/src/renderer/src/pages/home/Messages/ChatFlowHistory.tsx +++ b/src/renderer/src/pages/home/Messages/ChatFlowHistory.tsx @@ -199,7 +199,7 @@ const ChatFlowHistory: FC = ({ conversationId }) => { const [edges, setEdges, onEdgesChange] = useEdgesState([]) const [loading, setLoading] = useState(true) const { userName } = useSettings() - const { theme } = useTheme() + const { settedTheme } = useTheme() const topicId = conversationId @@ -491,7 +491,7 @@ const ChatFlowHistory: FC = ({ conversationId }) => { }} proOptions={{ hideAttribution: true }} className="react-flow-container" - colorMode={theme === 'auto' ? 'system' : theme}> + colorMode={settedTheme}> ` const DisplaySettings: FC = () => { const { - setTheme, - theme, windowStyle, setWindowStyle, topicPosition, @@ -65,10 +63,11 @@ const DisplaySettings: FC = () => { pinTopicsToTop, customCss, sidebarIcons, + setTheme, assistantIconType, userTheme } = useSettings() - const { theme: themeMode } = useTheme() + const { theme, settedTheme } = useTheme() const { t } = useTranslation() const dispatch = useAppDispatch() const [currentZoom, setCurrentZoom] = useState(1.0) @@ -121,11 +120,11 @@ const DisplaySettings: FC = () => { ) }, { - value: ThemeMode.auto, + value: ThemeMode.system, label: (
- {t('settings.theme.auto')} + {t('settings.theme.system')}
) } @@ -168,13 +167,13 @@ const DisplaySettings: FC = () => { ) return ( - + {t('settings.display.title')} {t('settings.theme.title')} - + diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx index 8435e542ea..7665099f23 100644 --- a/src/renderer/src/pages/settings/GeneralSettings.tsx +++ b/src/renderer/src/pages/settings/GeneralSettings.tsx @@ -19,7 +19,6 @@ const GeneralSettings: FC = () => { const { language, proxyUrl: storeProxyUrl, - theme, setLaunch, setTray, launchOnBoot, @@ -30,7 +29,7 @@ const GeneralSettings: FC = () => { enableDataCollection } = useSettings() const [proxyUrl, setProxyUrl] = useState(storeProxyUrl) - const { theme: themeMode } = useTheme() + const { theme } = useTheme() const updateTray = (isShowTray: boolean) => { setTray(isShowTray) @@ -116,7 +115,7 @@ const GeneralSettings: FC = () => { } return ( - + {t('settings.general.title')} diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index 75e3352bd2..d8e778866c 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -198,7 +198,7 @@ export const initialState: SettingsState = { launchToTray: false, trayOnClose: true, tray: true, - theme: ThemeMode.auto, + theme: ThemeMode.system, userTheme: { colorPrimary: '#00b96b' }, diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 5a08a74bfb..cb62285be6 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -317,7 +317,7 @@ export enum FileTypes { export enum ThemeMode { light = 'light', dark = 'dark', - auto = 'auto' + system = 'system' } export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'el-GR' | 'en-US' | 'es-ES' | 'fr-FR' | 'ja-JP' | 'pt-PT' | 'ru-RU' diff --git a/src/renderer/src/windows/mini/home/HomeWindow.tsx b/src/renderer/src/windows/mini/home/HomeWindow.tsx index 6b61903c3e..9982647464 100644 --- a/src/renderer/src/windows/mini/home/HomeWindow.tsx +++ b/src/renderer/src/windows/mini/home/HomeWindow.tsx @@ -1,4 +1,5 @@ import { isMac } from '@renderer/config/constant' +import { useTheme } from '@renderer/context/ThemeProvider' import { useDefaultAssistant, useDefaultModel } from '@renderer/hooks/useAssistant' import { useSettings } from '@renderer/hooks/useSettings' import i18n from '@renderer/i18n' @@ -9,6 +10,7 @@ import store from '@renderer/store' import { upsertManyBlocks } from '@renderer/store/messageBlock' import { updateOneBlock, upsertOneBlock } from '@renderer/store/messageBlock' import { newMessagesActions } from '@renderer/store/newMessage' +import { ThemeMode } from '@renderer/types' import { Chunk, ChunkType } from '@renderer/types/chunk' import { AssistantMessageStatus } from '@renderer/types/newMessage' import { MessageBlockStatus } from '@renderer/types/newMessage' @@ -43,7 +45,8 @@ const HomeWindow: FC = () => { const { defaultModel, quickAssistantModel } = useDefaultModel() // 如果 quickAssistantModel 未設定,則使用 defaultModel const model = quickAssistantModel || defaultModel - const { language, readClipboardAtStartup, windowStyle, theme } = useSettings() + const { language, readClipboardAtStartup, windowStyle } = useSettings() + const { theme } = useTheme() const { t } = useTranslation() const inputBarRef = useRef(null) const featureMenusRef = useRef(null) @@ -258,12 +261,7 @@ const HomeWindow: FC = () => { const backgroundColor = () => { // ONLY MAC: when transparent style + light theme: use vibrancy effect // because the dark style under mac's vibrancy effect has not been implemented - if ( - isMac && - windowStyle === 'transparent' && - theme === 'light' && - !window.matchMedia('(prefers-color-scheme: dark)').matches - ) { + if (isMac && windowStyle === 'transparent' && theme === ThemeMode.light) { return 'transparent' }