109 lines
2.9 KiB
TypeScript
109 lines
2.9 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 currentMode = computed(() =>
|
|
currentTheme.value === darkTheme ? "dark" : "light",
|
|
);
|
|
|
|
// 保存主题到本地存储
|
|
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,
|
|
currentMode,
|
|
setTheme,
|
|
toggleTheme,
|
|
isDarkTheme,
|
|
isLightTheme,
|
|
setupThemeListener,
|
|
};
|
|
});
|