diff --git a/src/components/layout/LocaleSwitcher.tsx b/src/components/layout/LocaleSwitcher.tsx
index 0a300d5..1e2a8d3 100644
--- a/src/components/layout/LocaleSwitcher.tsx
+++ b/src/components/layout/LocaleSwitcher.tsx
@@ -19,6 +19,7 @@ export function LocaleSwitcher() {
return (
+ {/* eslint-disable-next-line @next/next/no-img-element */}

void>();
+let clientTheme: Theme | null = null; // lazily initialised on first client read
+
+function getSnapshot(): Theme {
+ if (clientTheme === null) {
+ clientTheme = readThemeFromDOM();
+ }
+ return clientTheme;
+}
+
+// The server always returns the default theme so SSR HTML is deterministic.
+// The client will then reconcile with the real cookie/DOM value via getSnapshot.
+function getServerSnapshot(): Theme {
+ return 'dark';
+}
+
+function subscribe(callback: () => void): () => void {
+ listeners.add(callback);
+ return () => listeners.delete(callback);
+}
+
+function setGlobalTheme(next: Theme) {
+ clientTheme = next;
+ applyThemeToDOM(next);
+ setCookie(next);
+ listeners.forEach((cb) => cb());
+}
+
+// ── Hook ──────────────────────────────────────────────────────────────────────
+
export function useTheme() {
- const [theme, setTheme] = useState
('dark');
+ const theme = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
- useEffect(() => {
- const cookieTheme = getCookie('theme') as Theme | null;
- const rootTheme = document.documentElement.classList.contains('dark')
- ? 'dark'
- : 'light';
-
- const initial = cookieTheme || rootTheme || 'dark';
-
- setTheme(initial);
-
- document.documentElement.classList.toggle('dark', initial === 'dark');
- document.documentElement.classList.toggle(
- 'light-mode',
- initial === 'light',
- );
- }, []);
-
- function applyTheme(t: Theme) {
- document.documentElement.classList.toggle('dark', t === 'dark');
- document.documentElement.classList.toggle('light-mode', t === 'light');
-
- setCookie(t);
- }
-
- function toggleTheme() {
- setTheme((prev) => {
- const next = prev === 'dark' ? 'light' : 'dark';
- applyTheme(next);
- return next;
- });
- }
+ const toggleTheme = useCallback(() => {
+ setGlobalTheme(theme === 'dark' ? 'light' : 'dark');
+ }, [theme]);
return {
theme,
dark: theme === 'dark',
toggleTheme,
};
-}
+}
\ No newline at end of file