1
0
Code Issues Pull Requests Packages Projects Releases Wiki Activity GitHub Gitee

feat: 深色模式适配

This commit is contained in:
2025-02-22 22:11:39 +08:00
parent efdc89bba1
commit 907c6dd1c2
8 changed files with 156 additions and 38 deletions

View File

@@ -9,6 +9,7 @@ const themeConfigStore = useThemeConfigStore()
<template> <template>
{{ themeConfigStore.elConfig.size }} {{ themeConfigStore.elConfig.size }}
{{ themeConfigStore.themeConfig.themeMode }}
<el-config-provider :size="themeConfigStore.elConfig.size" :z-index="themeConfigStore.elConfig.zIndex" <el-config-provider :size="themeConfigStore.elConfig.size" :z-index="themeConfigStore.elConfig.zIndex"
:button="{ autoInsertSpace: true }" :locale="locale"> :button="{ autoInsertSpace: true }" :locale="locale">
<MainView /> <MainView />

View File

@@ -1,26 +1,3 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */ /* semantic color variables for this project */
:root { :root {
--color-background: var(--vt-c-white); --color-background: var(--vt-c-white);
@@ -84,3 +61,11 @@ body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.light body {
}
.dark body {
background-color: black;
color: white;
}

View File

@@ -4,7 +4,7 @@ a,
.green { .green {
text-decoration: none; text-decoration: none;
color: hsla(160, 100%, 37%, 1); color: hsla(160, 100%, 37%, 1);
transition: 0.4s; /* transition: 0.4s; */
padding: 3px; padding: 3px;
} }

View File

@@ -0,0 +1,98 @@
<template>
<ElSwitch v-model="themeConfig.themeMode" :active-icon="Moon" active-value="dark" :inactive-icon="Sunny"
inactive-value="light" inline-prompt @click="_toggleDark($event)" />
</template>
<script setup lang="ts">
import { nextTick, onBeforeMount } from 'vue'
import { storeToRefs } from 'pinia'
import { ElSwitch } from 'element-plus'
import { Moon, Sunny } from '@element-plus/icons-vue'
import { useThemeConfigStore } from '@/stores/themeConfig'
import { useDark, useToggle } from '@vueuse/core'
const themeConfigStore = useThemeConfigStore()
const { themeConfig } = storeToRefs(themeConfigStore)
const isDark = useDark()
onBeforeMount(() => {
if (themeConfig.value.themeMode === 'auto') {
} else {
if (themeConfig.value.themeMode === 'dark') {
isDark.value = true
} else {
isDark.value = false
}
}
const root = document.documentElement
root.classList.add(isDark.value ? 'dark' : 'light')
})
const _toggleDark = async (event: MouseEvent) => {
if (typeof document.startViewTransition === 'function') {
const x = event.clientX
const y = event.clientY
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y))
nextTick(async () => {
let _isDark: boolean
const transition = document.startViewTransition(() => {
const root = document.documentElement
_isDark = root.classList.contains('dark')
root.classList.remove(_isDark ? 'dark' : 'light')
root.classList.add(_isDark ? 'light' : 'dark')
})
await transition.ready.then(() => {
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
// console.log('_isDark', _isDark)
document.documentElement.animate(
{
// clipPath: _isDark ? [...clipPath].reverse() : clipPath,
clipPath: clipPath,
},
{
duration: 500,
easing: 'ease-in',
// pseudoElement: _isDark ? '::view-transition-old(root)' : '::view-transition-new(root)',
pseudoElement: '::view-transition-new(root)',
}
)
})
})
} else {
const toggleDark = useToggle(themeConfig.value.isDark)
await toggleDark()
}
}
</script>
<style>
/* 注意这里不加 scope, 是全局样式 */
::view-transition-old(root),
::view-transition-new(root) {
mix-blend-mode: normal;
animation: none;
}
::view-transition-old(root) {
z-index: 999;
}
::view-transition-new(root) {
z-index: 1;
}
.dark,
.light {
&::view-transition-old(root) {
z-index: 1;
}
&::view-transition-new(root) {
z-index: 999;
}
}
</style>

View File

@@ -8,6 +8,9 @@ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
// element-plus 深色模式
import 'element-plus/theme-chalk/dark/css-vars.css'
const app = createApp(App) const app = createApp(App)
// 导入 vue-i18n 模块 // 导入 vue-i18n 模块

View File

@@ -1,20 +1,41 @@
import { ref } from 'vue' import { computed, ref, type WritableComputedRef } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { ElConfigSize, ThemeMode } from '@/types/common/ThemeConfig';
import { useDark } from '@vueuse/core';
export const useThemeConfigStore = defineStore('themeConfig', () => { export const useThemeConfigStore = defineStore('themeConfig', () => {
// refer: https://element-plus.org/zh-CN/component/config-provider.html // refer: https://element-plus.org/zh-CN/component/config-provider.html
const elConfig = ref<{ const elConfig = ref<{
// 全局组件大小 // 全局组件大小
size: "" | "small" | "default" | "large"; size: ElConfigSize;
// 全局初始化 zIndex 的值 // 全局初始化 zIndex 的值
zIndex?: number; zIndex?: number;
}>({ }>({
size: 'small', size: 'small',
zIndex: 3000, // zIndex: 3000,
})
const themeConfig = ref<{
themeMode: ThemeMode,
// updateThemeMode: Function,
getCurrentThemeMode: Function,
}>({
themeMode: 'auto',
// updateThemeMode: (themeMode: ThemeMode) => {
// themeConfig.value.themeMode = themeMode
// },
getCurrentThemeMode: () => {
if (themeConfig.value.themeMode === 'auto') {
return ''
}
return themeConfig.value.themeMode
},
}) })
return { return {
elConfig, elConfig,
themeConfig,
} }
}, { }, {
// 启用持久化 // 启用持久化

View File

@@ -0,0 +1,10 @@
/**
* element-plus config
*/
export type ElConfigSize = '' | 'small' | 'default' | 'large'
/**
* theme config
*/
export type ThemeMode = 'auto' | 'light' | 'dark'

View File

@@ -1,20 +1,20 @@
<template> <template>
<RouterView /> <RouterView />
<header> <DarkSwitch />
<div class="wrapper"> <div class="wrapper">
<ElButton @click="() => themeConfigStore.elConfig.size = 'small'">哈哈哈</ElButton> <ElButton @click="() => themeConfigStore.elConfig.size = 'small'">哈哈哈</ElButton>
<ElButton @click="() => themeConfigStore.elConfig.size = 'default'">哈哈哈</ElButton> <ElButton @click="() => themeConfigStore.elConfig.size = 'default'">哈哈哈</ElButton>
<ElButton @click="() => themeConfigStore.elConfig.size = 'large'">哈哈哈</ElButton> <ElButton @click="() => themeConfigStore.elConfig.size = 'large'">哈哈哈</ElButton>
<nav> <nav>
<!-- <RouterLink to="/">Home</RouterLink> --> <!-- <RouterLink to="/">Home</RouterLink> -->
<!-- <RouterLink to="/about">About</RouterLink> --> <!-- <RouterLink to="/about">About</RouterLink> -->
</nav> </nav>
</div> </div>
</header>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import DarkSwitch from '@/components/DarkSwitch/DarkSwitch.vue';
import { useThemeConfigStore } from '@/stores/themeConfig'; import { useThemeConfigStore } from '@/stores/themeConfig';
import { ElButton } from 'element-plus'; import { ElButton } from 'element-plus';
import { RouterLink, RouterView } from 'vue-router' import { RouterLink, RouterView } from 'vue-router'