/
45case
/
ptable
Обзор
Документация
Войти
/
45case
/
ptable
Код
Запросы
3
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
dev
src/shared/lib/useTheme.ts
103 строки
2 KB
Olya
first_commit
06 июл 2026, 18:16
06 июл 2026, 18:16
0ff6e29
Код
Авторство
О чём код?
import { readonly, ref } from "vue"; export const APP_THEMES = { LIGHT: "light", DARK: "dark", } as const; export type AppTheme = (typeof APP_THEMES)[keyof typeof APP_THEMES]; const THEME_STORAGE_KEY = "periodic-table-theme"; const DEFAULT_THEME: AppTheme = APP_THEMES.LIGHT; const theme = ref<AppTheme>(DEFAULT_THEME); const readonlyTheme = readonly(theme); let isThemeInitialized = false; function isAppTheme(value: string | null): value is AppTheme { return value === APP_THEMES.LIGHT || value === APP_THEMES.DARK; } function getStoredTheme(): AppTheme | null { if (typeof window === "undefined") { return null; } const storedTheme = window.localStorage.getItem(THEME_STORAGE_KEY); return isAppTheme(storedTheme) ? storedTheme : null; } function getSystemTheme(): AppTheme { if (typeof window === "undefined") { return DEFAULT_THEME; } return window.matchMedia("(prefers-color-scheme: dark)").matches ? APP_THEMES.DARK : APP_THEMES.LIGHT; } function applyTheme(themeValue: AppTheme) { if (typeof document === "undefined") { return; } const root = document.documentElement; root.dataset.theme = themeValue; root.style.colorScheme = themeValue; } function applyThemeWithoutMotion(themeValue: AppTheme) { if (typeof document === "undefined" || typeof window === "undefined") { applyTheme(themeValue); return; } const root = document.documentElement; root.classList.add("theme-switching"); applyTheme(themeValue); window.requestAnimationFrame(() => { window.requestAnimationFrame(() => { root.classList.remove("theme-switching"); }); }); } function persistTheme(themeValue: AppTheme) { if (typeof window === "undefined") { return; } window.localStorage.setItem(THEME_STORAGE_KEY, themeValue); } export function initializeTheme() { if (isThemeInitialized) { return; } const initialTheme = getStoredTheme() ?? getSystemTheme(); theme.value = initialTheme; applyTheme(initialTheme); isThemeInitialized = true; } export function useTheme() { function setTheme(nextTheme: AppTheme) { theme.value = nextTheme; applyThemeWithoutMotion(nextTheme); persistTheme(nextTheme); } function toggleTheme() { setTheme(theme.value === APP_THEMES.LIGHT ? APP_THEMES.DARK : APP_THEMES.LIGHT); } return { theme: readonlyTheme, setTheme, toggleTheme, }; }