1
0
mirror of https://github.com/zclzone/vue-naive-admin.git synced 2025-04-30 22:29:01 +08:00

feat: 增加设置主题色功能

This commit is contained in:
zclzone 2024-05-10 20:02:55 +08:00
parent 621c34a1fb
commit cf3c4b9020
15 changed files with 3259 additions and 2714 deletions

View File

@ -5,23 +5,90 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.png" />
<link rel="stylesheet" href="/resource/loading.css" />
<style>
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
}
.dark .loading-container {
background-color: #232324;
color: rgba(255, 255, 255, 0.9);
}
.loading-container .loading {
--speed-of-animation: 0.9s;
--gap: 12px;
--first-color: #4c86f9;
--second-color: #49a84c;
--third-color: #f6bb02;
--fourth-color: #26a69a;
--fifth-color: #2196f3;
margin: auto;
width: 160px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
gap: var(--gap);
}
.loading-container .loading span {
width: 6px;
height: 80px;
background: var(--first-color);
animation: scale var(--speed-of-animation) ease-in-out infinite;
}
.loading-container .loading span:nth-child(2) {
background: var(--second-color);
animation-delay: -0.8s;
}
.loading-container .loading span:nth-child(3) {
background: var(--third-color);
animation-delay: -0.7s;
}
.loading-container .loading span:nth-child(4) {
background: var(--fourth-color);
animation-delay: -0.6s;
}
.loading-container .loading span:nth-child(5) {
background: var(--fifth-color);
animation-delay: -0.5s;
}
@keyframes scale {
0%,
40%,
100% {
transform: scaleY(0.25);
}
20% {
transform: scaleY(1);
}
}
</style>
<title><%= title %></title>
</head>
<body class="dark:text-#e9e9e9 auto-bg">
<div id="app">
<!-- 白屏时的loading效果 -->
<div class="loading-container">
<div class="loading-spin__container">
<div class="loading-spin">
<div class="left-0 top-0 loading-spin-item"></div>
<div class="left-0 bottom-0 loading-spin-item loading-delay-500"></div>
<div class="right-0 top-0 loading-spin-item loading-delay-1000"></div>
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
</div>
<div class="loading">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="loading-title"><%= title %></div>
</div>
<script src="/resource/loading.js"></script>
</div>
<script type="module" src="/src/main.js"></script>
</body>

View File

@ -10,6 +10,8 @@
"lint:fix": "eslint --fix --ext .js,.vue ."
},
"dependencies": {
"@ant-design/colors": "^7.0.2",
"@arco-design/color": "^0.4.0",
"@vueuse/core": "^10.9.0",
"axios": "^1.6.8",
"dayjs": "^1.11.10",

5648
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
/**********************************
* @Author: Ronnie Zhang
* @LastEditor: Ronnie Zhang
* @LastEditTime: 2023/12/04 22:50:18
* @Email: zclzone@outlook.com
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
**********************************/
.loading-container {
position: fixed;
left: 0;
top: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.loading-spin__container {
width: 56px;
height: 56px;
margin: 36px 0;
}
.loading-spin {
position: relative;
height: 100%;
animation: loadingSpin 1s linear infinite;
}
.left-0 {
left: 0;
}
.right-0 {
right: 0;
}
.top-0 {
top: 0;
}
.bottom-0 {
bottom: 0;
}
.loading-spin-item {
position: absolute;
height: 16px;
width: 16px;
background-color: var(--primary-color);
border-radius: 8px;
-webkit-animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes loadingSpin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loadingPulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: .5;
}
}
.loading-delay-500 {
-webkit-animation-delay: 500ms;
animation-delay: 500ms;
}
.loading-delay-1000 {
-webkit-animation-delay: 1000ms;
animation-delay: 1000ms;
}
.loading-delay-1500 {
-webkit-animation-delay: 1500ms;
animation-delay: 1500ms;
}
.loading-title {
font-size: 28px;
font-weight: 500;
color: var(--primary-color);
}

View File

@ -1,18 +0,0 @@
/**********************************
* @Author: Ronnie Zhang
* @LastEditor: Ronnie Zhang
* @LastEditTime: 2023/12/04 22:50:27
* @Email: zclzone@outlook.com
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
**********************************/
function addThemeColorCssVars() {
const key = '__THEME_COLOR__'
const defaultColor = '#316c72'
const themeColor = localStorage.getItem(key) || defaultColor
const cssVars = `--primary-color: ${themeColor}`
document.documentElement.style.cssText = cssVars
}
addThemeColorCssVars()

View File

@ -29,8 +29,6 @@
<script setup>
import { zhCN, dateZhCN, darkTheme } from 'naive-ui'
import { LayoutSetting } from '@/components'
import { useCssVar } from '@vueuse/core'
import { kebabCase } from 'lodash-es'
import { useAppStore, useTabStore } from '@/store'
const layouts = new Map()
@ -50,15 +48,6 @@ const Layout = computed(() => {
return getLayout(route.meta?.layout || appStore.layout)
})
function setupCssVar() {
const common = appStore.naiveThemeOverrides?.common || {}
for (const key in common) {
useCssVar(`--${kebabCase(key)}`, document.documentElement).value = common[key] || ''
if (key === 'primaryColor') window.localStorage.setItem('__THEME_COLOR__', common[key] || '')
}
}
setupCssVar()
const tabStore = useTabStore()
const keepAliveNames = computed(() => {
return tabStore.tabs.filter((item) => item.keepAlive).map((item) => item.name)

View File

@ -0,0 +1,25 @@
<template>
<n-tooltip trigger="hover">
<template #trigger>
<n-color-picker
class="mr-16 h-40 w-80"
:value="appStore.primaryColor"
:swatches="primaryColors"
:on-update:value="(v) => appStore.setPrimaryColor(v)"
/>
</template>
设置主题色
</n-tooltip>
</template>
<script setup>
import { getPresetColors } from '@arco-design/color'
import { useAppStore } from '@/store'
const appStore = useAppStore()
const primaryColors = Object.entries(getPresetColors()).map(([, value]) => value.primary)
watchEffect(() => {
appStore.setThemeColor(appStore.primaryColor, appStore.isDark)
})
</script>

View File

@ -66,7 +66,7 @@ function handleMenuSelect(key, item) {
right: 8px;
}
&.n-menu-item-content--selected::before {
border-left: 4px solid var(--primary-color);
border-left: 4px solid rgb(var(--primary-color));
}
}
}

View File

@ -11,7 +11,6 @@
<n-tabs
:value="tabStore.activeTab"
:closable="tabStore.tabs.length > 1"
:style="`--selected-bg: ${appStore.isDark ? '#1b2429' : '#eaf0f1'}`"
type="card"
@close="(path) => tabStore.removeTab(path)"
>
@ -38,10 +37,9 @@
<script setup>
import ContextMenu from './ContextMenu.vue'
import { useTabStore, useAppStore } from '@/store'
import { useTabStore } from '@/store'
const router = useRouter()
const appStore = useAppStore()
const tabStore = useTabStore()
const contextMenuOption = reactive({
@ -85,12 +83,12 @@ async function handleContextMenu(e, tagItem) {
border-radius: 4px !important;
margin-right: 4px;
&:hover {
border: 1px solid var(--primary-color) !important;
border: 1px solid rgb(var(--primary-color)) !important;
}
}
.n-tabs-tab--active {
border: 1px solid var(--primary-color) !important;
background-color: var(--selected-bg) !important;
border: 1px solid rgb(var(--primary-color)) !important;
background-color: rgba(var(--primary-color), 0.1) !important;
}
.n-tabs-pad,
.n-tabs-tab-pad,

View File

@ -32,6 +32,9 @@
class="i-me:gitee mr-16 cursor-pointer"
@click="handleLinkClick('https://gitee.com/isme-admin/vue-naive-admin/tree/2.x')"
/>
<ThemeSetting class="mr-16" />
<UserAvatar />
</div>
</AppCard>

View File

@ -34,6 +34,9 @@
class="i-me:gitee mr-16 cursor-pointer"
@click="handleLinkClick('https://gitee.com/isme-admin/vue-naive-admin/tree/2.x')"
/>
<ThemeSetting class="mr-16" />
<UserAvatar />
</div>
</AppCard>
@ -56,4 +59,8 @@ const { isFullscreen, toggle } = useFullscreen()
function handleLinkClick(link) {
window.open(link)
}
watchEffect(() => {
appStore.setThemeColor(appStore.primaryColor, appStore.isDark)
})
</script>

View File

@ -8,32 +8,14 @@
export const defaultLayout = 'normal'
export const defaultPrimaryColor = '#316C72'
export const naiveThemeOverrides = {
common: {
primaryColor: '#316C72FF',
primaryColorHover: '#316C72E3',
primaryColorPressed: '#2B4C59FF',
primaryColorSuppl: '#316C72E3',
infoColor: '#2080F0FF',
infoColorHover: '#4098FCFF',
infoColorPressed: '#1060C9FF',
infoColorSuppl: '#4098FCFF',
successColor: '#18A058FF',
successColorHover: '#36AD6AFF',
successColorPressed: '#0C7A43FF',
successColorSuppl: '#36AD6AFF',
warningColor: '#F0A020FF',
warningColorHover: '#FCB040FF',
warningColorPressed: '#C97C10FF',
warningColorSuppl: '#FCB040FF',
errorColor: '#D03050FF',
errorColorHover: '#DE576DFF',
errorColorPressed: '#AB1F3FFF',
errorColorSuppl: '#DE576DFF',
},
}

View File

@ -8,13 +8,15 @@
import { defineStore } from 'pinia'
import { useDark } from '@vueuse/core'
import { defaultLayout, naiveThemeOverrides } from '@/settings'
import { generate, getRgbStr } from '@arco-design/color'
import { defaultLayout, defaultPrimaryColor, naiveThemeOverrides } from '@/settings'
export const useAppStore = defineStore('app', {
state: () => ({
collapsed: false,
isDark: useDark(),
layout: defaultLayout,
primaryColor: defaultPrimaryColor,
naiveThemeOverrides,
}),
actions: {
@ -30,9 +32,25 @@ export const useAppStore = defineStore('app', {
setLayout(v) {
this.layout = v
},
setPrimaryColor(color) {
this.primaryColor = color
},
setThemeColor(color = this.primaryColor, isDark = this.isDark) {
const colors = generate(color, {
list: true,
dark: isDark,
})
document.body.style.setProperty('--primary-color', getRgbStr(colors[5]))
this.naiveThemeOverrides.common = Object.assign(this.naiveThemeOverrides.common || {}, {
primaryColor: colors[5],
primaryColorHover: colors[4],
primaryColorSuppl: colors[4],
primaryColorPressed: colors[6],
})
},
},
persist: {
paths: ['collapsed', 'naiveThemeOverrides'],
paths: ['collapsed', 'layout', 'primaryColor', 'naiveThemeOverrides'],
storage: sessionStorage,
},
})

View File

@ -68,7 +68,7 @@ body {
background: #bfbfbf;
}
&::-webkit-scrollbar-thumb:hover {
background: var(--primary-color);
background: rgb(var(--primary-color));
}
}
}

View File

@ -48,26 +48,7 @@ export default defineConfig({
],
theme: {
colors: {
primary: 'var(--primary-color)',
primary_hover: 'var(--primary-color-hover)',
primary_pressed: 'var(--primary-color-pressed)',
primary_active: 'var(--primary-color-active)',
info: 'var(--info-color)',
info_hover: 'var(--info-color-hover)',
info_pressed: 'var(--info-color-pressed)',
info_active: 'var(--info-color-active)',
success: 'var(--success-color)',
success_hover: 'var(--success-color-hover)',
success_pressed: 'var(--success-color-pressed)',
success_active: 'var(--success-color-active)',
warning: 'var(--warning-color)',
warning_hover: 'var(--warning-color-hover)',
warning_pressed: 'var(--warning-color-pressed)',
warning_active: 'var(--warning-color-active)',
error: 'var(--error-color)',
error_hover: 'var(--error-color-hover)',
error_pressed: 'var(--error-color-pressed)',
error_active: 'var(--error-color-active)',
primary: 'rgba(var(--primary-color))',
dark: '#18181c',
light_border: '#efeff5',
dark_border: '#2d2d30',