diff --git a/src/App.tsx b/src/App.tsx index 0d1f1df..15562c6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,10 +31,11 @@ function App() { const [authReady, setAuthReady] = useState(false); useEffect(() => { - initializeTheme(); + const cleanupTheme = initializeTheme(); void restoreSession().finally(() => { setAuthReady(true); }); + return cleanupTheme; }, [initializeTheme, restoreSession]); useEffect(() => { diff --git a/src/components/layout/MainLayout.tsx b/src/components/layout/MainLayout.tsx index 0481d97..b132e6d 100644 --- a/src/components/layout/MainLayout.tsx +++ b/src/components/layout/MainLayout.tsx @@ -1,4 +1,12 @@ -import { ReactNode, SVGProps, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { + ReactNode, + SVGProps, + useCallback, + useEffect, + useLayoutEffect, + useRef, + useState, +} from 'react'; import { NavLink, Outlet } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/Button'; @@ -14,10 +22,16 @@ import { IconScrollText, IconSettings, IconShield, - IconSlidersHorizontal + IconSlidersHorizontal, } from '@/components/ui/icons'; import { INLINE_LOGO_JPEG } from '@/assets/logoInline'; -import { useAuthStore, useConfigStore, useLanguageStore, useNotificationStore, useThemeStore } from '@/stores'; +import { + useAuthStore, + useConfigStore, + useLanguageStore, + useNotificationStore, + useThemeStore, +} from '@/stores'; import { configApi, versionApi } from '@/services/api'; const sidebarIcons: Record = { @@ -30,7 +44,7 @@ const sidebarIcons: Record = { usage: , config: , logs: , - system: + system: , }; // Header action icons - smaller size for header buttons @@ -44,7 +58,7 @@ const headerIconProps: SVGProps = { strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true', - focusable: 'false' + focusable: 'false', }; const headerIcons = { @@ -97,19 +111,38 @@ const headerIcons = { ), - moon: ( - - - - ), - logout: ( - - - - - - ) - }; + moon: ( + + + + ), + autoTheme: ( + + + + + + + + + + + + + + + + + + ), + logout: ( + + + + + + ), +}; const parseVersionSegments = (version?: string | null) => { if (!version) return null; @@ -153,7 +186,7 @@ export function MainLayout() { const updateConfigValue = useConfigStore((state) => state.updateConfigValue); const theme = useThemeStore((state) => state.theme); - const toggleTheme = useThemeStore((state) => state.toggleTheme); + const cycleTheme = useThemeStore((state) => state.cycleTheme); const toggleLanguage = useLanguageStore((state) => state.toggleLanguage); const [sidebarOpen, setSidebarOpen] = useState(false); @@ -187,7 +220,9 @@ export function MainLayout() { updateHeaderHeight(); const resizeObserver = - typeof ResizeObserver !== 'undefined' && headerRef.current ? new ResizeObserver(updateHeaderHeight) : null; + typeof ResizeObserver !== 'undefined' && headerRef.current + ? new ResizeObserver(updateHeaderHeight) + : null; if (resizeObserver && headerRef.current) { resizeObserver.observe(headerRef.current); } @@ -320,8 +355,10 @@ export function MainLayout() { { path: '/oauth', label: t('nav.oauth', { defaultValue: 'OAuth' }), icon: sidebarIcons.oauth }, { path: '/usage', label: t('nav.usage_stats'), icon: sidebarIcons.usage }, { path: '/config', label: t('nav.config_management'), icon: sidebarIcons.config }, - ...(config?.loggingToFile ? [{ path: '/logs', label: t('nav.logs'), icon: sidebarIcons.logs }] : []), - { path: '/system', label: t('nav.system_info'), icon: sidebarIcons.system } + ...(config?.loggingToFile + ? [{ path: '/logs', label: t('nav.logs'), icon: sidebarIcons.logs }] + : []), + { path: '/system', label: t('nav.system_info'), icon: sidebarIcons.system }, ]; const handleRefreshAll = async () => { @@ -370,7 +407,11 @@ export function MainLayout() { @@ -400,20 +441,40 @@ export function MainLayout() {
- - - -