feat: 新增主题跟随系统

新增主题跟随系统
This commit is contained in:
theo
2025-12-25 17:06:39 +08:00
parent 39859aebd5
commit 3b7a1b0254
4 changed files with 38 additions and 3 deletions

View File

@@ -23,7 +23,7 @@
<script setup lang="ts">
import { useSettingsStore } from "@/store";
import { ThemeMode } from "@/enums";
import { Moon, Sunny } from "@element-plus/icons-vue";
import { Moon, Sunny, Monitor } from "@element-plus/icons-vue";
const { t } = useI18n();
const settingsStore = useSettingsStore();
@@ -31,6 +31,7 @@ const settingsStore = useSettingsStore();
const theneList = [
{ label: t("login.light"), value: ThemeMode.LIGHT, component: Sunny },
{ label: t("login.dark"), value: ThemeMode.DARK, component: Moon },
{ label: t("login.auto"), value: ThemeMode.AUTO, component: Monitor },
];
const handleDarkChange = (theme: ThemeMode) => {

View File

@@ -8,6 +8,7 @@
"languageToggle": "Language Switch",
"dark": "Dark",
"light": "Light",
"auto": "Follow System",
"username": "Username",
"password": "Password",
"login": "Login",

View File

@@ -8,6 +8,7 @@
"languageToggle": "语言切换",
"dark": "暗黑",
"light": "明亮",
"auto": "跟随系统",
"username": "用户名",
"password": "密码",
"login": "登 录",

View File

@@ -66,6 +66,35 @@ export const useSettingsStore = defineStore("setting", () => {
// 主题模式(亮色/暗色)
const theme = useStorage<ThemeMode>(STORAGE_KEYS.THEME, defaultSettings.theme);
// 系统主题媒体查询(用于 ThemeMode.AUTO
const prefersDarkMedia =
typeof window !== "undefined" && typeof window.matchMedia === "function"
? window.matchMedia("(prefers-color-scheme: dark)")
: null;
function getSystemTheme(): ThemeMode {
return prefersDarkMedia && prefersDarkMedia.matches ? ThemeMode.DARK : ThemeMode.LIGHT;
}
function handleSystemThemeChange(e: MediaQueryListEvent | MediaQueryList) {
// 仅在用户选择自动(跟随系统)时响应系统主题变化
if (theme.value === ThemeMode.AUTO) {
const effectiveTheme = (e as MediaQueryList).matches ? ThemeMode.DARK : ThemeMode.LIGHT;
toggleDarkMode(effectiveTheme === ThemeMode.DARK);
const colors = generateThemeColors(themeColor.value, effectiveTheme);
applyTheme(colors);
}
}
if (prefersDarkMedia) {
// 兼容旧浏览器和新浏览器的监听方式
if (typeof prefersDarkMedia.addEventListener === "function") {
prefersDarkMedia.addEventListener("change", handleSystemThemeChange);
} else if (typeof (prefersDarkMedia as any).addListener === "function") {
(prefersDarkMedia as any).addListener(handleSystemThemeChange);
}
}
// 设置项映射,用于统一管理
const settingsMap = {
showTagsView,
@@ -80,8 +109,11 @@ export const useSettingsStore = defineStore("setting", () => {
watch(
[theme, themeColor],
([newTheme, newThemeColor]: [ThemeMode, string]) => {
toggleDarkMode(newTheme === ThemeMode.DARK);
const colors = generateThemeColors(newThemeColor, newTheme);
// 计算实际生效的主题:若为 AUTO 则使用系统当前偏好
const effectiveTheme: ThemeMode = newTheme === ThemeMode.AUTO ? getSystemTheme() : newTheme;
toggleDarkMode(effectiveTheme === ThemeMode.DARK);
const colors = generateThemeColors(newThemeColor, effectiveTheme);
applyTheme(colors);
},
{ immediate: true }