feat(design-system): ThemeProvider + useTheme — toggle dark/light (Sprint 0.5 étape 2)

This commit is contained in:
Hermann_Kitio 2026-04-17 23:55:41 +03:00
parent e0a4653653
commit a1d98bd255
3 changed files with 64 additions and 5 deletions

View file

@ -1,14 +1,39 @@
import { useState, useEffect } from 'react'
import { QueryClientProvider } from '@tanstack/react-query'
import { BrowserRouter } from 'react-router-dom'
import { queryClient } from '@/shared/lib/query-client'
import {
ThemeContext,
type Theme,
getInitialTheme,
applyTheme,
persistTheme,
} from '@/shared/lib/theme'
import { AppRouter } from './router'
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setThemeState] = useState<Theme>(getInitialTheme)
useEffect(() => {
applyTheme(theme)
persistTheme(theme)
}, [theme])
function setTheme(t: Theme) {
setThemeState(t)
}
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>
}
export function Providers() {
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppRouter />
</BrowserRouter>
</QueryClientProvider>
<ThemeProvider>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppRouter />
</BrowserRouter>
</QueryClientProvider>
</ThemeProvider>
)
}

View file

@ -0,0 +1,8 @@
import { useContext } from 'react'
import { ThemeContext } from '@/shared/lib/theme'
export function useTheme() {
const ctx = useContext(ThemeContext)
if (!ctx) throw new Error('useTheme must be used within ThemeProvider')
return ctx
}

26
src/shared/lib/theme.ts Normal file
View file

@ -0,0 +1,26 @@
import { createContext } from 'react'
export type Theme = 'light' | 'dark'
export interface ThemeContextValue {
theme: Theme
setTheme: (t: Theme) => void
}
export const ThemeContext = createContext<ThemeContextValue | null>(null)
const STORAGE_KEY = 'expria-theme'
export function getInitialTheme(): Theme {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored === 'light' || stored === 'dark') return stored
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
export function applyTheme(theme: Theme): void {
document.documentElement.classList.toggle('dark', theme === 'dark')
}
export function persistTheme(theme: Theme): void {
localStorage.setItem(STORAGE_KEY, theme)
}