File size: 3,527 Bytes
69b897d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import { defineStore } from 'pinia'
import { ref, computed, watch } from 'vue'

// 主题模式枚举
export const ThemeMode = {
  LIGHT: 'light',
  DARK: 'dark',
  AUTO: 'auto'
}

export const useThemeStore = defineStore('theme', () => {
  // 状态 - 支持三种模式:light, dark, auto
  const themeMode = ref(ThemeMode.AUTO)
  const systemPrefersDark = ref(false)

  // 计算属性 - 实际的暗黑模式状态
  const isDarkMode = computed(() => {
    if (themeMode.value === ThemeMode.DARK) {
      return true
    } else if (themeMode.value === ThemeMode.LIGHT) {
      return false
    } else {
      // auto 模式,跟随系统
      return systemPrefersDark.value
    }
  })

  // 计算属性 - 当前实际使用的主题
  const currentTheme = computed(() => {
    return isDarkMode.value ? ThemeMode.DARK : ThemeMode.LIGHT
  })

  // 初始化主题
  const initTheme = () => {
    // 检测系统主题偏好
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
    systemPrefersDark.value = mediaQuery.matches

    // 从 localStorage 读取保存的主题模式
    const savedMode = localStorage.getItem('themeMode')

    if (savedMode && Object.values(ThemeMode).includes(savedMode)) {
      themeMode.value = savedMode
    } else {
      // 默认使用 auto 模式
      themeMode.value = ThemeMode.AUTO
    }

    // 应用主题
    applyTheme()

    // 开始监听系统主题变化
    watchSystemTheme()
  }

  // 应用主题到 DOM
  const applyTheme = () => {
    const root = document.documentElement

    if (isDarkMode.value) {
      root.classList.add('dark')
    } else {
      root.classList.remove('dark')
    }
  }

  // 设置主题模式
  const setThemeMode = (mode) => {
    if (Object.values(ThemeMode).includes(mode)) {
      themeMode.value = mode
    }
  }

  // 循环切换主题模式
  const cycleThemeMode = () => {
    const modes = [ThemeMode.LIGHT, ThemeMode.DARK, ThemeMode.AUTO]
    const currentIndex = modes.indexOf(themeMode.value)
    const nextIndex = (currentIndex + 1) % modes.length
    themeMode.value = modes[nextIndex]
  }

  // 监听主题模式变化,自动保存到 localStorage 并应用
  watch(themeMode, (newMode) => {
    localStorage.setItem('themeMode', newMode)
    applyTheme()
  })

  // 监听系统主题偏好变化
  watch(systemPrefersDark, () => {
    // 只有在 auto 模式下才需要重新应用主题
    if (themeMode.value === ThemeMode.AUTO) {
      applyTheme()
    }
  })

  // 监听系统主题变化
  const watchSystemTheme = () => {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')

    const handleChange = (e) => {
      systemPrefersDark.value = e.matches
    }

    // 初始检测
    systemPrefersDark.value = mediaQuery.matches

    // 添加监听器
    mediaQuery.addEventListener('change', handleChange)

    // 返回清理函数
    return () => {
      mediaQuery.removeEventListener('change', handleChange)
    }
  }

  // 兼容旧版 API
  const toggleTheme = () => {
    cycleThemeMode()
  }

  const setTheme = (theme) => {
    if (theme === 'dark') {
      setThemeMode(ThemeMode.DARK)
    } else if (theme === 'light') {
      setThemeMode(ThemeMode.LIGHT)
    }
  }

  return {
    // State
    themeMode,
    isDarkMode,
    currentTheme,
    systemPrefersDark,

    // Constants
    ThemeMode,

    // Actions
    initTheme,
    setThemeMode,
    cycleThemeMode,
    watchSystemTheme,

    // 兼容旧版 API
    toggleTheme,
    setTheme
  }
})