103 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { ref, computed, watch } from 'vue'
 | 
						|
import { defineStore } from 'pinia'
 | 
						|
 | 
						|
// 本地存储主题的键名
 | 
						|
const THEME_STORAGE_KEY = 'fpga-weblab-theme'
 | 
						|
 | 
						|
export const useThemeStore = defineStore('theme', () => {
 | 
						|
  const allTheme = ["winter", "night"]
 | 
						|
  const darkTheme = "night";
 | 
						|
  const lightTheme = "winter";
 | 
						|
  
 | 
						|
  // 尝试从本地存储中获取保存的主题
 | 
						|
  const getSavedTheme = (): string | null => {
 | 
						|
    return localStorage.getItem(THEME_STORAGE_KEY)
 | 
						|
  }
 | 
						|
  
 | 
						|
  // 检测系统主题偏好
 | 
						|
  const getPreferredTheme = (): string => {
 | 
						|
    const savedTheme = getSavedTheme()
 | 
						|
    // 如果有保存的主题设置,优先使用
 | 
						|
    if (savedTheme && allTheme.includes(savedTheme)) {
 | 
						|
      return savedTheme
 | 
						|
    }
 | 
						|
    // 否则检测系统主题模式
 | 
						|
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches 
 | 
						|
      ? darkTheme : lightTheme
 | 
						|
  }
 | 
						|
  
 | 
						|
  // 初始化主题为首选主题
 | 
						|
  const currentTheme = ref(getPreferredTheme())
 | 
						|
 | 
						|
  // 保存主题到本地存储
 | 
						|
  const saveTheme = (theme: string) => {
 | 
						|
    localStorage.setItem(THEME_STORAGE_KEY, theme)
 | 
						|
  }
 | 
						|
 | 
						|
  // 当主题变化时,保存到本地存储
 | 
						|
  watch(currentTheme, (newTheme) => {
 | 
						|
    saveTheme(newTheme)
 | 
						|
  })
 | 
						|
 | 
						|
  // 添加系统主题变化的监听
 | 
						|
  const setupThemeListener = () => {
 | 
						|
    if (window.matchMedia) {
 | 
						|
      const colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)')
 | 
						|
      const handler = (e: MediaQueryListEvent) => {
 | 
						|
        // 只有当用户没有手动设置过主题时,才跟随系统变化
 | 
						|
        if (!getSavedTheme()) {
 | 
						|
          currentTheme.value = e.matches ? darkTheme : lightTheme
 | 
						|
        }
 | 
						|
      }
 | 
						|
      
 | 
						|
      // 添加主题变化监听器
 | 
						|
      colorSchemeQuery.addEventListener('change', handler)
 | 
						|
    }
 | 
						|
  }
 | 
						|
  function setTheme(theme: string) {
 | 
						|
    const isContained: boolean = allTheme.includes(theme)
 | 
						|
    if (isContained) {
 | 
						|
      currentTheme.value = theme
 | 
						|
      saveTheme(theme) // 保存主题到本地存储
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      console.error(`Not have such theme: ${theme}`)
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function toggleTheme() {
 | 
						|
    if (currentTheme.value == darkTheme) {
 | 
						|
      currentTheme.value = lightTheme;
 | 
						|
    } else if (currentTheme.value == lightTheme) {
 | 
						|
      currentTheme.value = darkTheme;
 | 
						|
    } else {
 | 
						|
      currentTheme.value = lightTheme;
 | 
						|
    }
 | 
						|
    // 主题切换时自动保存(通过 watch 函数实现)
 | 
						|
  }
 | 
						|
 | 
						|
  function isDarkTheme(): boolean {
 | 
						|
    return currentTheme.value == darkTheme
 | 
						|
  }
 | 
						|
 | 
						|
  function isLightTheme(): boolean {
 | 
						|
    return currentTheme.value == lightTheme
 | 
						|
  }
 | 
						|
 | 
						|
  // 初始化时设置系统主题变化监听器
 | 
						|
  if (typeof window !== 'undefined') {
 | 
						|
    setupThemeListener()
 | 
						|
  }
 | 
						|
 | 
						|
  return {
 | 
						|
    allTheme,
 | 
						|
    currentTheme,
 | 
						|
    setTheme,
 | 
						|
    toggleTheme,
 | 
						|
    isDarkTheme,
 | 
						|
    isLightTheme,
 | 
						|
    setupThemeListener
 | 
						|
  }
 | 
						|
})
 | 
						|
 |