- 新增 API 模块统一封装所有 IPC 调用,提高代码可维护性 - 创建 `src/types/index.ts` 集中定义核心业务类型(Game, NodeConfig 等) - 新增组合式函数 `useFilePicker`、`useGameScanner` 和 `useAppUpdater` 以复用逻辑 - 改进设置页面,新增侧边栏导航和多个设置模块(通用、网络、日志、关于) - 优化本地代理逻辑,增加节点列表变化监听和自动重启机制 - 扩展协议解析测试用例,覆盖更多 VMess、VLESS Reality 等场景 - 更新项目结构文档 `docs/src-structure.md` 说明模块职责 - 修复 Electron 主进程预加载路径兼容性问题
86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
import type { Theme, ThemeColor } from '@/types'
|
|
|
|
export type { Theme, ThemeColor }
|
|
|
|
const theme = ref<Theme>('auto')
|
|
const resolvedTheme = ref<'light' | 'dark'>('dark') // Default to dark
|
|
const themeColor = ref<ThemeColor>('green')
|
|
|
|
export function useTheme() {
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
|
|
function applyTheme() {
|
|
const root = document.documentElement
|
|
const isDark = theme.value === 'dark' || (theme.value === 'auto' && mediaQuery.matches)
|
|
|
|
resolvedTheme.value = isDark ? 'dark' : 'light'
|
|
|
|
// Apply dark mode
|
|
if (isDark) {
|
|
root.classList.add('dark')
|
|
} else {
|
|
root.classList.remove('dark')
|
|
}
|
|
|
|
// Apply theme color
|
|
// Remove previous theme classes
|
|
root.classList.remove('theme-green', 'theme-blue', 'theme-purple', 'theme-orange', 'theme-red')
|
|
root.classList.add(`theme-${themeColor.value}`)
|
|
}
|
|
|
|
function setTheme(newTheme: Theme) {
|
|
theme.value = newTheme
|
|
localStorage.setItem('theme', newTheme)
|
|
applyTheme()
|
|
}
|
|
|
|
function setThemeColor(color: ThemeColor) {
|
|
themeColor.value = color
|
|
localStorage.setItem('themeColor', color)
|
|
applyTheme()
|
|
}
|
|
|
|
function toggleTheme() {
|
|
const next = resolvedTheme.value === 'dark' ? 'light' : 'dark'
|
|
setTheme(next)
|
|
}
|
|
|
|
function handleSystemChange() {
|
|
if (theme.value === 'auto') {
|
|
applyTheme()
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
const savedTheme = localStorage.getItem('theme') as Theme
|
|
if (savedTheme && ['light', 'dark', 'auto'].includes(savedTheme)) {
|
|
theme.value = savedTheme
|
|
}
|
|
|
|
const savedColor = localStorage.getItem('themeColor') as ThemeColor
|
|
if (savedColor && ['green', 'blue', 'purple', 'orange', 'red'].includes(savedColor)) {
|
|
themeColor.value = savedColor
|
|
}
|
|
|
|
applyTheme()
|
|
mediaQuery.addEventListener('change', handleSystemChange)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
mediaQuery.removeEventListener('change', handleSystemChange)
|
|
})
|
|
|
|
const isDark = computed(() => resolvedTheme.value === 'dark')
|
|
|
|
return {
|
|
theme,
|
|
resolvedTheme,
|
|
isDark,
|
|
themeColor,
|
|
setTheme,
|
|
setThemeColor,
|
|
toggleTheme
|
|
}
|
|
}
|