Files
inchstep/web/src/components/ThemeProvider.tsx
T
zeronline 471013938d
CI / Server (Go) (push) Has been cancelled
CI / Web (Next.js) (push) Has been cancelled
CI / Mobile (React Native) (push) Has been cancelled
CI / Admin (React) (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
提交修改
2026-06-29 17:38:01 +08:00

62 lines
1.5 KiB
TypeScript

'use client'
import { createContext, useContext, useEffect, useState, useCallback } from 'react'
import type { ThemeMode } from '@/constants/theme'
interface IThemeContext {
mode: ThemeMode
toggle: () => void
setMode: (mode: ThemeMode) => void
}
const ThemeContext = createContext<IThemeContext>({
mode: 'dark',
toggle: () => {},
setMode: () => {},
})
export function useTheme() {
return useContext(ThemeContext)
}
export default function ThemeProvider({ children }: { children: React.ReactNode }) {
const [mode, setModeState] = useState<ThemeMode>('dark')
const [mounted, setMounted] = useState(false)
useEffect(() => {
const stored = localStorage.getItem('inchstep-theme') as ThemeMode | null
if (stored === 'light' || stored === 'dark') {
setModeState(stored)
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
setModeState('dark')
} else {
setModeState('dark')
}
setMounted(true)
}, [])
useEffect(() => {
if (!mounted) return
document.documentElement.setAttribute('data-theme', mode)
localStorage.setItem('inchstep-theme', mode)
}, [mode, mounted])
const toggle = useCallback(() => {
setModeState(prev => (prev === 'light' ? 'dark' : 'light'))
}, [])
const setMode = useCallback((m: ThemeMode) => {
setModeState(m)
}, [])
if (!mounted) {
return <div style={{ visibility: 'hidden' }}>{children}</div>
}
return (
<ThemeContext.Provider value={{ mode, toggle, setMode }}>
{children}
</ThemeContext.Provider>
)
}