/**
* 主题管理(日间/夜间模式)
*
* 桌面端:除了切换 ``,还会同步 Tauri 原生窗口标题栏的
* 主题(Windows 下通过 DwmSetWindowAttribute 切 immersive dark mode),
* 避免夜间模式下出现"应用黑、窗口栏白"的割裂观感。Web 端该步骤会安静跳过。
*/
import { isTauriRuntime } from './tauri-api.js'
const THEME_KEY = 'clawpanel-theme'
// 延迟加载 Tauri window 模块,Web 构建不会真正拉取
let _tauriWindowModule = null
async function getTauriCurrentWindow() {
if (!isTauriRuntime()) return null
if (_tauriWindowModule === false) return null
if (!_tauriWindowModule) {
try {
_tauriWindowModule = await import('@tauri-apps/api/window')
} catch (_) {
_tauriWindowModule = false
return null
}
}
try {
return _tauriWindowModule.getCurrentWindow()
} catch (_) {
return null
}
}
async function syncTauriTitleBar(theme) {
const win = await getTauriCurrentWindow()
if (!win || typeof win.setTheme !== 'function') return
try {
// Tauri v2: 接受 'light' | 'dark' | null(null = 跟随系统)
await win.setTheme(theme === 'dark' ? 'dark' : 'light')
} catch (_) {
// 某些 WebView2 版本或未授权时会抛错,静默忽略
}
}
export function initTheme() {
const saved = localStorage.getItem(THEME_KEY)
const theme = saved || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
applyTheme(theme)
}
export function toggleTheme(onApply) {
const html = document.documentElement
const current = html.dataset.theme || 'light'
const next = current === 'dark' ? 'light' : 'dark'
// 设置扩散起点:白切黑从左下角,黑切白从右上角
const toDark = next === 'dark'
html.style.setProperty('--theme-reveal-x', toDark ? '0%' : '100%')
html.style.setProperty('--theme-reveal-y', toDark ? '100%' : '0%')
const doApply = () => {
applyTheme(next)
if (onApply) onApply(next)
}
if (document.startViewTransition) {
document.startViewTransition(doApply)
} else {
doApply()
}
return next
}
export function getTheme() {
return document.documentElement.dataset.theme || 'light'
}
function applyTheme(theme) {
document.documentElement.dataset.theme = theme
localStorage.setItem(THEME_KEY, theme)
// Fire-and-forget,不等待 Tauri IPC 返回,避免阻塞 DOM 更新和过渡动画
syncTauriTitleBar(theme)
}