Client settings (#7381)

Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
Douwe Osinga
2026-02-21 14:26:03 +00:00
committed by GitHub
parent c543586b6f
commit 45d59be201
16 changed files with 335 additions and 233 deletions
+49 -31
View File
@@ -22,29 +22,6 @@ function resolveTheme(preference: ThemePreference): ResolvedTheme {
return preference;
}
function loadThemePreference(): ThemePreference {
const useSystemTheme = localStorage.getItem('use_system_theme');
if (useSystemTheme === 'true') {
return 'system';
}
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
return 'dark';
}
return 'light';
}
function saveThemePreference(preference: ThemePreference): void {
if (preference === 'system') {
localStorage.setItem('use_system_theme', 'true');
} else {
localStorage.setItem('use_system_theme', 'false');
localStorage.setItem('theme', preference);
}
}
function applyThemeToDocument(theme: ResolvedTheme): void {
const toRemove = theme === 'dark' ? 'light' : 'dark';
document.documentElement.classList.add(theme);
@@ -56,19 +33,53 @@ interface ThemeProviderProps {
}
export function ThemeProvider({ children }: ThemeProviderProps) {
const [userThemePreference, setUserThemePreferenceState] =
useState<ThemePreference>(loadThemePreference);
const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>(() =>
resolveTheme(loadThemePreference())
);
// Start with light theme to avoid flash, will update once settings load
const [userThemePreference, setUserThemePreferenceState] = useState<ThemePreference>('light');
const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>('light');
const setUserThemePreference = useCallback((preference: ThemePreference) => {
useEffect(() => {
async function loadThemeFromSettings() {
try {
const [useSystemTheme, savedTheme] = await Promise.all([
window.electron.getSetting('useSystemTheme'),
window.electron.getSetting('theme'),
]);
let preference: ThemePreference;
if (useSystemTheme) {
preference = 'system';
} else {
preference = savedTheme;
}
setUserThemePreferenceState(preference);
setResolvedTheme(resolveTheme(preference));
} catch (error) {
console.warn('[ThemeContext] Failed to load theme settings:', error);
}
}
loadThemeFromSettings();
}, []);
const setUserThemePreference = useCallback(async (preference: ThemePreference) => {
setUserThemePreferenceState(preference);
saveThemePreference(preference);
const resolved = resolveTheme(preference);
setResolvedTheme(resolved);
// Save to settings
try {
if (preference === 'system') {
await window.electron.setSetting('useSystemTheme', true);
} else {
await window.electron.setSetting('useSystemTheme', false);
await window.electron.setSetting('theme', preference);
}
} catch (error) {
console.warn('[ThemeContext] Failed to save theme settings:', error);
}
// Broadcast to other windows via Electron
window.electron?.broadcastThemeChange({
mode: resolved,
@@ -104,8 +115,15 @@ export function ThemeProvider({ children }: ThemeProviderProps) {
: 'light';
setUserThemePreferenceState(newPreference);
saveThemePreference(newPreference);
setResolvedTheme(resolveTheme(newPreference));
// Save to settings (don't await, fire and forget)
if (newPreference === 'system') {
window.electron.setSetting('useSystemTheme', true);
} else {
window.electron.setSetting('useSystemTheme', false);
window.electron.setSetting('theme', newPreference);
}
};
window.electron.on('theme-changed', handleThemeChanged);