feat: implement theme toggle functionality with light, dark, and system preferences
- Added theme variables for light and dark modes in viewer-template.html. - Created a custom hook `useTheme` to manage theme preferences and resolve the current theme based on user selection or system settings. - Introduced `ThemeToggle` component to allow users to switch between themes. - Updated `Header` component to include the `ThemeToggle` and pass theme preference and change handler. - Modified `App` component to integrate theme management and pass relevant props to child components.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export type ThemePreference = 'system' | 'light' | 'dark';
|
||||
export type ResolvedTheme = 'light' | 'dark';
|
||||
|
||||
const STORAGE_KEY = 'claude-mem-theme';
|
||||
|
||||
function getSystemTheme(): ResolvedTheme {
|
||||
if (typeof window === 'undefined') return 'dark';
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
function getStoredPreference(): ThemePreference {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored === 'system' || stored === 'light' || stored === 'dark') {
|
||||
return stored;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to read theme preference from localStorage:', e);
|
||||
}
|
||||
return 'system';
|
||||
}
|
||||
|
||||
function resolveTheme(preference: ThemePreference): ResolvedTheme {
|
||||
if (preference === 'system') {
|
||||
return getSystemTheme();
|
||||
}
|
||||
return preference;
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
const [preference, setPreference] = useState<ThemePreference>(getStoredPreference);
|
||||
const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>(() =>
|
||||
resolveTheme(getStoredPreference())
|
||||
);
|
||||
|
||||
// Update resolved theme when preference changes
|
||||
useEffect(() => {
|
||||
const newResolvedTheme = resolveTheme(preference);
|
||||
setResolvedTheme(newResolvedTheme);
|
||||
document.documentElement.setAttribute('data-theme', newResolvedTheme);
|
||||
}, [preference]);
|
||||
|
||||
// Listen for system theme changes when preference is 'system'
|
||||
useEffect(() => {
|
||||
if (preference !== 'system') return;
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const handleChange = (e: MediaQueryListEvent) => {
|
||||
const newTheme = e.matches ? 'dark' : 'light';
|
||||
setResolvedTheme(newTheme);
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
};
|
||||
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
return () => mediaQuery.removeEventListener('change', handleChange);
|
||||
}, [preference]);
|
||||
|
||||
const setThemePreference = (newPreference: ThemePreference) => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, newPreference);
|
||||
setPreference(newPreference);
|
||||
} catch (e) {
|
||||
console.warn('Failed to save theme preference to localStorage:', e);
|
||||
// Still update the theme even if localStorage fails
|
||||
setPreference(newPreference);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
preference,
|
||||
resolvedTheme,
|
||||
setThemePreference
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user