frontend/src/hooks/useSkin.ts
Rama main · réplica de lectura del repositorio original.
import { useCallback, useSyncExternalStore } from "react";
import { applySkin, DEFAULT_SKIN, isSkinId, SKIN_STORAGE_KEY, type SkinId } from "@/lib/skins";
/**
* Shared skin state.
*
* Deliberately a module-level store rather than useState-per-hook: the shell,
* the header switcher and the settings page all read the skin, and independent
* useState copies would leave stale shells behind after a switch.
* `useSyncExternalStore` gives every caller the same value with no provider.
*/
function read(): SkinId {
try {
const stored = localStorage.getItem(SKIN_STORAGE_KEY);
if (isSkinId(stored)) return stored;
} catch { /* private mode */ }
return DEFAULT_SKIN;
}
let current: SkinId = typeof document === "undefined" ? DEFAULT_SKIN : read();
const listeners = new Set<() => void>();
function subscribe(fn: () => void) {
listeners.add(fn);
return () => listeners.delete(fn);
}
function getSnapshot(): SkinId {
return current;
}
export function setSkin(skin: SkinId) {
if (skin === current) return;
current = skin;
try { localStorage.setItem(SKIN_STORAGE_KEY, skin); } catch { /* private mode */ }
applySkin(skin);
listeners.forEach((fn) => fn());
}
export function useSkin() {
const skin = useSyncExternalStore(subscribe, getSnapshot, () => DEFAULT_SKIN);
return { skin, setSkin: useCallback(setSkin, []) };
}