|
|
import { defineStore } from 'pinia' |
|
|
import { ref, computed, watch } from 'vue' |
|
|
|
|
|
|
|
|
export const ThemeMode = { |
|
|
LIGHT: 'light', |
|
|
DARK: 'dark', |
|
|
AUTO: 'auto' |
|
|
} |
|
|
|
|
|
export const useThemeStore = defineStore('theme', () => { |
|
|
|
|
|
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 { |
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
const savedMode = localStorage.getItem('themeMode') |
|
|
|
|
|
if (savedMode && Object.values(ThemeMode).includes(savedMode)) { |
|
|
themeMode.value = savedMode |
|
|
} else { |
|
|
|
|
|
themeMode.value = ThemeMode.AUTO |
|
|
} |
|
|
|
|
|
|
|
|
applyTheme() |
|
|
|
|
|
|
|
|
watchSystemTheme() |
|
|
} |
|
|
|
|
|
|
|
|
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] |
|
|
} |
|
|
|
|
|
|
|
|
watch(themeMode, (newMode) => { |
|
|
localStorage.setItem('themeMode', newMode) |
|
|
applyTheme() |
|
|
}) |
|
|
|
|
|
|
|
|
watch(systemPrefersDark, () => { |
|
|
|
|
|
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) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const toggleTheme = () => { |
|
|
cycleThemeMode() |
|
|
} |
|
|
|
|
|
const setTheme = (theme) => { |
|
|
if (theme === 'dark') { |
|
|
setThemeMode(ThemeMode.DARK) |
|
|
} else if (theme === 'light') { |
|
|
setThemeMode(ThemeMode.LIGHT) |
|
|
} |
|
|
} |
|
|
|
|
|
return { |
|
|
|
|
|
themeMode, |
|
|
isDarkMode, |
|
|
currentTheme, |
|
|
systemPrefersDark, |
|
|
|
|
|
|
|
|
ThemeMode, |
|
|
|
|
|
|
|
|
initTheme, |
|
|
setThemeMode, |
|
|
cycleThemeMode, |
|
|
watchSystemTheme, |
|
|
|
|
|
|
|
|
toggleTheme, |
|
|
setTheme |
|
|
} |
|
|
}) |
|
|
|