Co-Study4Grid / frontend /src /hooks /useTheme.ts
github-actions[bot]
Deploy 7688ef1
13d4e44
Raw
History Blame Contribute Delete
2.18 kB
// Copyright (c) 2025-2026, RTE (https://www.rte-france.com)
// This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0.
// If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
import { useCallback, useEffect, useState } from 'react';
import { interactionLogger } from '../utils/interactionLogger';
export type Theme = 'light' | 'dark';
const STORAGE_KEY = 'cs4g-theme';
// Read the persisted choice, falling back to the OS preference. Kept
// pure (no DOM writes) so the same logic can run from the pre-mount
// inline script in index.html and from React without diverging.
export function resolveInitialTheme(): Theme {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark') return stored;
} catch {
// localStorage unavailable (private mode, SSR-like envs) — fall through.
}
if (typeof window !== 'undefined' && window.matchMedia) {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
return 'light';
}
function applyThemeToDocument(theme: Theme): void {
if (typeof document === 'undefined') return;
document.documentElement.setAttribute('data-theme', theme);
document.documentElement.style.colorScheme = theme;
}
export interface ThemeState {
theme: Theme;
toggleTheme: () => void;
setTheme: (t: Theme) => void;
}
export function useTheme(): ThemeState {
const [theme, setThemeState] = useState<Theme>(() => resolveInitialTheme());
useEffect(() => {
applyThemeToDocument(theme);
try {
localStorage.setItem(STORAGE_KEY, theme);
} catch {
// ignore — same fallback as resolveInitialTheme.
}
}, [theme]);
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
const toggleTheme = useCallback(() => {
setThemeState(prev => {
const next: Theme = prev === 'dark' ? 'light' : 'dark';
interactionLogger.record('theme_toggled', { theme: next });
return next;
});
}, []);
return { theme, toggleTheme, setTheme };
}