v1.3.0: 主题系统+代码分割+设置重构+命令片段库+命令面板+连接面板 | 19 files +2141/-257 | tsc零错误 构建成功

This commit is contained in:
OpsXShell Dev committed 2026-04-18 19:25:45 +08:00
1 parent caba5f4c0d
commit 1f2de032a4
19 files changed
+2142 -258

No files matched your search

+76
View File
@@ -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 }
}