mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 10:40:07 +08:00
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 <beyondkmkp@gmail.com>
This commit is contained in:
parent
0df331cf8a
commit
9f49ce6dc9
@ -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',
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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) {
|
||||
|
||||
48
src/main/services/ThemeService.ts
Normal file
48
src/main/services/ThemeService.ts
Normal file
@ -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()
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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 = () => {
|
||||
</Icon>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t('settings.theme.title') + ': ' + t(`settings.theme.${settingTheme}`)}
|
||||
title={t('settings.theme.title') + ': ' + t(`settings.theme.${settedTheme}`)}
|
||||
mouseEnterDelay={0.8}
|
||||
placement="right">
|
||||
<Icon theme={theme} onClick={() => toggleTheme()}>
|
||||
{settingTheme === 'dark' ? (
|
||||
{settedTheme === ThemeMode.dark ? (
|
||||
<Moon size={20} className="icon" />
|
||||
) : settingTheme === 'light' ? (
|
||||
) : settedTheme === ThemeMode.light ? (
|
||||
<Sun size={20} className="icon" />
|
||||
) : (
|
||||
<SunMoon size={20} className="icon" />
|
||||
|
||||
@ -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<ThemeContextType>({
|
||||
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<ThemeProviderProps> = ({ children, defaultTheme }) => {
|
||||
const { theme, setTheme } = useSettings()
|
||||
const [effectiveTheme, setEffectiveTheme] = useState(theme)
|
||||
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
|
||||
// 用户设置的主题
|
||||
const { theme: settedTheme, setTheme: setSettedTheme } = useSettings()
|
||||
const [actualTheme, setActualTheme] = useState<ThemeMode>(
|
||||
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 <ThemeContext value={{ theme: effectiveTheme, settingTheme: theme, toggleTheme }}>{children}</ThemeContext>
|
||||
useEffect(() => {
|
||||
window.api.setTheme(settedTheme)
|
||||
}, [settedTheme])
|
||||
|
||||
return <ThemeContext value={{ theme: actualTheme, settedTheme, toggleTheme }}>{children}</ThemeContext>
|
||||
}
|
||||
|
||||
export const useTheme = () => use(ThemeContext)
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -1681,7 +1681,7 @@
|
||||
"zoom_out": "ズームアウト",
|
||||
"zoom_reset": "ズームをリセット"
|
||||
},
|
||||
"theme.auto": "自動",
|
||||
"theme.system": "システム",
|
||||
"theme.dark": "ダーク",
|
||||
"theme.light": "ライト",
|
||||
"theme.title": "テーマ",
|
||||
|
||||
@ -1681,7 +1681,7 @@
|
||||
"zoom_out": "Уменьшить",
|
||||
"zoom_reset": "Сбросить масштаб"
|
||||
},
|
||||
"theme.auto": "Автоматически",
|
||||
"theme.system": "Системная",
|
||||
"theme.dark": "Темная",
|
||||
"theme.light": "Светлая",
|
||||
"theme.title": "Тема",
|
||||
|
||||
@ -1691,7 +1691,7 @@
|
||||
"zoom_out": "缩小界面",
|
||||
"zoom_reset": "重置缩放"
|
||||
},
|
||||
"theme.auto": "自动",
|
||||
"theme.system": "系统",
|
||||
"theme.dark": "深色",
|
||||
"theme.light": "浅色",
|
||||
"theme.title": "主题",
|
||||
|
||||
@ -1684,7 +1684,7 @@
|
||||
"zoom_reset": "重設縮放",
|
||||
"exit_fullscreen": "退出螢幕"
|
||||
},
|
||||
"theme.auto": "自動",
|
||||
"theme.system": "系統",
|
||||
"theme.dark": "深色",
|
||||
"theme.light": "淺色",
|
||||
"theme.title": "主題",
|
||||
|
||||
@ -1478,7 +1478,7 @@
|
||||
"zoom_out": "Σμικρύνση εμφάνισης",
|
||||
"zoom_reset": "Επαναφορά εμφάνισης"
|
||||
},
|
||||
"theme.auto": "Αυτόματο",
|
||||
"theme.system": "Σύστημα",
|
||||
"theme.dark": "Σκοτεινό",
|
||||
"theme.light": "Φωτεινό",
|
||||
"theme.title": "Θέμα",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -199,7 +199,7 @@ const ChatFlowHistory: FC<ChatFlowHistoryProps> = ({ conversationId }) => {
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState<any>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const { userName } = useSettings()
|
||||
const { theme } = useTheme()
|
||||
const { settedTheme } = useTheme()
|
||||
|
||||
const topicId = conversationId
|
||||
|
||||
@ -491,7 +491,7 @@ const ChatFlowHistory: FC<ChatFlowHistoryProps> = ({ conversationId }) => {
|
||||
}}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
className="react-flow-container"
|
||||
colorMode={theme === 'auto' ? 'system' : theme}>
|
||||
colorMode={settedTheme}>
|
||||
<Controls showInteractive={false} />
|
||||
<MiniMap
|
||||
nodeStrokeWidth={3}
|
||||
|
||||
@ -54,8 +54,6 @@ const ColorCircle = styled.div<{ color: string; isActive?: boolean }>`
|
||||
|
||||
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: (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
||||
<SyncOutlined />
|
||||
<span>{t('settings.theme.auto')}</span>
|
||||
<span>{t('settings.theme.system')}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -168,13 +167,13 @@ const DisplaySettings: FC = () => {
|
||||
)
|
||||
|
||||
return (
|
||||
<SettingContainer theme={themeMode}>
|
||||
<SettingContainer theme={theme}>
|
||||
<SettingGroup theme={theme}>
|
||||
<SettingTitle>{t('settings.display.title')}</SettingTitle>
|
||||
<SettingDivider />
|
||||
<SettingRow>
|
||||
<SettingRowTitle>{t('settings.theme.title')}</SettingRowTitle>
|
||||
<Segmented value={theme} shape="round" onChange={setTheme} options={themeOptions} />
|
||||
<Segmented value={settedTheme} shape="round" onChange={setTheme} options={themeOptions} />
|
||||
</SettingRow>
|
||||
<SettingDivider />
|
||||
<SettingRow>
|
||||
|
||||
@ -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<string | undefined>(storeProxyUrl)
|
||||
const { theme: themeMode } = useTheme()
|
||||
const { theme } = useTheme()
|
||||
|
||||
const updateTray = (isShowTray: boolean) => {
|
||||
setTray(isShowTray)
|
||||
@ -116,7 +115,7 @@ const GeneralSettings: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingContainer theme={themeMode}>
|
||||
<SettingContainer theme={theme}>
|
||||
<SettingGroup theme={theme}>
|
||||
<SettingTitle>{t('settings.general.title')}</SettingTitle>
|
||||
<SettingDivider />
|
||||
|
||||
@ -198,7 +198,7 @@ export const initialState: SettingsState = {
|
||||
launchToTray: false,
|
||||
trayOnClose: true,
|
||||
tray: true,
|
||||
theme: ThemeMode.auto,
|
||||
theme: ThemeMode.system,
|
||||
userTheme: {
|
||||
colorPrimary: '#00b96b'
|
||||
},
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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<HTMLDivElement>(null)
|
||||
const featureMenusRef = useRef<FeatureMenusRef>(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'
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user