mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-03 13:44:47 +08:00
feat: 添加整体风格自适应操作系统浅色、深色、自动主题功能,让平台充满现代气息 (#869)
* feat: 添加整体风格自适应操作系统浅色、深色、自动主题功能,让平台更加现代化 * chore: update
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
reactive,
|
||||
computed,
|
||||
nextTick,
|
||||
onUnmounted,
|
||||
onBeforeMount
|
||||
} from "vue";
|
||||
import panel from "../panel/index.vue";
|
||||
@@ -21,6 +22,7 @@ import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
|
||||
import Check from "@iconify-icons/ep/check";
|
||||
import dayIcon from "@/assets/svg/day.svg?component";
|
||||
import darkIcon from "@/assets/svg/dark.svg?component";
|
||||
import systemIcon from "@/assets/svg/system.svg?component";
|
||||
|
||||
const { device } = useNav();
|
||||
const { isDark } = useDark();
|
||||
@@ -32,6 +34,7 @@ const horizontalRef = ref();
|
||||
|
||||
const {
|
||||
dataTheme,
|
||||
overallStyle,
|
||||
layoutTheme,
|
||||
themeColors,
|
||||
toggleClass,
|
||||
@@ -70,7 +73,7 @@ const getThemeColorStyle = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
/** 当网页为暗黑模式时不显示亮白色切换选项 */
|
||||
/** 当网页整体为暗色风格时不显示亮白色主题配色切换选项 */
|
||||
const showThemeColors = computed(() => {
|
||||
return themeColor => {
|
||||
return themeColor === "light" && isDark.value ? false : true;
|
||||
@@ -162,13 +165,24 @@ const getThemeColor = computed(() => {
|
||||
const themeOptions = computed<Array<OptionsType>>(() => {
|
||||
return [
|
||||
{
|
||||
label: "亮色",
|
||||
label: "浅色",
|
||||
icon: dayIcon,
|
||||
theme: "light",
|
||||
tip: "清新启航,点亮舒适的工作界面",
|
||||
iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
|
||||
},
|
||||
{
|
||||
label: "暗色",
|
||||
label: "深色",
|
||||
icon: darkIcon,
|
||||
theme: "dark",
|
||||
tip: "月光序曲,沉醉于夜的静谧雅致",
|
||||
iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
|
||||
},
|
||||
{
|
||||
label: "自动",
|
||||
icon: systemIcon,
|
||||
theme: "system",
|
||||
tip: "同步时光,界面随晨昏自然呼应",
|
||||
iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
|
||||
}
|
||||
];
|
||||
@@ -177,10 +191,12 @@ const themeOptions = computed<Array<OptionsType>>(() => {
|
||||
const markOptions: Array<OptionsType> = [
|
||||
{
|
||||
label: "灵动",
|
||||
tip: "灵动标签,添趣生辉",
|
||||
value: "smart"
|
||||
},
|
||||
{
|
||||
label: "卡片",
|
||||
tip: "卡片标签,高效浏览",
|
||||
value: "card"
|
||||
}
|
||||
];
|
||||
@@ -195,7 +211,8 @@ function setLayoutModel(layout: string) {
|
||||
darkMode: $storage.layout?.darkMode,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: layoutTheme.value.theme
|
||||
themeColor: $storage.layout?.themeColor,
|
||||
overallStyle: $storage.layout?.overallStyle
|
||||
};
|
||||
useAppStoreHook().setLayout(layout);
|
||||
}
|
||||
@@ -220,9 +237,34 @@ watch($storage, ({ layout }) => {
|
||||
}
|
||||
});
|
||||
|
||||
const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
/** 根据操作系统主题设置平台整体风格 */
|
||||
function updateTheme() {
|
||||
if (overallStyle.value !== "system") return;
|
||||
if (mediaQueryList.matches) {
|
||||
dataTheme.value = true;
|
||||
} else {
|
||||
dataTheme.value = false;
|
||||
}
|
||||
dataThemeChange(overallStyle.value);
|
||||
}
|
||||
|
||||
function removeMatchMedia() {
|
||||
mediaQueryList.removeEventListener("change", updateTheme);
|
||||
}
|
||||
|
||||
/** 监听操作系统主题改变 */
|
||||
function watchSystemThemeChange() {
|
||||
updateTheme();
|
||||
removeMatchMedia();
|
||||
mediaQueryList.addEventListener("change", updateTheme);
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
/* 初始化项目配置 */
|
||||
nextTick(() => {
|
||||
watchSystemThemeChange();
|
||||
settings.greyVal &&
|
||||
document.querySelector("html")?.setAttribute("class", "html-grey");
|
||||
settings.weakVal &&
|
||||
@@ -231,6 +273,8 @@ onBeforeMount(() => {
|
||||
settings.hideFooter && hideFooterChange();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => removeMatchMedia);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -238,12 +282,17 @@ onBeforeMount(() => {
|
||||
<div class="p-6">
|
||||
<p class="mb-3 font-medium text-sm dark:text-white">整体风格</p>
|
||||
<Segmented
|
||||
:modelValue="dataTheme ? 1 : 0"
|
||||
class="select-none"
|
||||
:modelValue="overallStyle === 'system' ? 2 : dataTheme ? 1 : 0"
|
||||
:options="themeOptions"
|
||||
@change="
|
||||
{
|
||||
dataTheme = !dataTheme;
|
||||
dataThemeChange();
|
||||
theme => {
|
||||
theme.index === 1 && theme.index !== 2
|
||||
? (dataTheme = true)
|
||||
: (dataTheme = false);
|
||||
overallStyle = theme.option.theme;
|
||||
dataThemeChange(theme.option.theme);
|
||||
theme.index === 2 && watchSystemThemeChange();
|
||||
}
|
||||
"
|
||||
/>
|
||||
@@ -272,7 +321,7 @@ onBeforeMount(() => {
|
||||
<li
|
||||
ref="verticalRef"
|
||||
v-tippy="{
|
||||
content: '左侧菜单',
|
||||
content: '左侧菜单,亲切熟悉',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'vertical' ? 'is-select' : ''"
|
||||
@@ -285,7 +334,7 @@ onBeforeMount(() => {
|
||||
v-if="device !== 'mobile'"
|
||||
ref="horizontalRef"
|
||||
v-tippy="{
|
||||
content: '顶部菜单',
|
||||
content: '顶部菜单,简洁概览',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'horizontal' ? 'is-select' : ''"
|
||||
@@ -298,7 +347,7 @@ onBeforeMount(() => {
|
||||
v-if="device !== 'mobile'"
|
||||
ref="mixRef"
|
||||
v-tippy="{
|
||||
content: '混合菜单',
|
||||
content: '混合菜单,灵活多变',
|
||||
zIndex: 41000
|
||||
}"
|
||||
:class="layoutTheme.layout === 'mix' ? 'is-select' : ''"
|
||||
@@ -311,6 +360,7 @@ onBeforeMount(() => {
|
||||
|
||||
<p class="mt-5 mb-3 font-medium text-base dark:text-white">页签风格</p>
|
||||
<Segmented
|
||||
class="select-none"
|
||||
:modelValue="markValue === 'smart' ? 0 : 1"
|
||||
:options="markOptions"
|
||||
@change="onChange"
|
||||
|
||||
@@ -38,6 +38,7 @@ export function useDataThemeChange() {
|
||||
|
||||
const { $storage } = useGlobal<GlobalPropertiesApi>();
|
||||
const dataTheme = ref<boolean>($storage?.layout?.darkMode);
|
||||
const overallStyle = ref<string>($storage?.layout?.overallStyle);
|
||||
const body = document.documentElement as HTMLElement;
|
||||
|
||||
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
|
||||
@@ -64,7 +65,8 @@ export function useDataThemeChange() {
|
||||
darkMode: dataTheme.value,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: isClick ? theme : storageThemeColor
|
||||
themeColor: isClick ? theme : storageThemeColor,
|
||||
overallStyle: overallStyle.value
|
||||
};
|
||||
|
||||
if (theme === "default" || theme === "light") {
|
||||
@@ -94,8 +96,9 @@ export function useDataThemeChange() {
|
||||
}
|
||||
};
|
||||
|
||||
/** 亮色、暗色整体风格切换 */
|
||||
function dataThemeChange() {
|
||||
/** 浅色、深色整体风格切换 */
|
||||
function dataThemeChange(overall?: string) {
|
||||
overallStyle.value = overall;
|
||||
if (useEpThemeStoreHook().epTheme === "light" && dataTheme.value) {
|
||||
setLayoutThemeColor("default", false);
|
||||
} else {
|
||||
@@ -130,6 +133,7 @@ export function useDataThemeChange() {
|
||||
return {
|
||||
body,
|
||||
dataTheme,
|
||||
overallStyle,
|
||||
layoutTheme,
|
||||
themeColors,
|
||||
onReset,
|
||||
|
||||
@@ -28,7 +28,8 @@ export function useLayout() {
|
||||
darkMode: $config?.DarkMode ?? false,
|
||||
sidebarStatus: $config?.SidebarStatus ?? true,
|
||||
epThemeColor: $config?.EpThemeColor ?? "#409EFF",
|
||||
themeColor: $config?.Theme ?? "light"
|
||||
themeColor: $config?.Theme ?? "light",
|
||||
overallStyle: $config?.OverallStyle ?? "light"
|
||||
};
|
||||
}
|
||||
/** 灰色模式、色弱模式、隐藏标签页 */
|
||||
|
||||
@@ -73,7 +73,8 @@ function setTheme(layoutModel: string) {
|
||||
darkMode: $storage.layout?.darkMode,
|
||||
sidebarStatus: $storage.layout?.sidebarStatus,
|
||||
epThemeColor: $storage.layout?.epThemeColor,
|
||||
themeColor: $storage.layout?.themeColor
|
||||
themeColor: $storage.layout?.themeColor,
|
||||
overallStyle: $storage.layout?.overallStyle
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,7 +120,7 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
useDataThemeChange().dataThemeChange();
|
||||
useDataThemeChange().dataThemeChange($storage.layout?.overallStyle);
|
||||
});
|
||||
|
||||
const layoutHeader = defineComponent({
|
||||
|
||||
Reference in New Issue
Block a user