Files
SPlayer/src/components/Global/Provider.vue
2025-10-24 15:23:51 +08:00

279 lines
8.3 KiB
Vue

<!-- 全局配置 -->
<template>
<n-config-provider
:locale="zhCN"
:date-locale="dateZhCN"
:theme="theme"
:theme-overrides="themeOverrides"
abstract
inline-theme-disabled
preflight-style-disabled
>
<n-global-style />
<n-loading-bar-provider>
<n-dialog-provider>
<n-notification-provider>
<n-message-provider :max="1" placement="bottom">
<n-modal-provider>
<slot />
<NaiveProviderContent />
</n-modal-provider>
</n-message-provider>
</n-notification-provider>
</n-dialog-provider>
</n-loading-bar-provider>
</n-config-provider>
</template>
<script setup lang="ts">
import {
zhCN,
dateZhCN,
darkTheme,
useOsTheme,
useLoadingBar,
useModal,
useDialog,
useMessage,
useNotification,
GlobalThemeOverrides,
} from "naive-ui";
import { useSettingStore, useStatusStore } from "@/stores";
import { setColorSchemes } from "@/utils/color";
// import { rgbToHex } from "@imsyy/color-utils";
import themeColor from "@/assets/data/themeColor.json";
const statusStore = useStatusStore();
const settingStore = useSettingStore();
// 操作系统主题
const osTheme = useOsTheme();
// 全局主题(使用 shallowRef 避免深层追踪开销)
const themeOverrides = shallowRef<GlobalThemeOverrides>({});
// 轻量的 rgba 构造器
const toRGBA = (rgb: string, alpha: number) => `rgba(${rgb}, ${alpha})`;
// 主题缓存键
let lastThemeCacheKey: string | null = null;
// 获取明暗模式
const theme = computed(() => {
return settingStore.themeMode === "auto"
? // 跟随系统
osTheme.value === "dark"
? darkTheme
: null
: // 自定义
settingStore.themeMode === "dark"
? darkTheme
: null;
});
// 获取当前主题色数据
const getThemeMainColor = () => {
const themeType = theme.value ? "dark" : "light";
if (settingStore.themeFollowCover && statusStore.songCoverTheme) {
const coverColor = statusStore.songCoverTheme;
if (!coverColor) return {};
return setColorSchemes(coverColor, themeType);
} else if (settingStore.themeColorType !== "custom") {
return setColorSchemes(themeColor[settingStore.themeColorType].color, themeType);
} else {
return setColorSchemes(settingStore.themeCustomColor, themeType);
}
};
// 更改全局主题
const changeGlobalTheme = () => {
try {
// 获取配色方案
const colorSchemes = getThemeMainColor();
if (!colorSchemes || Object.keys(colorSchemes).length === 0) {
themeOverrides.value = {};
return;
}
// 构造主题缓存 Key
const themeModeLabel = theme.value ? "dark" : "light";
const themeCacheKey = `${themeModeLabel}|${settingStore.themeGlobalColor ? 1 : 0}|${settingStore.globalFont}|${colorSchemes.primary}|${colorSchemes.background}|${colorSchemes["surface-container"]}`;
if (lastThemeCacheKey === themeCacheKey) return;
lastThemeCacheKey = themeCacheKey;
// 关键颜色
const primaryRGB = colorSchemes.primary as string;
const surfaceContainerRGB = colorSchemes["surface-container"] as string;
// 全局字体
const fontFamily = `${settingStore.globalFont === "default" ? "v-sans" : settingStore.globalFont}, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
// 通用样式基座
const commonBase = {
fontFamily,
primaryColor: `rgb(${primaryRGB})`,
primaryColorHover: toRGBA(primaryRGB, 0.78),
primaryColorPressed: toRGBA(primaryRGB, 0.26),
primaryColorSuppl: toRGBA(primaryRGB, 0.12),
} as GlobalThemeOverrides["common"];
if (settingStore.themeGlobalColor) {
themeOverrides.value = {
common: {
...commonBase,
textColorBase: primaryRGB,
textColor1: `rgb(${primaryRGB})`,
textColor2: toRGBA(primaryRGB, 0.82),
textColor3: toRGBA(primaryRGB, 0.52),
bodyColor: `rgb(${colorSchemes.background})`,
cardColor: `rgb(${surfaceContainerRGB})`,
tagColor: `rgb(${surfaceContainerRGB})`,
modalColor: `rgb(${surfaceContainerRGB})`,
popoverColor: `rgb(${surfaceContainerRGB})`,
buttonColor2: toRGBA(primaryRGB, 0.08),
buttonColor2Hover: toRGBA(primaryRGB, 0.12),
buttonColor2Pressed: toRGBA(primaryRGB, 0.08),
iconColor: `rgb(${primaryRGB})`,
iconColorHover: toRGBA(primaryRGB, 0.475),
closeIconColor: toRGBA(primaryRGB, 0.58),
hoverColor: toRGBA(primaryRGB, 0.09),
borderColor: toRGBA(primaryRGB, 0.09),
textColorDisabled: toRGBA(primaryRGB, 0.3),
placeholderColorDisabled: toRGBA(primaryRGB, 0.3),
iconColorDisabled: toRGBA(primaryRGB, 0.3),
},
Card: {
borderColor: toRGBA(primaryRGB, 0.09),
},
Button: {
textColorHover: toRGBA(primaryRGB, 0.78),
textColorFocus: toRGBA(primaryRGB, 0.58),
colorPrimary: toRGBA(primaryRGB, 0.9),
colorHoverPrimary: `rgb(${primaryRGB})`,
colorPressedPrimary: toRGBA(primaryRGB, 0.8),
colorFocusPrimary: `rgb(${primaryRGB})`,
},
Slider: {
handleColor: `rgb(${primaryRGB})`,
fillColor: `rgb(${primaryRGB})`,
fillColorHover: `rgb(${primaryRGB})`,
railColor: toRGBA(primaryRGB, 0.2),
railColorHover: toRGBA(primaryRGB, 0.3),
},
Switch: {
railColorActive: toRGBA(primaryRGB, 0.8),
},
Input: {
color: toRGBA(primaryRGB, 0.1),
colorFocus: `rgb(${surfaceContainerRGB})`,
placeholderColor: toRGBA(primaryRGB, 0.58),
border: `1px solid ${toRGBA(primaryRGB, 0.1)}`,
clearColor: toRGBA(primaryRGB, 0.38),
clearColorHover: toRGBA(primaryRGB, 0.48),
clearColorPressed: toRGBA(primaryRGB, 0.3),
},
Icon: {
color: `rgb(${primaryRGB})`,
},
Empty: {
textColor: toRGBA(primaryRGB, 0.38),
},
Divider: {
color: toRGBA(primaryRGB, 0.09),
},
Dropdown: {
dividerColor: toRGBA(primaryRGB, 0.09),
},
Layout: {
siderBorderColor: toRGBA(primaryRGB, 0.09),
},
Tabs: {
colorSegment: toRGBA(primaryRGB, 0.08),
tabColorSegment: toRGBA(primaryRGB, 0.12),
},
Drawer: {
headerBorderBottom: `1px solid ${toRGBA(primaryRGB, 0.09)}`,
footerBorderTop: `1px solid ${toRGBA(primaryRGB, 0.09)}`,
},
Menu: {
dividerColor: toRGBA(primaryRGB, 0.09),
},
Progress: {
railColor: toRGBA(primaryRGB, 0.16),
},
Popover: {
color: `rgb(${surfaceContainerRGB})`,
},
};
} else {
themeOverrides.value = {
common: {
...commonBase,
},
Icon: {
color: `rgb(${primaryRGB})`,
},
Slider: {
handleColor: `rgb(${primaryRGB})`,
fillColor: `rgb(${primaryRGB})`,
fillColorHover: `rgb(${primaryRGB})`,
railColor: toRGBA(primaryRGB, 0.2),
railColorHover: toRGBA(primaryRGB, 0.3),
},
};
}
} catch (error) {
themeOverrides.value = {};
console.error("切换主题色出现错误:", error);
window.$message.error("切换主题色出现错误,已使用默认配置");
}
};
// 挂载 naive 组件
const setupNaiveTools = () => {
// 进度条
window.$loadingBar = useLoadingBar();
// 通知
window.$notification = useNotification();
// 信息
window.$message = useMessage();
// 对话框
window.$dialog = useDialog();
// 模态框
window.$modal = useModal();
};
// 挂载工具
const NaiveProviderContent = defineComponent({
setup() {
setupNaiveTools();
},
render() {
return h("div", { className: "main-tools" });
},
});
// 监听设置更改
watch(
() => [
settingStore.themeColorType,
settingStore.themeFollowCover,
settingStore.themeGlobalColor,
settingStore.globalFont,
statusStore.songCoverTheme?.main,
theme.value,
],
() => changeGlobalTheme(),
);
// 自定义颜色更改
watchDebounced(
() => settingStore.themeCustomColor,
() => {
changeGlobalTheme();
},
{ debounce: 500, maxWait: 1000 },
);
onMounted(() => {
changeGlobalTheme();
});
</script>