前端: 浅色模式 + 系统自动主题

- 引入语义化 CSS 变量令牌(bg/surface/edge/ink/muted/accent 等), data-theme 三态切换
- theme store(localStorage + 系统偏好跟随), 首屏内联脚本防主题闪烁
- ThemeToggle 组件(浅色/深色/跟随系统) 置于导航与控制台顶栏
- 全量替换硬编码 zinc/emerald/red 类为令牌, 图表基线/状态色随主题适配
- 浅色对比度校准(accent/err/warn 深浅各一套)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-15 16:20:43 +08:00
co-authored by Claude
parent 4846db9293
commit a422034b2b
24 changed files with 380 additions and 249 deletions
+42
View File
@@ -0,0 +1,42 @@
import { defineStore } from 'pinia'
export type ThemeMode = 'light' | 'dark' | 'system'
const STORAGE_KEY = 'ot_theme'
const media = window.matchMedia('(prefers-color-scheme: dark)')
function resolve(mode: ThemeMode): 'light' | 'dark' {
if (mode === 'system') return media.matches ? 'dark' : 'light'
return mode
}
export const useThemeStore = defineStore('theme', {
state: () => ({
mode: (localStorage.getItem(STORAGE_KEY) as ThemeMode) || 'system',
}),
getters: {
resolved(state): 'light' | 'dark' {
return resolve(state.mode)
},
},
actions: {
// 应用当前主题;监听系统切换(system 模式时跟随)
init() {
this.apply()
media.addEventListener('change', () => this.apply())
},
set(mode: ThemeMode) {
this.mode = mode
localStorage.setItem(STORAGE_KEY, mode)
this.apply()
},
cycle() {
const order: ThemeMode[] = ['system', 'light', 'dark']
const i = order.indexOf(this.mode)
this.set(order[(i + 1) % order.length])
},
apply() {
document.documentElement.setAttribute('data-theme', this.resolved)
},
},
})