v1.3.0: 主题系统+代码分割+设置重构+命令片段库+命令面板+连接面板 | 19 files +2141/-257 | tsc零错误 构建成功
This commit is contained in:
1 parent
caba5f4c0d
commit
1f2de032a4
19 files changed
+2142
-258
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { useSettingsStore } from '../stores/settingsStore'
|
||||
import { darkColors, lightColors, type AppThemeMode, type ColorMap } from '../themes/app-theme'
|
||||
|
||||
/**
|
||||
* Resolves the *effective* theme ('dark' | 'light') from the user preference,
|
||||
* including the 'system' → prefers-color-scheme mapping.
|
||||
*/
|
||||
function resolveEffectiveTheme(preference: AppThemeMode): 'dark' | 'light' {
|
||||
if (preference !== 'system') return preference
|
||||
if (typeof window === 'undefined') return 'dark'
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a colour map to `document.documentElement` as CSS custom properties.
|
||||
*/
|
||||
function applyCSSVars(colors: ColorMap) {
|
||||
const root = document.documentElement
|
||||
for (const [key, value] of Object.entries(colors)) {
|
||||
root.style.setProperty(`--color-${key}`, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* useTheme — keeps the DOM in sync with the user's theme preference.
|
||||
*
|
||||
* • Reads `settings.theme` from the settings store.
|
||||
* • Listens to `prefers-color-scheme` changes when set to 'system'.
|
||||
* • Writes `data-theme="dark" | "light"` on `<html>`.
|
||||
* • Writes `--color-*` CSS custom properties on `<html>`.
|
||||
*/
|
||||
export function useTheme() {
|
||||
const theme = useSettingsStore((s) => s.settings.theme)
|
||||
const isLoaded = useSettingsStore((s) => s.isLoaded)
|
||||
|
||||
const effective = useMemo(() => resolveEffectiveTheme(theme), [theme])
|
||||
|
||||
// Apply theme to DOM whenever effective theme changes
|
||||
useEffect(() => {
|
||||
if (!isLoaded) return
|
||||
|
||||
const colors = effective === 'dark' ? darkColors : lightColors
|
||||
|
||||
// Set data attribute for potential direct CSS selectors
|
||||
document.documentElement.setAttribute('data-theme', effective)
|
||||
|
||||
// Apply CSS custom properties
|
||||
applyCSSVars(colors)
|
||||
|
||||
// Update body bg & colour (mirrors index.css body rules but via vars)
|
||||
document.body.style.backgroundColor = 'var(--color-dark-900)'
|
||||
document.body.style.color = 'var(--color-text-primary)'
|
||||
}, [effective, isLoaded])
|
||||
|
||||
// Listen for system colour-scheme changes when preference is 'system'
|
||||
useEffect(() => {
|
||||
if (theme !== 'system' || typeof window === 'undefined') return
|
||||
|
||||
const mql = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
|
||||
const handler = (e: MediaQueryListEvent) => {
|
||||
const newEffective = e.matches ? 'dark' : 'light'
|
||||
const colors = e.matches ? darkColors : lightColors
|
||||
document.documentElement.setAttribute('data-theme', newEffective)
|
||||
applyCSSVars(colors)
|
||||
document.body.style.backgroundColor = 'var(--color-dark-900)'
|
||||
document.body.style.color = 'var(--color-text-primary)'
|
||||
}
|
||||
|
||||
mql.addEventListener('change', handler)
|
||||
return () => mql.removeEventListener('change', handler)
|
||||
}, [theme])
|
||||
|
||||
return { theme, effective }
|
||||
}
|
||||
Reference in new issue
Block a user