5 changed files with 93 additions and 17 deletions
@ -115,7 +115,7 @@ importers: |
|||
version: 1.5.4 |
|||
vite-plugin-node-polyfills: |
|||
specifier: ^0.23.0 |
|||
version: 0.23.0([email protected])([email protected].0(@types/[email protected])([email protected])([email protected])([email protected])) |
|||
version: 0.23.0([email protected])([email protected].1(@types/[email protected])([email protected])([email protected])([email protected])) |
|||
zustand: |
|||
specifier: 5.0.3 |
|||
version: 5.0.3(@types/[email protected])([email protected])([email protected])([email protected]([email protected])) |
|||
@ -149,7 +149,7 @@ importers: |
|||
version: 0.0.20 |
|||
'@vitejs/plugin-react': |
|||
specifier: ^4.3.4 |
|||
version: 4.3.4([email protected].0(@types/[email protected])([email protected])([email protected])([email protected])) |
|||
version: 4.3.4([email protected].1(@types/[email protected])([email protected])([email protected])([email protected])) |
|||
autoprefixer: |
|||
specifier: ^10.4.20 |
|||
version: 10.4.20([email protected]) |
|||
@ -178,8 +178,8 @@ importers: |
|||
specifier: ^5.7.3 |
|||
version: 5.7.3 |
|||
vite: |
|||
specifier: ^6.1.0 |
|||
version: 6.1.0(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
specifier: ^6.1.1 |
|||
version: 6.1.1(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
|
|||
packages: |
|||
|
|||
@ -2503,6 +2503,10 @@ packages: |
|||
resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} |
|||
engines: {node: ^10 || ^12 || >=14} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} |
|||
engines: {node: ^10 || ^12 || >=14} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} |
|||
|
|||
@ -2929,8 +2933,8 @@ packages: |
|||
peerDependencies: |
|||
vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 |
|||
|
|||
[email protected].0: |
|||
resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==} |
|||
[email protected].1: |
|||
resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==} |
|||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} |
|||
hasBin: true |
|||
peerDependencies: |
|||
@ -5226,14 +5230,14 @@ snapshots: |
|||
|
|||
'@types/[email protected]': {} |
|||
|
|||
'@vitejs/[email protected]([email protected].0(@types/[email protected])([email protected])([email protected])([email protected]))': |
|||
'@vitejs/[email protected]([email protected].1(@types/[email protected])([email protected])([email protected])([email protected]))': |
|||
dependencies: |
|||
'@babel/core': 7.26.8 |
|||
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/[email protected]) |
|||
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/[email protected]) |
|||
'@types/babel__core': 7.20.5 |
|||
react-refresh: 0.14.2 |
|||
vite: 6.1.0(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
vite: 6.1.1(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
transitivePeerDependencies: |
|||
- supports-color |
|||
|
|||
@ -6140,6 +6144,12 @@ snapshots: |
|||
picocolors: 1.1.1 |
|||
source-map-js: 1.2.1 |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
nanoid: 3.3.8 |
|||
picocolors: 1.1.1 |
|||
source-map-js: 1.2.1 |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
@ -6579,18 +6589,18 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]([email protected])([email protected].0(@types/[email protected])([email protected])([email protected])([email protected])): |
|||
[email protected]([email protected])([email protected].1(@types/[email protected])([email protected])([email protected])([email protected])): |
|||
dependencies: |
|||
'@rollup/plugin-inject': 5.0.5([email protected]) |
|||
node-stdlib-browser: 1.2.0 |
|||
vite: 6.1.0(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
vite: 6.1.1(@types/[email protected])([email protected])([email protected])([email protected]) |
|||
transitivePeerDependencies: |
|||
- rollup |
|||
|
|||
[email protected].0(@types/[email protected])([email protected])([email protected])([email protected]): |
|||
[email protected].1(@types/[email protected])([email protected])([email protected])([email protected]): |
|||
dependencies: |
|||
esbuild: 0.24.2 |
|||
postcss: 8.5.1 |
|||
postcss: 8.5.3 |
|||
rollup: 4.34.6 |
|||
optionalDependencies: |
|||
'@types/node': 22.13.4 |
|||
|
|||
@ -0,0 +1,67 @@ |
|||
import type React from "react"; |
|||
import { createContext, useContext, useEffect, useState } from "react"; |
|||
|
|||
type Theme = "light" | "dark" | "system"; |
|||
|
|||
interface ThemeContextType { |
|||
theme: Theme; |
|||
setTheme: (theme: Theme) => void; |
|||
} |
|||
|
|||
const ThemeContext = createContext<ThemeContextType | undefined>(undefined); |
|||
|
|||
export function ThemeProvider({ children }: { children: React.ReactNode }) { |
|||
const [theme, setTheme] = useState<Theme>(() => { |
|||
if (typeof window !== "undefined") { |
|||
const savedTheme = localStorage.getItem("theme") as Theme; |
|||
return savedTheme || "system"; |
|||
} |
|||
return "system"; |
|||
}); |
|||
|
|||
useEffect(() => { |
|||
const root = window.document.documentElement; |
|||
root.classList.remove("light", "dark"); |
|||
|
|||
if (theme === "system") { |
|||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") |
|||
.matches |
|||
? "dark" |
|||
: "light"; |
|||
root.classList.add(systemTheme); |
|||
} else { |
|||
root.classList.add(theme); |
|||
} |
|||
|
|||
localStorage.setItem("theme", theme); |
|||
}, [theme]); |
|||
|
|||
useEffect(() => { |
|||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); |
|||
|
|||
const handleChange = () => { |
|||
if (theme === "system") { |
|||
const root = window.document.documentElement; |
|||
root.classList.remove("light", "dark"); |
|||
root.classList.add(mediaQuery.matches ? "dark" : "light"); |
|||
} |
|||
}; |
|||
|
|||
mediaQuery.addEventListener("change", handleChange); |
|||
return () => mediaQuery.removeEventListener("change", handleChange); |
|||
}, [theme]); |
|||
|
|||
return ( |
|||
<ThemeContext.Provider value={{ theme, setTheme }}> |
|||
{children} |
|||
</ThemeContext.Provider> |
|||
); |
|||
} |
|||
|
|||
export function useTheme() { |
|||
const context = useContext(ThemeContext); |
|||
if (context === undefined) { |
|||
throw new Error("useTheme must be used within a ThemeProvider"); |
|||
} |
|||
return context; |
|||
} |
|||
Loading…
Reference in new issue