Skip to content

Commit

Permalink
✨ feat(project): add theme feature dark light system model
Browse files Browse the repository at this point in the history
  • Loading branch information
ishareme committed Jan 5, 2023
1 parent e48730e commit 766b142
Show file tree
Hide file tree
Showing 16 changed files with 129 additions and 33 deletions.
8 changes: 4 additions & 4 deletions src/libs/Button/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ import { computed } from 'vue';
// size 大小 区分文字按钮和icon按钮
const typeEnum = {
primary: 'text-white bg-zinc-800 hover:bg-zinc-900 active:bg-zinc-800',
main: 'text-white bg-main hover:bg-hover-main active:bg-hover-main',
info: 'text-zinc-800 bg-zinc-200 hover:bg-zinc-300 active:bg-zinc-200',
primary:
'text-white bg-zinc-800 dark:bg-zinc-900 hover:bg-zinc-900 dark:hover:bg-zinc-700 active:bg-zinc-800 dark:active:bg-zinc-700',
main: 'text-white bg-main dark:bg-zinc-900 hover:bg-hover-main dark:hover:bg-zinc-700 active:bg-hover-main dark:active:bg-zinc-700',
info: 'text-zinc-800 dark:text-zinc-300 bg-zinc-200 dark:bg-zinc-700 hover:bg-zinc-300 dark:hover:bg-zinc-600 active:bg-zinc-200 dark:active:bg-zinc-700',
};
const sizeEnum = {
// 文字按钮
Expand Down Expand Up @@ -88,7 +89,6 @@ const props = defineProps({
type: String,
default: 'main',
validator(val) {
console.log('[ val ]', val);
const keys = Object.keys(typeEnum);
const result = keys.includes(val);
if (!result) {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Popover/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<div
ref="contentTarget"
v-show="isVisible"
class="absolute p-1 z-20 bg-white border rounded-md"
class="absolute p-1 z-20 bg-white dark:bg-zinc-900 border rounded-md dark:border-zinc-700"
:style="contentStyle"
>
<!-- 匿名插槽 弹出层视图中展示的内容-->
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Popup/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div
v-show="isVisable"
v-bind="$attrs"
class="w-screen bg-white z-50 fixed bottom-0 left-0"
class="w-screen bg-white dark:bg-zinc-800 z-50 fixed bottom-0 left-0"
>
<slot></slot>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/libs/Search/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
class="relative p-0.5 rounded-xl duration-500 hover:bg-red-200/40 group"
class="relative p-0.5 rounded-xl duration-500 border-white dark:border-zinc-200 hover:bg-red-200/40 group"
>
<SvgIcon
class="w-1.5 h-1.5 pcenterY left-2"
Expand All @@ -10,7 +10,7 @@
<input
v-model="inputValue"
type="text"
class="block w-full h-[44px] text-sm pl-4 outline-none bg-zinc-100 caret-zinc-400 text-zinc-900 tracking-wide font-semibold border rounded-xl border-zinc-100 duration-500 focus:border-red-300 group-hover:bg-white"
class="block w-full h-[44px] text-sm pl-4 outline-none bg-zinc-100 dark:bg-zinc-800 caret-zinc-400 text-zinc-900 dark:text-zinc-200 tracking-wide font-semibold border rounded-xl border-zinc-100 dark:border-zinc-700 duration-500 focus:border-red-300 group-hover:bg-white dark:group-hover:bg-zinc-900 dark:group-hover:border-zinc-700"
placeholder="搜索"
@keyup="onSearch"
@focus="onFocus"
Expand Down Expand Up @@ -40,7 +40,7 @@
<div
v-if="$slots.dropdown"
v-show="isFocus"
class="max-h-[368px] w-full text-base overflow-auto bg-white absolute top-[52px] left-0 z-20 p-2 rounded border border-b-zinc-200 duration-200 hover:shadow-2xl"
class="max-h-[368px] w-full text-base overflow-auto bg-white dark:bg-zinc-800 absolute top-[52px] left-0 z-20 p-2 rounded border border-b-zinc-200 dark:border-zinc-600 duration-200 hover:shadow-2xl"
>
<slot name="dropdown"></slot>
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

import { useRem } from '@/utils/flexible';
import useTheme from '@/utils/theme';

import libs from './libs';
import './styles/index.scss';
// 导入注册svg
import 'virtual:svg-icons-register';

useRem();
useTheme();

createApp(App).use(router).use(store).use(libs).mount('#app');
1 change: 1 addition & 0 deletions src/store/getters.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default {
categorys: (state) => state.category.categorys,
theme: (state) => state.theme.themeType,
};
5 changes: 4 additions & 1 deletion src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { createStore } from 'vuex';
import getters from './getters';
import category from './modules/category';
import theme from './modules/theme';

// 强制缓存
import createPersistedstate from 'vuex-persistedstate';

const store = createStore({
modules: {
category,
theme,
},
getters,
plugins: [
createPersistedstate({
// 指定保存的 localstorage 中的key
key: 'APP_KEYS',
// 需要保存的模块
paths: ['category'],
paths: ['category', 'theme'],
}),
],
});
Expand Down
12 changes: 12 additions & 0 deletions src/store/modules/theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { THEME_LIGHT } from '@/constants';
export default {
namespaced: true,
state: () => ({
themeType: THEME_LIGHT,
}),
mutations: {
changeThemeType(state, newTheme) {
state.themeType = newTheme;
},
},
};
47 changes: 47 additions & 0 deletions src/utils/theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { watch } from 'vue';
import store from '../store';
import { THEME_LIGHT, THEME_DARK, THEME_SYSTEM } from '@/constants';

// 监听主题变更
let matchMedia;
const watchSystemThemeChange = () => {
// 仅需初始化一次即可
if (matchMedia) return;
matchMedia = window.matchMedia('(prefers-color-scheme: dark)');
// 监听主题变更
matchMedia.onchange = () => {
changeTheme(THEME_SYSTEM);
};
};

const changeTheme = (theme) => {
let themeClassName = '';
switch (theme) {
case THEME_LIGHT:
themeClassName = 'light';
break;
case THEME_DARK:
themeClassName = 'dark';
break;
case THEME_SYSTEM:
watchSystemThemeChange();
themeClassName = matchMedia.matches ? 'dark' : 'light';
break;
}
const html = document.querySelector('html');
html.classList = themeClassName;
};

// 初始化主题
export default () => {
watch(
() => store.getters.theme,
(val) => {
changeTheme(val);
},
{
// 初始执行一次
immediate: true,
}
);
};
2 changes: 1 addition & 1 deletion src/views/layout/components/header/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
class="w-full bg-white border-b border-b-zinc-200 border-solid px-2 py-1"
class="w-full bg-white dark:bg-zinc-800 border-b border-b-zinc-200 dark:border-b-zinc-700 border-solid px-2 py-1 duration-500"
>
<div class="flex items-center">
<img
Expand Down
12 changes: 7 additions & 5 deletions src/views/layout/components/header/profile/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Popover placement="bottom-left" class="flex items-center">
<template #reference>
<div
class="relative flex items-center p-0.5 rounded-sm cursor-pointer duration-200 outline-none hover:bg-zinc-100"
class="relative flex items-center p-0.5 rounded-sm cursor-pointer duration-200 outline-none hover:bg-zinc-100 dark:hover:bg-zinc-900"
>
<img
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202104%2F22%2F20210422220415_2e4bd.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1675515403&t=3e7768a1fd37e2a38d6343bb5ee73cb9"
Expand All @@ -11,7 +11,7 @@
<SvgIcon
class="h-1.5 w-1.5 ml-0.5"
name="down-arrow"
fillClass="fill-zinc-900"
fillClass="fill-zinc-900 dark:fill-zinc-300"
/>
<SvgIcon
class="h-1.5 w-1.5 absolute right-[16px] bottom-0"
Expand All @@ -24,14 +24,16 @@
<div
v-for="item in profileMenu"
:key="item.id"
class="flex items-center p-1 cursor-pointer rounded hover:bg-zinc-100/60"
class="flex items-center p-1 cursor-pointer rounded hover:bg-zinc-100/60 dark:hover:bg-zinc-800"
>
<SvgIcon
:name="item.icon"
class="w-1.5 h-1.5 mr-1"
fillClass="fill-zinc-900"
fillClass="fill-zinc-900 dark:fill-zinc-300"
/>
<span class="text-zinc-800 text-sm">{{ item.title }}</span>
<span class="text-zinc-800 text-sm dark:text-zinc-300">{{
item.title
}}</span>
</div>
</div>
</Popover>
Expand Down
29 changes: 23 additions & 6 deletions src/views/layout/components/header/theme/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@
<Popover placement="bottom-left">
<template #reference>
<SvgIcon
name="theme-light"
class="w-4 h-4 p-1 cursor-pointer rounded-sm duration-200 outline-none hover:bg-zinc-100/60"
fillClass="fill-zinc-900"
:name="svgIconName"
class="w-4 h-4 p-1 cursor-pointer rounded-sm duration-200 outline-none hover:bg-zinc-100/60 dark:hover:bg-zinc-900"
fillClass="fill-zinc-900 dark:fill-zinc-300"
/>
</template>

<div class="w-[140px] overflow-hidden">
<div
v-for="item in themeData"
:key="item.id"
class="flex items-center p-1 cursor-pointer rounded hover:bg-zinc-100/60"
class="flex items-center p-1 cursor-pointer rounded hover:bg-zinc-100/60 dark:hover:bg-zinc-800"
@click="onItemClick(item)"
>
<SvgIcon
:name="item.icon"
class="w-1.5 h-1.5 mr-1"
fillClass="fill-zinc-900"
fillClass="fill-zinc-900 dark:fill-zinc-300"
/>
<span class="text-zinc-800 text-sm">{{ item.name }}</span>
<span class="text-zinc-800 text-sm dark:text-zinc-300">{{
item.name
}}</span>
</div>
</div>
</Popover>
</template>

<script setup>
import { THEME_DARK, THEME_LIGHT, THEME_SYSTEM } from '@/constants';
import { computed } from 'vue';
import { useStore } from 'vuex';
const themeData = [
{
id: 0,
Expand All @@ -47,6 +52,18 @@ const themeData = [
name: '跟随系统',
},
];
const store = useStore();
const onItemClick = (item) => {
store.commit('theme/changeThemeType', item.type);
};
// 展示图标
const svgIconName = computed(() => {
const findTheme = themeData.find(
(item) => item.type === store.getters.theme
);
return findTheme?.icon;
});
</script>
<style lang="scss" scoped></style>
8 changes: 6 additions & 2 deletions src/views/main/components/menu/index.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<template>
<div class="py-2 h-[80vh] flex flex-col">
<h2 class="text-xl text-zinc-900 font-bold mb-2 px-1">所有分类</h2>
<h2
class="text-xl text-zinc-900 font-bold mb-2 px-1 dark:text-zinc-200"
>
所有分类
</h2>
<ul class="overflow-y-scroll">
<li
v-for="(item, index) in $store.getters.categorys"
:key="item.id"
class="text-lg text-zinc-900 px-1 py-1.5 duration-200 active:bg-zinc-100"
class="text-lg text-zinc-900 px-1 py-1.5 duration-200 active:bg-zinc-100 dark:text-zinc-300 dark:active:bg-zinc-900"
@click="onMenuItemClick(index)"
>
{{ item.name }}
Expand Down
8 changes: 5 additions & 3 deletions src/views/main/components/navigation/mobile/index.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<template>
<div class="bg-white sticky top-0 left-0 z-10">
<div
class="bg-white sticky top-0 left-0 z-10 dark:bg-zinc-900 duration-500"
>
<ul
ref="ulTarget"
class="relative flex overflow-x-auto p-1 text-xs text-zinc-600 overflow-y-hidden"
>
<!-- 汉堡按钮 -->
<li
class="fixed right-[-1px] top-0 z-20 h-4 px-1 flex items-center bg-white shadow-l-white"
class="fixed right-[-1px] top-0 z-20 h-4 px-1 flex items-center bg-white dark:bg-zinc-900 shadow-l-white dark:shadow-l-zinc"
@click="onShowPopup"
>
<SvgIcon class="w-1.5 h-1.5" name="hamburger" />
Expand All @@ -16,7 +18,7 @@
<li
ref="sliderTarget"
:style="sliderStyle"
class="absolute h-[22px] bg-zinc-900 rounded-lg transition-all duration-200"
class="absolute h-[22px] bg-zinc-900 dark:bg-zinc-800 rounded-lg transition-all duration-200"
></li>

<!-- items -->
Expand Down
13 changes: 8 additions & 5 deletions src/views/main/components/navigation/pc/index.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
<template>
<div class="bg-white sticky top-0 left-0 w-full z-10">
<div
class="bg-white dark:bg-zinc-800 sticky top-0 left-0 w-full z-10 duration-500"
>
<ul
class="w-[75%] relative flex flex-wrap justify-center overflow-x-auto overflow-y-hidden px-[10px] py-1 text-xs text-zinc-600 duration-300 mx-auto"
:class="[isOpenCategory ? 'h-[206px]' : 'h-[56px]']"
>
<!-- 箭头 -->
<li
class="block absolute right-1 bottom-1 z-20 p-1 rounded cursor-pointer duration-200 hover:bg-zinc-200"
class="block absolute right-1 bottom-1 z-20 p-1 rounded cursor-pointer duration-200 hover:bg-zinc-200 dark:hover:bg-zinc-900"
@click="onToggleOpen"
>
<SvgIcon
:name="isOpenCategory ? 'fold' : 'unfold'"
class="w-1 h-1"
fillClass="fill-zinc-900"
fillClass="fill-zinc-900 dark:fill-zinc-300"
/>
</li>
<li
v-for="(item, index) in $store.getters.categorys"
:key="item.id"
@click="onItemClick(index)"
class="shrink-0 px-1.5 py-0 z-10 duration-200 text-zinc-700 text-base font-bold h-4 leading-4 cursor-pointer rounded mr-1 mb-1 hover:bg-zinc-200"
class="shrink-0 px-1.5 py-0 z-10 duration-200 text-zinc-900 dark:text-zinc-500 dark:hover:text-zinc-300 text-base font-bold h-4 leading-4 cursor-pointer rounded mr-1 mb-1 hover:bg-zinc-200 dark:hover:bg-zinc-900"
:class="{
'text-zinc-900 bg-zinc-200': currentCategoryIndex === index,
'text-zinc-900 dark:text-zinc-100/70 bg-zinc-200 dark:bg-zinc-900':
currentCategoryIndex === index,
}"
>
{{ item.name }}
Expand Down
3 changes: 3 additions & 0 deletions tailwind.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ function pxToVmin(variable) {
}

module.exports = {
// 手动切换暗黑模式
darkMode: 'class',
// tailwind 的应用范围
content: ['./index.html', './src/**/*.{vue,js}'],
theme: {
Expand All @@ -20,6 +22,7 @@ module.exports = {
},
boxShadow: {
'l-white': '-10px 0 10px white',
'l-zinc': '-10px 0 10px #18181b',
},
height: {
header: '72px',
Expand Down

0 comments on commit 766b142

Please sign in to comment.