added system theme option (#2104)

This commit is contained in:
Nahiyan Khan
2025-04-09 10:09:12 -04:00
committed by GitHub
parent 4b86900f47
commit 7b9ce82245
@@ -51,33 +51,55 @@ const MenuButton: React.FC<MenuButtonProps> = ({
</button>
);
interface DarkModeToggleProps {
isDarkMode: boolean;
onToggle: () => void;
interface ThemeSelectProps {
themeMode: 'light' | 'dark' | 'system';
onThemeChange: (theme: 'light' | 'dark' | 'system') => void;
}
const DarkModeToggle: React.FC<DarkModeToggleProps> = ({ isDarkMode, onToggle }) => (
<button
className="flex items-center min-h-[64px] justify-between px-4 py-3 hover:bg-bgSubtle border-b border-borderSubtle"
onClick={onToggle}
>
<div className="flex flex-col items-start">
<span className="text-sm">{isDarkMode ? 'Light Mode' : 'Dark Mode'}</span>
<span className="text-xs font-regular text-textSubtle mt-0.5">
{isDarkMode ? 'Switch to light theme' : 'Switch to dark theme'}
</span>
</div>
<div className="h-4 w-4 overflow-hidden relative rounded-full">
<div className="absolute bg-bg flex h-4 w-4 flex-row items-center justify-center transition-transform rotate-180 dark:rotate-0 translate-x-[100%] dark:translate-x-[0%]">
<Sun className="h-4 w-4 transition-all duration-[400ms]" />
</div>
const ThemeSelect: React.FC<ThemeSelectProps> = ({ themeMode, onThemeChange }) => {
return (
<div className="px-4 py-3 border-b border-borderSubtle">
<div className="text-sm mb-2">Theme</div>
<div className="grid grid-cols-3 gap-2">
<button
onClick={() => onThemeChange('light')}
className={`flex items-center justify-center gap-2 p-2 rounded-md border transition-colors ${
themeMode === 'light'
? 'border-borderStandard'
: 'border-borderSubtle hover:border-borderStandard text-textSubtle hover:text-textStandard'
}`}
>
<Sun className="h-4 w-4" />
<span className="text-xs">Light</span>
</button>
<div className="absolute bg-bg flex h-4 w-4 flex-row items-center justify-center transition-transform dark:translate-x-[-100%] dark:-rotate-90">
<Moon className="h-4 w-4 transition-all duration-[400ms]" />
<button
onClick={() => onThemeChange('dark')}
className={`flex items-center justify-center gap-2 p-2 rounded-md border transition-colors ${
themeMode === 'dark'
? 'border-borderStandard'
: 'border-borderSubtle hover:border-borderStandard text-textSubtle hover:text-textStandard'
}`}
>
<Moon className="h-4 w-4" />
<span className="text-xs">Dark</span>
</button>
<button
onClick={() => onThemeChange('system')}
className={`flex items-center justify-center gap-2 p-2 rounded-md border transition-colors ${
themeMode === 'system'
? 'border-borderStandard'
: 'border-borderSubtle hover:border-borderStandard text-textSubtle hover:text-textStandard'
}`}
>
<Sliders className="h-4 w-4" />
<span className="text-xs">System</span>
</button>
</div>
</div>
</button>
);
);
};
export default function MoreMenu({
setView,
@@ -90,16 +112,21 @@ export default function MoreMenu({
const { remove } = useConfig();
const [versions, setVersions] = useState<VersionInfo | null>(null);
const [showVersions, setShowVersions] = useState(false);
const [useSystemTheme, setUseSystemTheme] = useState(
() => localStorage.getItem('use_system_theme') === 'true'
);
const [isDarkMode, setDarkMode] = useState(() => {
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (useSystemTheme) {
return systemPrefersDark;
const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>(() => {
const savedUseSystemTheme = localStorage.getItem('use_system_theme') === 'true';
if (savedUseSystemTheme) {
return 'system';
}
const savedTheme = localStorage.getItem('theme');
return savedTheme ? savedTheme === 'dark' : systemPrefersDark;
return savedTheme === 'dark' ? 'dark' : 'light';
});
const [isDarkMode, setDarkMode] = useState(() => {
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (themeMode === 'system') {
return systemPrefersDark;
}
return themeMode === 'dark';
});
useEffect(() => {
@@ -128,7 +155,7 @@ export default function MoreMenu({
// Handler for system theme changes
const handleThemeChange = (e: { matches: boolean }) => {
if (useSystemTheme) {
if (themeMode === 'system') {
setDarkMode(e.matches);
}
};
@@ -137,32 +164,31 @@ export default function MoreMenu({
mediaQuery.addEventListener('change', handleThemeChange);
// Initial setup
if (useSystemTheme) {
if (themeMode === 'system') {
setDarkMode(mediaQuery.matches);
localStorage.setItem('use_system_theme', 'true');
} else {
const savedTheme = localStorage.getItem('theme');
setDarkMode(savedTheme ? savedTheme === 'dark' : mediaQuery.matches);
setDarkMode(themeMode === 'dark');
localStorage.setItem('use_system_theme', 'false');
localStorage.setItem('theme', themeMode);
}
// Cleanup
return () => mediaQuery.removeEventListener('change', handleThemeChange);
}, [useSystemTheme]);
}, [themeMode]);
useEffect(() => {
if (isDarkMode) {
document.documentElement.classList.add('dark');
document.documentElement.classList.remove('light');
} else {
document.documentElement.classList.remove('dark');
document.documentElement.classList.add('light');
}
if (!useSystemTheme) {
localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
}
}, [isDarkMode, useSystemTheme]);
}, [isDarkMode]);
const toggleTheme = () => {
if (!useSystemTheme) {
setDarkMode(!isDarkMode);
}
const handleThemeChange = (newTheme: 'light' | 'dark' | 'system') => {
setThemeMode(newTheme);
};
return (
@@ -229,8 +255,6 @@ export default function MoreMenu({
Configure .goosehints
</MenuButton>
<DarkModeToggle isDarkMode={isDarkMode} onToggle={toggleTheme} />
{/* Make Agent from Chat */}
<MenuButton
onClick={() => {
@@ -257,6 +281,8 @@ export default function MoreMenu({
<span className="text-textSubtle ml-1">,</span>
</MenuButton>
<ThemeSelect themeMode={themeMode} onThemeChange={handleThemeChange} />
{settingsV2Enabled && (
<MenuButton
onClick={async () => {