2025-12-27 15:06:02 +00:00

146 lines
3.4 KiB
JavaScript

import { createContext, useContext, useState, useEffect } from 'react'
import { theme } from 'antd'
import PropTypes from 'prop-types'
const ThemeContext = createContext()
export const ThemeProvider = ({ children }) => {
const [isSystem, setIsSystem] = useState(() => {
const savedSystem = sessionStorage.getItem('isSystem')
return savedSystem ? JSON.parse(savedSystem) : true
})
const [isDarkMode, setIsDarkMode] = useState(() => {
const savedTheme = sessionStorage.getItem('isDarkMode')
return savedTheme ? JSON.parse(savedTheme) : true
})
const [isCompact, setIsCompact] = useState(() => {
const savedCompact = sessionStorage.getItem('isCompact')
return savedCompact ? JSON.parse(savedCompact) : false
})
// System theme detection
useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
const handleSystemThemeChange = (e) => {
if (isSystem) {
setIsDarkMode(e.matches)
}
}
// Set initial value
if (isSystem) {
setIsDarkMode(mediaQuery.matches)
}
// Add listener
mediaQuery.addEventListener('change', handleSystemThemeChange)
// Cleanup
return () =>
mediaQuery.removeEventListener('change', handleSystemThemeChange)
}, [isSystem])
useEffect(() => {
sessionStorage.setItem('isSystem', JSON.stringify(isSystem))
}, [isSystem])
useEffect(() => {
sessionStorage.setItem('isDarkMode', JSON.stringify(isDarkMode))
}, [isDarkMode])
useEffect(() => {
sessionStorage.setItem('isCompact', JSON.stringify(isCompact))
}, [isCompact])
const toggleTheme = () => {
if (isSystem) {
setIsSystem(false)
}
setIsDarkMode(!isDarkMode)
}
const toggleSystem = () => {
setIsSystem(!isSystem)
if (!isSystem) {
// When enabling system theme, update to match system preference
setIsDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches)
}
}
const toggleCompact = () => {
setIsCompact(!isCompact)
}
const getThemeAlgorithm = () => {
var baseAlgorithm
if (isDarkMode == true) {
baseAlgorithm = theme.darkAlgorithm
} else {
baseAlgorithm = theme.defaultAlgorithm
}
return isCompact ? [theme.compactAlgorithm, baseAlgorithm] : [baseAlgorithm]
}
const colors = {
colorPrimary: '#0091FF',
colorSuccess: '#30D158',
colorWarning: '#FF9230',
colorError: '#FF4245',
colorInfo: '#0A84FF',
colorLink: '#5AC8F5',
colorCyan: '#5AC8F5',
colorPink: '#FF69B4',
colorPurple: '#800080',
colorMagenta: '#FF00FF',
colorVolcano: '#FF4500'
}
const getColors = () => {
return colors
}
const themeConfig = {
algorithm: getThemeAlgorithm(),
token: {
...colors,
borderRadius: '12px'
},
components: {
Layout: {
headerBg: isDarkMode ? '#141414' : '#ffffff'
}
}
}
return (
<ThemeContext.Provider
value={{
isDarkMode,
toggleTheme,
isCompact,
toggleCompact,
isSystem,
toggleSystem,
getColors,
themeConfig
}}
>
{children}
</ThemeContext.Provider>
)
}
ThemeProvider.propTypes = {
children: PropTypes.node.isRequired
}
// eslint-disable-next-line react-refresh/only-export-components
export const useThemeContext = () => {
const context = useContext(ThemeContext)
if (!context) {
throw new Error('useThemeContext must be used within a ThemeProvider')
}
return context
}