refactor: ♻️ refactor dark mode using vueuse useDark

This commit is contained in:
xiangshu233 2024-03-10 21:08:06 +08:00
parent 3cbf88638f
commit d2c4fd207b
10 changed files with 117 additions and 170 deletions

View File

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="zh-cmn-Hans" id="htmlRoot" class> <html lang="zh-cmn-Hans" id="htmlRoot">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" /> <link rel="icon" type="image/svg+xml" href="/logo.svg" />
@ -10,12 +10,12 @@
<div id="app"> <div id="app">
<script> <script>
;(() => { ;(() => {
const { darkMode, appTheme = '#5d9dfe' } = const { darkMode = 'dark', appTheme = '#5d9dfe' } =
JSON.parse(window.localStorage.getItem('DESIGN-SETTING')) || {} JSON.parse(window.localStorage.getItem('DESIGN-SETTING')) || {}
let htmlRoot = document.getElementById('htmlRoot') let htmlRoot = document.getElementById('htmlRoot')
if (htmlRoot) { if (htmlRoot) {
htmlRoot.setAttribute('data-theme', darkMode || 'light') htmlRoot.classList.add(darkMode)
} }
// 设置主题色变量 // 设置主题色变量
@ -29,7 +29,7 @@
body { body {
margin: 0; margin: 0;
} }
html[data-theme='dark'] .first-loading-wrap { html.dark .first-loading-wrap {
background-color: #101014; background-color: #101014;
} }
.first-loading-wrap { .first-loading-wrap {

View File

@ -27,6 +27,7 @@
<template #icon> <template #icon>
<i :class="menu.meta?.icon" /> <i :class="menu.meta?.icon" />
</template> </template>
{{ menu.meta?.title }}
</van-tabbar-item> </van-tabbar-item>
</van-tabbar> </van-tabbar>
</div> </div>

View File

@ -11,7 +11,6 @@ import 'virtual:svg-icons-register'
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router, { setupRouter } from './router' import router, { setupRouter } from './router'
import { updateDarkSign } from './theme'
import { setupStore } from '@/store' import { setupStore } from '@/store'
async function bootstrap() { async function bootstrap() {
@ -23,11 +22,6 @@ async function bootstrap() {
await router.isReady() await router.isReady()
// 路由准备就绪后挂载APP实例 // 路由准备就绪后挂载APP实例
app.mount('#app', true) app.mount('#app', true)
// 根节点挂载 dark 标识
const appDesignSetting = window.localStorage.getItem('DESIGN-SETTING')
const darkMode = appDesignSetting && JSON.parse(appDesignSetting).darkMode
updateDarkSign(darkMode)
} }
void bootstrap() void bootstrap()

View File

@ -43,6 +43,26 @@ const routeModuleList: Array<RouteRecordRaw> = [
}, },
], ],
}, },
{
path: '/example',
name: 'Example',
redirect: '/example/index',
component: Layout,
meta: {
title: '示例',
icon: 'i-material-symbols:award-star',
},
children: [
{
path: 'index',
name: 'ExamplePage',
meta: {
keepAlive: false,
},
component: () => import('@/views/example/index.vue'),
},
],
},
{ {
path: '/my', path: '/my',
name: 'My', name: 'My',

View File

@ -37,7 +37,7 @@ export const appThemeList: string[] = [
const setting: DesignSettingState = { const setting: DesignSettingState = {
// 深色主题 // 深色主题
darkMode: 'light', darkMode: 'dark',
// 系统主题色 // 系统主题色
appTheme: '#5d9dfe', appTheme: '#5d9dfe',
// 系统内置主题色列表 // 系统内置主题色列表

View File

@ -10,7 +10,7 @@ html {
position: relative; position: relative;
} }
[data-theme='dark'] { html.dark {
&, &,
* { * {
color-scheme: dark !important; color-scheme: dark !important;
@ -22,7 +22,7 @@ html {
} }
} }
[data-theme='light'] { html.light {
&, &,
* { * {
color-scheme: light !important; color-scheme: light !important;
@ -69,7 +69,6 @@ a:active {
color: rgb(#0000, 0.7); color: rgb(#0000, 0.7);
} }
/* stylelint-disable-next-line no-duplicate-selectors */
a:active, a:active,
a:hover { a:hover {
outline: 0; outline: 0;
@ -93,24 +92,16 @@ a:hover {
transform: scale(1.03); transform: scale(1.03);
} }
.xicon { html.light {
font-size: 18px; .my-card {
backdrop-filter: blur(10px);
svg { background: rgba(255, 255, 255, 70%);
width: 100% !important;
height: 100% !important;
} }
} }
.my-card { html.dark {
backdrop-filter: blur(10px);
/* stylelint-disable-next-line color-function-notation */
background: rgba(255, 255, 255, 70%);
}
html[data-theme='dark'] {
.my-card { .my-card {
/* stylelint-disable-next-line color-function-notation */ backdrop-filter: blur(10px);
background: rgba(30, 30, 30, 70%); background: rgba(30, 30, 30, 70%);
} }
} }

View File

@ -0,0 +1,40 @@
<template>
<div class="my-4">
<van-cell-group inset>
<van-cell center title="🌓 暗黑模式">
<template #right-icon>
<i inline-block align-middle i="dark:carbon-moon carbon-sun" />
<span class="ml-2">{{ isDark ? 'Dark' : 'Light' }}</span>
<span class="mx-2">{{ isDark }}</span>
<van-switch v-model="checked" size="22" @click="toggle()" />
</template>
</van-cell>
</van-cell-group>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useDark, useToggle } from '@vueuse/core'
import { useDesignSettingStore } from '@/store/modules/designSetting'
const designStore = useDesignSettingStore()
const isDark = useDark({
valueDark: 'dark',
valueLight: 'light',
})
const checked = ref(isDark.value)
const toggleDark = useToggle(isDark)
function toggle() {
toggleDark()
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
}
</script>
<style scoped lang="less">
</style>

View File

@ -2,11 +2,13 @@
<div> <div>
<NavBar /> <NavBar />
<van-divider>主题模式</van-divider> <van-divider>主题模式</van-divider>
<van-cell center title="暗黑模式"> <van-cell-group inset>
<template #right-icon> <van-cell center title="暗黑模式">
<van-switch v-model="getDarkMode" /> <template #right-icon>
</template> <van-switch v-model="getDarkMode" size="22" />
</van-cell> </template>
</van-cell>
</van-cell-group>
<van-divider>系统主题色</van-divider> <van-divider>系统主题色</van-divider>
<div flex="~" justify="center"> <div flex="~" justify="center">
@ -14,8 +16,8 @@
<span <span
v-for="(item, index) in designStore.appThemeList" v-for="(item, index) in designStore.appThemeList"
:key="index" :key="index"
h="9" h="8"
w="9" w="8"
items-center items-center
border="2 rounded-md" border="2 rounded-md"
flex="~" flex="~"
@ -32,24 +34,28 @@
</div> </div>
<van-divider>页面切换动画</van-divider> <van-divider>页面切换动画</van-divider>
<van-cell center title="开启动画"> <van-cell-group inset>
<template #right-icon> <van-cell center title="开启动画">
<van-switch v-model="designStore.isPageAnimate" /> <template #right-icon>
</template> <van-switch v-model="designStore.isPageAnimate" size="22" />
</van-cell> </template>
</van-cell>
<van-cell center title="动画类型">
<van-field
v-model="animateState.text"
readonly
class="!p-0"
:disabled="!designStore.isPageAnimate"
is-link
label-class="font-bold"
input-align="right"
:center="true"
:border="false"
@click="openAnimatePick"
/>
</van-cell>
</van-cell-group>
<van-field
v-model="animateState.text"
label="动画类型"
readonly
:disabled="!designStore.isPageAnimate"
is-link
label-class="font-bold"
input-align="right"
:center="true"
:border="false"
@click="openAnimatePick"
/>
<van-popup v-model:show="animateState.showPicker" position="bottom" round> <van-popup v-model:show="animateState.showPicker" position="bottom" round>
<van-picker <van-picker
v-model="animateState.value" v-model="animateState.value"
@ -63,19 +69,25 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive } from 'vue' import { computed, reactive } from 'vue'
import { useDark, useToggle } from '@vueuse/core'
import NavBar from './components/NavBar.vue' import NavBar from './components/NavBar.vue'
import { updateDarkSign } from '@/theme'
import { useDesignSettingStore } from '@/store/modules/designSetting' import { useDesignSettingStore } from '@/store/modules/designSetting'
import { animates as animateOptions } from '@/settings/animateSetting' import { animates as animateOptions } from '@/settings/animateSetting'
const designStore = useDesignSettingStore() const designStore = useDesignSettingStore()
const isDark = useDark({
valueDark: 'dark',
valueLight: 'light',
})
const toggleDark = useToggle(isDark)
const getDarkMode = computed({ const getDarkMode = computed({
get: () => designStore.getDarkMode === 'dark', get: () => isDark.value,
set: (value) => { set: () => {
const darkMode = value ? 'dark' : 'light' toggleDark()
updateDarkSign(darkMode) designStore.setDarkMode(isDark.value ? 'dark' : 'light')
designStore.setDarkMode(darkMode)
}, },
}) })

View File

@ -1,112 +0,0 @@
<template>
<div class="h-screen flex flex-col items-center justify-center p-8">
<!-- <van-cell center title="🌗 暗黑模式">
<template #right-icon>
<van-switch v-model="getDarkMode" size="18px" />
</template>
</van-cell> -->
<div class="wel-box w-full flex flex-col justify-between">
<div class="wel-top">
<div class="logo enter-y">
<SvgIcon :size="130" name="logo" />
</div>
<div
class="enter-y text-darkBlue dark:text-garyWhite mb-4 mt-12 text-center text-2xl font-black"
>
欢迎来到 {{ title }}
</div>
<div class="enter-y mb-6 mt-4 w-full">
<van-swipe class="h-30" :autoplay="3000" :indicator-color="designStore.appTheme">
<van-swipe-item
v-for="(text, index) in getSwipeText"
:key="index"
class="text-center text-gray-700 leading-relaxed dark:text-gray-400"
>
<p class="text-lg">
{{ text.title }}
</p>
<p class="text-sm">
{{ text.details }}
</p>
</van-swipe-item>
</van-swipe>
</div>
</div>
<div class="wel-bottom">
<van-button
class="enter-y !rounded-md"
type="primary"
block
@click="router.push({ name: 'Login' })"
>
Let's Get Started
</van-button>
<a class="enter-y mt-6 text-sm">创建账户</a>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { useDesignSettingStore } from '@/store/modules/designSetting'
import SvgIcon from '@/components/SvgIcon.vue'
import { useGlobSetting } from '@/hooks/setting'
// import { updateDarkSign } from '@/theme'
// const getDarkMode = computed({
// get: () => designStore.getDarkMode === 'dark',
// set: (value) => {
// const darkMode = value ? 'dark' : 'light'
// updateDarkSign(darkMode)
// designStore.setDarkMode(darkMode)
// },
// })
const designStore = useDesignSettingStore()
const globSetting = useGlobSetting()
const router = useRouter()
const { title } = globSetting
const getSwipeText = computed(() => {
return [
{
title: '💡 最新技术栈',
details: '基于Vue3、Vant4、Vite、TypeScript等最新技术栈开发',
},
{
title: '⚡️ 轻量快速的热重载',
details: '无论应用程序大小如何都始终极快的模块热重载HMR',
},
{
title: '🔩 主题配置',
details: '具备主题配置及黑暗主题适配,且持久化保存',
},
{
title: '🛠️ 丰富的 Vite 插件',
details: '集成大部分 Vite 插件,无需繁琐配置,开箱即用',
},
]
})
</script>
<style scoped lang="less">
.wel-box {
min-height: 50vh;
max-width: 45vh;
min-width: 30vh;
.wel-top {
display: flex;
align-items: center;
flex-direction: column;
}
.wel-bottom {
display: flex;
align-items: center;
flex-direction: column;
}
}
</style>

View File

@ -78,5 +78,6 @@ export default defineConfig({
'i-simple-icons:atlassian', 'i-simple-icons:atlassian',
'i-simple-icons:soundcharts', 'i-simple-icons:soundcharts',
'i-simple-icons:docsify', 'i-simple-icons:docsify',
'i-material-symbols:award-star',
], ],
}) })