This PR extends the build pipeline of the www service to support locale-prefixed static builds (EN/RU) with build-time SSG output injection, while also refactoring UI typography to a tokenized Tailwind v4 @theme-driven approach. Changes: - Add build-time SSG plugin to @ermnvldmr/rsbuild-config and wire multi-locale builds (/en/, /ru/) into services/www. - Introduce new @ermnvldmr/i18n package (locale constants, path helpers, keysets, pluralization) and apply it to www navigation/text. - Refactor ui typography to a shared getTypographyClassNames utility + Tailwind token definitions, with stl/cn updated for correct Tailwind-merge behavior.
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { useCallback, useSyncExternalStore } from 'react';
|
|
|
|
import type { StorageManager } from '../../window/localStorage';
|
|
|
|
/**
|
|
* A React hook that synchronizes state with a StorageManager.
|
|
*
|
|
* It provides reactivity across the component lifecycle and synchronizes
|
|
* values across multiple browser tabs using the 'storage' event.
|
|
*
|
|
* @template T - The type of the stored value.
|
|
* @param manager - The StorageManager instance returned by createLocalStorage.
|
|
* @returns A tuple containing the current value and a setter function.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const [theme, setTheme] = useLocalStorage(themeStorage);
|
|
* ```
|
|
*/
|
|
export function useLocalStorage<T>(
|
|
manager: StorageManager<T>
|
|
): [T, (value: T | ((prev: T) => T)) => void] {
|
|
const subscribe = useCallback(
|
|
(callback: () => void) => {
|
|
const handleStorageChange = (event: StorageEvent): void => {
|
|
if (event.key === manager.key) {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
window.addEventListener('storage', handleStorageChange);
|
|
return () => {
|
|
window.removeEventListener('storage', handleStorageChange);
|
|
};
|
|
},
|
|
[manager.key]
|
|
);
|
|
|
|
const getSnapshot = useCallback(() => manager.get(), [manager]);
|
|
|
|
const value = useSyncExternalStore(subscribe, getSnapshot, () => {
|
|
// SSR snapshot: createLocalStorage returns a no-op manager in Node context,
|
|
// so manager.get() safely returns defaultValue without accessing localStorage.
|
|
return manager.get();
|
|
});
|
|
|
|
const setValue = useCallback(
|
|
(nextValue: T | ((prev: T) => T)) => {
|
|
manager.set(nextValue);
|
|
},
|
|
[manager]
|
|
);
|
|
|
|
return [value, setValue];
|
|
}
|