refactor(projects): 嵌入naive-ui的css vars,替换windicss的extend color

This commit is contained in:
Soybean 2021-11-17 12:28:53 +08:00
parent 27f600c467
commit 2869b4cd33
13 changed files with 114 additions and 132 deletions

View File

@ -6,16 +6,18 @@
:theme="dark"
:theme-overrides="theme.themeOverrids"
>
<n-loading-bar-provider>
<n-dialog-provider>
<n-notification-provider>
<n-message-provider>
<slot></slot>
<app-provider-content />
</n-message-provider>
</n-notification-provider>
</n-dialog-provider>
</n-loading-bar-provider>
<n-element class="h-full">
<n-loading-bar-provider>
<n-dialog-provider>
<n-notification-provider>
<n-message-provider>
<slot></slot>
<app-provider-content />
</n-message-provider>
</n-notification-provider>
</n-dialog-provider>
</n-loading-bar-provider>
</n-element>
</n-config-provider>
</template>
@ -23,18 +25,18 @@
import { computed, watch } from 'vue';
import {
NConfigProvider,
darkTheme,
zhCN,
dateZhCN,
NElement,
NLoadingBarProvider,
NDialogProvider,
NNotificationProvider,
NMessageProvider
NMessageProvider,
darkTheme,
zhCN,
dateZhCN
} from 'naive-ui';
import { useDark } from '@vueuse/core';
import { AppProviderContent } from '@/components';
import { useThemeStore } from '@/store';
import { addColorAlpha } from '@/utils';
const osDark = useDark();
const theme = useThemeStore();
@ -43,13 +45,6 @@ const { handleDarkMode } = useThemeStore();
/** 系统暗黑模式 */
const dark = computed(() => (theme.darkMode ? darkTheme : undefined));
//
const primary = computed(() => theme.themeColor);
const primaryWithAlpha = computed(() => {
const alpha = theme.darkMode ? 0.15 : 0.1;
return addColorAlpha(primary.value, alpha);
});
//
watch(
osDark,
@ -61,18 +56,4 @@ watch(
}
);
</script>
<style>
/* 全局与主题颜色相关 */
.g_text-primary {
color: v-bind(primary);
}
.g_bg-primary {
background-color: v-bind(primary);
}
.g_bg-primary_active {
background-color: v-bind(primaryWithAlpha);
}
.g_border-primary {
border-color: v-bind(primary);
}
</style>
<style></style>

View File

@ -1,26 +1,17 @@
<template>
<hover-container class="px-12px" :show-tooltip="false">
<n-switch :value="theme.darkMode" size="large" @update:value="handleDarkMode">
<template #checked>
<icon-mdi-white-balance-sunny class="text-14px g_text-primary" />
</template>
<template #unchecked>
<icon-mdi-moon-waning-crescent class="text-14px g_text-primary" />
</template>
</n-switch>
<div class="hover:text-primary" @click="toggleDarkMode">
<icon-mdi-moon-waning-crescent v-if="theme.darkMode" class="text-14px" />
<icon-mdi-white-balance-sunny v-else class="text-14px" />
</div>
</hover-container>
</template>
<script lang="ts" setup>
import { NSwitch } from 'naive-ui';
import { HoverContainer } from '@/components';
import { useThemeStore } from '@/store';
const theme = useThemeStore();
const { handleDarkMode } = useThemeStore();
const { toggleDarkMode } = useThemeStore();
</script>
<style scoped>
:deep(.n-switch__rail) {
background-color: #000e1c !important;
}
</style>
<style scoped></style>

View File

@ -2,7 +2,7 @@
<div class="mb-6px px-4px cursor-pointer" @mouseenter="setTrue" @mouseleave="setFalse">
<div
class="flex-center flex-col py-12px rounded-2px"
:class="{ 'g_text-primary g_bg-primary_active': isActive, 'g_text-primary': isHover }"
:class="{ 'text-primary bg-primary-active': isActive, 'text-primary': isHover }"
>
<component :is="icon" :class="[isMini ? 'text-16px' : 'text-20px']" />
<p

View File

@ -15,7 +15,7 @@
:style="{ width: showDrawer ? theme.menuStyle.width + 'px' : '0px' }"
>
<header class="header-height flex-y-center justify-between">
<h2 class="g_text-primary pl-8px text-16px font-bold">{{ title }}</h2>
<h2 class="text-primary pl-8px text-16px font-bold">{{ title }}</h2>
<div class="px-8px text-16px text-gray-600 cursor-pointer" @click="toggleFixedMixMenu">
<icon-mdi:pin-off v-if="app.menu.fixedMix" />
<icon-mdi:pin v-else />

View File

@ -3,10 +3,10 @@
<div class="flex-center">
<n-switch :value="theme.darkMode" @update:value="handleDarkMode">
<template #checked>
<icon-mdi-white-balance-sunny class="text-14px g_text-primary" />
<icon-mdi-white-balance-sunny class="text-14px text-primary" />
</template>
<template #unchecked>
<icon-mdi-moon-waning-crescent class="text-14px g_text-primary" />
<icon-mdi-moon-waning-crescent class="text-14px text-primary" />
</template>
</n-switch>
</div>

View File

@ -1,7 +1,7 @@
<template>
<a href="/" class="logo-height nowrap-hidden flex-center cursor-pointer">
<system-logo class="w-32px h-32px" :color="primaryColor" />
<h2 v-show="showTitle" class="g_text-primary pl-8px text-16px font-bold">{{ title }}</h2>
<h2 v-show="showTitle" class="text-primary pl-8px text-16px font-bold">{{ title }}</h2>
</a>
</template>

View File

@ -1,8 +1,39 @@
import { brightenColor, darkenColor } from '@/utils';
import { brightenColor, darkenColor, addColorAlpha } from '@/utils';
export function getHoverAndPressedColor(color: string) {
return {
hover: brightenColor(color),
pressed: darkenColor(color)
};
type ColorType = 'primary' | 'info' | 'success' | 'warning' | 'error';
type ColorScene = '' | 'Suppl' | 'Hover' | 'Pressed' | 'Active';
type ColorKey = `${ColorType}Color${ColorScene}`;
type ThemeColor = {
[key in ColorKey]?: string;
};
interface ColorAction {
scene: ColorScene;
handler: (color: string) => string;
}
/** 获取主题颜色的各种场景对应的颜色 */
export function getThemeColors(colors: [ColorType, string][]) {
const colorActions: ColorAction[] = [
{ scene: '', handler: color => color },
{ scene: 'Suppl', handler: color => color },
{ scene: 'Hover', handler: color => brightenColor(color) },
{ scene: 'Pressed', handler: color => darkenColor(color) },
{ scene: 'Active', handler: color => addColorAlpha(color, 0.1) }
];
const themeColor: ThemeColor = {};
colors.forEach(color => {
colorActions.forEach(action => {
const [colorType, colorValue] = color;
const colorKey: ColorKey = `${colorType}Color${action.scene}`;
themeColor[colorKey] = action.handler(colorValue);
});
});
return themeColor;
}

View File

@ -3,17 +3,10 @@ import type { GlobalThemeOverrides } from 'naive-ui';
import { themeSettings, defaultThemeSettings } from '@/settings';
import { store } from '@/store';
import type { ThemeSettings, NavMode, MultiTabMode, AnimateType, HorizontalMenuPosition } from '@/interface';
import { addColorAlpha } from '@/utils';
import { getHoverAndPressedColor } from './helpers';
import { getThemeColors } from './helpers';
type ThemeState = ThemeSettings;
interface relativeThemeColor {
hover: string;
pressed: string;
shallow: string;
}
const themeStore = defineStore({
id: 'theme-store',
state: (): ThemeState => ({
@ -23,58 +16,29 @@ const themeStore = defineStore({
/** naive UI主题配置 */
themeOverrids(): GlobalThemeOverrides {
const {
themeColor: primaryColor,
otherColor: { info: infoColor, success: successColor, warning: warningColor, error: errorColor }
themeColor,
otherColor: { info, success, warning, error }
} = this;
const { hover: primaryColorHover, pressed: primaryColorPressed } = getHoverAndPressedColor(primaryColor);
const { hover: infoColorHover, pressed: infoColorPressed } = getHoverAndPressedColor(infoColor);
const { hover: successColorHover, pressed: successColorPressed } = getHoverAndPressedColor(successColor);
const { hover: warningColorHover, pressed: warningColorPressed } = getHoverAndPressedColor(warningColor);
const { hover: errorColorHover, pressed: errorColorPressed } = getHoverAndPressedColor(errorColor);
const themeColors = getThemeColors([
['primary', themeColor],
['info', info],
['success', success],
['warning', warning],
['error', error]
]);
const primaryColorSuppl = primaryColor;
const infoColorSuppl = infoColor;
const successColorSuppl = infoColor;
const warningColorSuppl = warningColor;
const errorColorSuppl = errorColor;
const colorLoading = primaryColor;
const colorLoading = themeColor;
return {
common: {
primaryColor,
primaryColorHover,
primaryColorPressed,
primaryColorSuppl,
infoColor,
infoColorHover,
infoColorPressed,
infoColorSuppl,
successColor,
successColorHover,
successColorPressed,
successColorSuppl,
warningColor,
warningColorHover,
warningColorPressed,
warningColorSuppl,
errorColor,
errorColorHover,
errorColorPressed,
errorColorSuppl
...themeColors
},
LoadingBar: {
colorLoading
}
};
},
relativeThemeColor(): relativeThemeColor {
const shallow = addColorAlpha(this.themeColor, 0.1);
return {
...getHoverAndPressedColor(this.themeColor),
shallow
};
},
isVerticalNav(): boolean {
const { mode } = this.navStyle;
return mode === 'vertical' || mode === 'vertical-mix';
@ -92,6 +56,10 @@ const themeStore = defineStore({
handleDarkMode(isDark: boolean) {
this.darkMode = isDark;
},
/** 切换暗黑模式 */
toggleDarkMode() {
this.darkMode = !this.darkMode;
},
/** 设置系统主题颜色 */
setThemeColor(color: string) {
this.themeColor = color;

View File

@ -8,10 +8,10 @@
<n-tag type="primary">{{ lastestBuildTime }}</n-tag>
</n-descriptions-item>
<n-descriptions-item label="Github地址">
<a class="g_text-primary" href="https://github.com/honghuangdc/soybean-admin" target="_blank">Github地址</a>
<a class="text-primary" href="https://github.com/honghuangdc/soybean-admin" target="_blank">Github地址</a>
</n-descriptions-item>
<n-descriptions-item label="预览地址">
<a class="g_text-primary" href="https://soybean.pro" target="_blank">预览地址</a>
<a class="text-primary" href="https://soybean.pro" target="_blank">预览地址</a>
</n-descriptions-item>
</n-descriptions>
</n-card>

View File

@ -4,7 +4,7 @@
<n-space :vertical="true" :size="16">
<n-card title="项目主要技术栈" :bordered="false" size="small" class="shadow-sm rounded-16px">
<template #header-extra>
<a class="g_text-primary" href="javascript:;">更多技术栈</a>
<a class="text-primary" href="javascript:;">更多技术栈</a>
</template>
<n-grid :item-responsive="true" responsive="screen" cols="m:2 l:3" :x-gap="8" :y-gap="8">
<n-grid-item v-for="item in technology" :key="item.id">
@ -14,7 +14,7 @@
</n-card>
<n-card title="动态" :bordered="false" size="small" class="shadow-sm rounded-16px">
<template #header-extra>
<a class="g_text-primary" href="javascript:;">更多动态</a>
<a class="text-primary" href="javascript:;">更多动态</a>
</template>
<n-list>
<n-list-item v-for="item in activity" :key="item.id">

View File

@ -10,7 +10,7 @@
<n-space :vertical="true" size="large">
<div class="flex-y-center justify-between">
<n-checkbox v-model:checked="rememberMe">记住我</n-checkbox>
<span class="g_text-primary cursor-pointer" @click="toCurrentLogin('reset-pwd')">忘记密码</span>
<span class="text-primary cursor-pointer" @click="toCurrentLogin('reset-pwd')">忘记密码</span>
</div>
<n-button type="primary" size="large" :block="true" :round="true" :loading="loading" @click="handleSubmit">
确定

View File

@ -10,7 +10,7 @@
</header>
<main class="pt-24px">
<div v-for="item in modules" v-show="module === item.key" :key="item.key">
<h3 class="text-18px g_text-primary font-medium">{{ item.label }}</h3>
<h3 class="text-18px text-primary font-medium">{{ item.label }}</h3>
<component :is="item.component" />
</div>
</main>

View File

@ -1,9 +1,4 @@
import { defineConfig } from 'windicss/helpers';
import themeSettings from './src/settings/theme.json';
const {
otherColor: { info, success, warning, error }
} = themeSettings;
export default defineConfig({
extract: {
@ -15,31 +10,47 @@ export default defineConfig({
'wh-full': 'w-full h-full',
'center-layout': 'w-1280px mx-auto px-15px',
'flex-center': 'flex justify-center items-center',
'flex-col-center': 'flex flex-col justify-center items-center',
'flex-col-center': 'flex-center flex-col',
'flex-x-center': 'flex justify-center',
'flex-y-center': 'flex items-center',
'inline-flex-center': 'inline-flex justify-center items-center',
'inline-flex-x-center': 'inline-flex justify-center',
'inline-flex-y-center': 'inline-flex items-center',
'flex-1-hidden': 'flex-1 overflow-hidden',
'flex-col-stretch': 'flex flex-col items-stretch',
'inline-flex-col-stretch': 'flex flex-col items-stretch',
'absolute-center': 'absolute left-0 top-0 flex justify-center items-center wh-full',
'flex-1-hidden': 'flex-1 overflow-hidden',
'absolute-center': 'absolute left-0 top-0 flex-center wh-full',
'absolute-lt': 'absolute left-0 top-0',
'absolute-lb': 'absolute left-0 bottom-0',
'absolute-rt': 'absolute right-0 top-0',
'absolute-rb': 'absolute right-0 bottom-0',
'fixed-center': 'fixed left-0 top-0 flex justify-center items-center wh-full',
'ellipsis-text': 'whitespace-nowrap overflow-hidden overflow-ellipsis',
'nowrap-hidden': 'whitespace-nowrap overflow-hidden'
'fixed-center': 'fixed left-0 top-0 flex-center wh-full',
'nowrap-hidden': 'whitespace-nowrap overflow-hidden',
'ellipsis-text': 'nowrap-hidden overflow-ellipsis'
},
theme: {
extend: {
colors: {
info,
success,
warning,
error,
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)',
light: '#ffffff',
dark: '#18181c'
},