前端: 浅色模式 + 系统自动主题
- 引入语义化 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:
@@ -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)
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user