Files
claude-mem/src/ui/viewer/hooks/useTheme.ts
T
Alex Newman f46b5b452f 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.
2025-11-06 13:10:35 -05:00

77 lines
2.3 KiB
TypeScript

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
};
}