5 changed files with 93 additions and 17 deletions
@ -115,7 +115,7 @@ importers: |
|||||
version: 1.5.4 |
version: 1.5.4 |
||||
vite-plugin-node-polyfills: |
vite-plugin-node-polyfills: |
||||
specifier: ^0.23.0 |
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: |
zustand: |
||||
specifier: 5.0.3 |
specifier: 5.0.3 |
||||
version: 5.0.3(@types/[email protected])([email protected])([email protected])([email protected]([email protected])) |
version: 5.0.3(@types/[email protected])([email protected])([email protected])([email protected]([email protected])) |
||||
@ -149,7 +149,7 @@ importers: |
|||||
version: 0.0.20 |
version: 0.0.20 |
||||
'@vitejs/plugin-react': |
'@vitejs/plugin-react': |
||||
specifier: ^4.3.4 |
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: |
autoprefixer: |
||||
specifier: ^10.4.20 |
specifier: ^10.4.20 |
||||
version: 10.4.20([email protected]) |
version: 10.4.20([email protected]) |
||||
@ -178,8 +178,8 @@ importers: |
|||||
specifier: ^5.7.3 |
specifier: ^5.7.3 |
||||
version: 5.7.3 |
version: 5.7.3 |
||||
vite: |
vite: |
||||
specifier: ^6.1.0 |
specifier: ^6.1.1 |
||||
version: 6.1.0(@types/[email protected])([email protected])([email protected])([email protected]) |
version: 6.1.1(@types/[email protected])([email protected])([email protected])([email protected]) |
||||
|
|
||||
packages: |
packages: |
||||
|
|
||||
@ -2503,6 +2503,10 @@ packages: |
|||||
resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} |
resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} |
||||
engines: {node: ^10 || ^12 || >=14} |
engines: {node: ^10 || ^12 || >=14} |
||||
|
|
||||
|
[email protected]: |
||||
|
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} |
||||
|
engines: {node: ^10 || ^12 || >=14} |
||||
|
|
||||
[email protected]: |
[email protected]: |
||||
resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} |
resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} |
||||
|
|
||||
@ -2929,8 +2933,8 @@ packages: |
|||||
peerDependencies: |
peerDependencies: |
||||
vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 |
vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 |
||||
|
|
||||
[email protected].0: |
[email protected].1: |
||||
resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==} |
resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==} |
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} |
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} |
||||
hasBin: true |
hasBin: true |
||||
peerDependencies: |
peerDependencies: |
||||
@ -5226,14 +5230,14 @@ snapshots: |
|||||
|
|
||||
'@types/[email protected]': {} |
'@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: |
dependencies: |
||||
'@babel/core': 7.26.8 |
'@babel/core': 7.26.8 |
||||
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/[email protected]) |
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/[email protected]) |
||||
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/[email protected]) |
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/[email protected]) |
||||
'@types/babel__core': 7.20.5 |
'@types/babel__core': 7.20.5 |
||||
react-refresh: 0.14.2 |
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: |
transitivePeerDependencies: |
||||
- supports-color |
- supports-color |
||||
|
|
||||
@ -6140,6 +6144,12 @@ snapshots: |
|||||
picocolors: 1.1.1 |
picocolors: 1.1.1 |
||||
source-map-js: 1.2.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]: {} |
||||
|
|
||||
[email protected]: {} |
[email protected]: {} |
||||
@ -6579,18 +6589,18 @@ snapshots: |
|||||
|
|
||||
[email protected]: {} |
[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: |
dependencies: |
||||
'@rollup/plugin-inject': 5.0.5([email protected]) |
'@rollup/plugin-inject': 5.0.5([email protected]) |
||||
node-stdlib-browser: 1.2.0 |
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: |
transitivePeerDependencies: |
||||
- rollup |
- 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: |
dependencies: |
||||
esbuild: 0.24.2 |
esbuild: 0.24.2 |
||||
postcss: 8.5.1 |
postcss: 8.5.3 |
||||
rollup: 4.34.6 |
rollup: 4.34.6 |
||||
optionalDependencies: |
optionalDependencies: |
||||
'@types/node': 22.13.4 |
'@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