mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
feat(ui): add system theme mode for dark mode controls
- default Joy color scheme to system - cycle theme control through light, dark, and system modes - update labels and icons to reflect the active theme preference Signed-off-by: blacksuan19 <abubakaryagob@gmail.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button, IconButton, useColorScheme } from '@mui/joy';
|
||||
import BrightnessAutoIcon from '@mui/icons-material/BrightnessAuto';
|
||||
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||
import LightModeIcon from '@mui/icons-material/LightMode';
|
||||
import { GoodTooltip } from './GoodTooltip';
|
||||
|
||||
export const darkModeToggleButtonSx = {
|
||||
boxShadow: 'sm',
|
||||
@@ -12,29 +14,64 @@ export const darkModeToggleButtonSx = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
type ThemeMode = 'light' | 'dark' | 'system';
|
||||
|
||||
const _nextThemeMode: Record<ThemeMode, ThemeMode> = {
|
||||
light: 'dark',
|
||||
dark: 'system',
|
||||
system: 'light',
|
||||
};
|
||||
|
||||
const _themeModeLabel: Record<ThemeMode, string> = {
|
||||
light: 'Light Theme',
|
||||
dark: 'Dark Theme',
|
||||
system: 'System Theme',
|
||||
};
|
||||
|
||||
function _themeModeIcon(mode: ThemeMode) {
|
||||
switch (mode) {
|
||||
case 'dark':
|
||||
return <DarkModeIcon />;
|
||||
case 'system':
|
||||
return <BrightnessAutoIcon />;
|
||||
case 'light':
|
||||
default:
|
||||
return <LightModeIcon />;
|
||||
}
|
||||
}
|
||||
|
||||
export function DarkModeToggleButton(props: { hasText?: boolean }) {
|
||||
|
||||
// external state
|
||||
const { mode: colorMode, setMode: setColorMode } = useColorScheme();
|
||||
const mode: ThemeMode = colorMode === 'light' || colorMode === 'dark' || colorMode === 'system'
|
||||
? colorMode
|
||||
: 'system';
|
||||
|
||||
const handleToggleDarkMode = (event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
setColorMode(colorMode === 'dark' ? 'light' : 'dark');
|
||||
setColorMode(_nextThemeMode[mode]);
|
||||
};
|
||||
|
||||
return props.hasText ? (
|
||||
<Button
|
||||
variant='soft'
|
||||
color='neutral'
|
||||
onClick={handleToggleDarkMode}
|
||||
sx={darkModeToggleButtonSx}
|
||||
startDecorator={colorMode !== 'dark' ? <DarkModeIcon color='primary' /> : <LightModeIcon />}
|
||||
>
|
||||
{colorMode === 'dark' ? 'Light Mode' : 'Dark Mode'}
|
||||
</Button>
|
||||
) : (
|
||||
<IconButton size='sm' variant='soft' onClick={handleToggleDarkMode} sx={{ ml: 'auto', /*mr: '2px',*/ my: '-0.25rem' /* absorb the menuItem padding */ }}>
|
||||
{colorMode !== 'dark' ? <DarkModeIcon /> : <LightModeIcon />}
|
||||
</IconButton>
|
||||
const title = `Theme: ${_themeModeLabel[mode]}`;
|
||||
|
||||
return (
|
||||
<GoodTooltip title={title}>
|
||||
{props.hasText ? (
|
||||
<Button
|
||||
variant='soft'
|
||||
color='neutral'
|
||||
onClick={handleToggleDarkMode}
|
||||
sx={darkModeToggleButtonSx}
|
||||
startDecorator={React.cloneElement(_themeModeIcon(mode), { color: 'primary' })}
|
||||
>
|
||||
{_themeModeLabel[mode]}
|
||||
</Button>
|
||||
) : (
|
||||
<IconButton size='sm' variant='soft' onClick={handleToggleDarkMode} sx={{ ml: 'auto', /*mr: '2px',*/ my: '-0.25rem' /* absorb the menuItem padding */ }}>
|
||||
{_themeModeIcon(mode)}
|
||||
</IconButton>
|
||||
)}
|
||||
</GoodTooltip>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export const ProviderTheming = (props: { emotionCache?: EmotionCache, children:
|
||||
|
||||
return (
|
||||
<CacheProvider value={props.emotionCache || clientSideEmotionCache}>
|
||||
<CssVarsProvider defaultMode='light' theme={theme}>
|
||||
<CssVarsProvider defaultMode='system' theme={theme}>
|
||||
<CssBaseline />
|
||||
{/* Inject sprites to be referenced by SVG rendering */}
|
||||
<VendorIconSpriteMemo />
|
||||
|
||||
Reference in New Issue
Block a user