Commit 5b8eb4a49a097a47caf491c44df427522ab58daa

Authored by Vben
1 parent f05cc6d3

feat: dark mode

Showing 100 changed files with 720 additions and 803 deletions

Too many changes to show.

To preserve performance only 100 of 109 files are displayed.

CHANGELOG.zh_CN.md
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 - 移除 useFullScreen 函数 11 - 移除 useFullScreen 函数
12 - tinymce 由 Cdn 改为 npm(打包体积偏大) 12 - tinymce 由 Cdn 改为 npm(打包体积偏大)
13 - Dashboard 重构 13 - Dashboard 重构
  14 +- 移除 ApexCharts 及示例
14 15
15 ### 🐛 Bug Fixes 16 ### 🐛 Bug Fixes
16 17
build/config/themeConfig.ts
@@ -2,11 +2,7 @@ import { generate } from '@ant-design/colors'; @@ -2,11 +2,7 @@ import { generate } from '@ant-design/colors';
2 2
3 export const primaryColor = '#0960bd'; 3 export const primaryColor = '#0960bd';
4 4
5 -export const borderColorBase = '#d9d9d9';  
6 -  
7 -export const themeMode = 'light';  
8 -  
9 -export type ThemeMode = 'dark' | 'light'; 5 +export const darkMode = 'light';
10 6
11 type Fn = (...arg: any) => any; 7 type Fn = (...arg: any) => any;
12 8
@@ -17,18 +13,17 @@ export interface GenerateColorsParams { @@ -17,18 +13,17 @@ export interface GenerateColorsParams {
17 color?: string; 13 color?: string;
18 } 14 }
19 15
20 -export function generateAntColors(color: string, mode: ThemeMode) { 16 +export function generateAntColors(color: string) {
21 return generate(color, { 17 return generate(color, {
22 - theme: mode == 'dark' ? 'dark' : 'default', 18 + theme: 'default',
23 }); 19 });
24 } 20 }
25 21
26 -export function getThemeColors(color?: string, theme?: ThemeMode) { 22 +export function getThemeColors(color?: string) {
27 const tc = color || primaryColor; 23 const tc = color || primaryColor;
28 - const tm = theme || themeMode;  
29 - const colors = generateAntColors(tc, tm); 24 + const colors = generateAntColors(tc);
30 const primary = colors[5]; 25 const primary = colors[5];
31 - const modeColors = generateAntColors(primary, tm === 'dark' ? 'light' : 'dark'); 26 + const modeColors = generateAntColors(primary);
32 27
33 return [...colors, ...modeColors]; 28 return [...colors, ...modeColors];
34 } 29 }
@@ -71,36 +66,3 @@ export function generateColors({ @@ -71,36 +66,3 @@ export function generateColors({
71 .filter((item) => item !== '#000000'); 66 .filter((item) => item !== '#000000');
72 return [...lightens, ...darkens, ...alphaColors, ...tinycolorDarkens, ...tinycolorLightens]; 67 return [...lightens, ...darkens, ...alphaColors, ...tinycolorDarkens, ...tinycolorLightens];
73 } 68 }
74 -  
75 -/**  
76 - * less global variable  
77 - */  
78 -export function generateModifyVars() {  
79 - const palettes = generateAntColors(primaryColor, themeMode);  
80 - const primary = palettes[5];  
81 -  
82 - const primaryColorObj: Record<string, string> = {};  
83 -  
84 - for (let index = 0; index < 10; index++) {  
85 - primaryColorObj[`primary-${index + 1}`] = palettes[index];  
86 - }  
87 -  
88 - return {  
89 - 'primary-color': primary,  
90 - ...primaryColorObj,  
91 - 'info-color': primary,  
92 - 'processing-color': primary,  
93 - 'success-color': '#55D187', // Success color  
94 - 'error-color': '#ED6F6F', // False color  
95 - 'warning-color': '#EFBD47', // Warning color  
96 - 'disabled-color': 'rgba(0, 0, 0, 0.25)', // Failure color  
97 - 'heading-color': 'rgba(0, 0, 0, 0.85)', // Title color  
98 - 'text-color': 'rgba(0, 0, 0, 0.85)', // Main text color  
99 - 'text-color-secondary': 'rgba(0, 0, 0, 0.45)', // Subtext color  
100 - 'font-size-base': '14px', // Main font size  
101 - 'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // Floating shadow  
102 - 'border-color-base': borderColorBase, // Border color,  
103 - 'border-radius-base': '2px', // Component/float fillet  
104 - 'link-color': primary, // Link color  
105 - };  
106 -}  
build/generate/generateModifyVars.ts 0 → 100644
  1 +import { generateAntColors, primaryColor } from '../config/themeConfig';
  2 +import { getThemeVariables } from 'ant-design-vue/dist/theme';
  3 +import { resolve } from 'path';
  4 +
  5 +/**
  6 + * less global variable
  7 + */
  8 +export function generateModifyVars(dark = false) {
  9 + const palettes = generateAntColors(primaryColor);
  10 + const primary = palettes[5];
  11 +
  12 + const primaryColorObj: Record<string, string> = {};
  13 +
  14 + for (let index = 0; index < 10; index++) {
  15 + primaryColorObj[`primary-${index + 1}`] = palettes[index];
  16 + }
  17 +
  18 + const modifyVars = getThemeVariables({ dark });
  19 + return {
  20 + ...modifyVars,
  21 + // Used for global import to avoid the need to import each style file separately
  22 + // reference: Avoid repeated references
  23 + hack: `${modifyVars.hack} @import (reference) "${resolve('src/design/config.less')}";`,
  24 + 'primary-color': primary,
  25 + ...primaryColorObj,
  26 + 'info-color': primary,
  27 + 'processing-color': primary,
  28 + 'success-color': '#55D187', // Success color
  29 + 'error-color': '#ED6F6F', // False color
  30 + 'warning-color': '#EFBD47', // Warning color
  31 + 'font-size-base': '14px', // Main font size
  32 + 'border-radius-base': '2px', // Component/float fillet
  33 + 'link-color': primary, // Link color
  34 + };
  35 +}
build/vite/plugin/index.ts
@@ -62,7 +62,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { @@ -62,7 +62,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
62 vitePlugins.push(configVisualizerConfig()); 62 vitePlugins.push(configVisualizerConfig());
63 63
64 //vite-plugin-theme 64 //vite-plugin-theme
65 - vitePlugins.push(configThemePlugin()); 65 + vitePlugins.push(configThemePlugin(isBuild));
66 66
67 // The following plugins only work in the production environment 67 // The following plugins only work in the production environment
68 if (isBuild) { 68 if (isBuild) {
build/vite/plugin/theme.ts
@@ -2,18 +2,50 @@ @@ -2,18 +2,50 @@
2 * Vite plugin for website theme color switching 2 * Vite plugin for website theme color switching
3 * https://github.com/anncwb/vite-plugin-theme 3 * https://github.com/anncwb/vite-plugin-theme
4 */ 4 */
5 -import { viteThemePlugin, mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme'; 5 +import type { Plugin } from 'vite';
  6 +import {
  7 + viteThemePlugin,
  8 + antdDarkThemePlugin,
  9 + mixLighten,
  10 + mixDarken,
  11 + tinycolor,
  12 +} from 'vite-plugin-theme';
6 import { getThemeColors, generateColors } from '../../config/themeConfig'; 13 import { getThemeColors, generateColors } from '../../config/themeConfig';
  14 +import { generateModifyVars } from '../../generate/generateModifyVars';
7 15
8 -export function configThemePlugin() { 16 +export function configThemePlugin(isBuild: boolean): Plugin[] {
9 const colors = generateColors({ 17 const colors = generateColors({
10 mixDarken, 18 mixDarken,
11 mixLighten, 19 mixLighten,
12 tinycolor, 20 tinycolor,
13 }); 21 });
14 22
15 - const plugin = viteThemePlugin({  
16 - colorVariables: [...getThemeColors(), ...colors],  
17 - });  
18 - return plugin; 23 + const plugin = [
  24 + viteThemePlugin({
  25 + resolveSelector: (s) => `[data-theme] ${s}`,
  26 + colorVariables: [...getThemeColors(), ...colors],
  27 + }),
  28 + antdDarkThemePlugin({
  29 + filter: (id) => {
  30 + if (isBuild) {
  31 + return !id.endsWith('antd.less');
  32 + }
  33 + return true;
  34 + },
  35 + // extractCss: false,
  36 + darkModifyVars: {
  37 + ...generateModifyVars(true),
  38 + 'text-color': '#c9d1d9',
  39 + 'text-color-base': '#c9d1d9',
  40 + 'component-background': '#151515',
  41 + // black: '#0e1117',
  42 + // #8b949e
  43 + 'text-color-secondary': '#8b949e',
  44 + 'border-color-base': '#30363d',
  45 + 'item-active-bg': '#111b26',
  46 + },
  47 + }),
  48 + ];
  49 +
  50 + return (plugin as unknown) as Plugin[];
19 } 51 }
index.html
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 -<html lang="en"> 2 +<html lang="en" id="htmlRoot">
3 <head> 3 <head>
4 <meta charset="UTF-8" /> 4 <meta charset="UTF-8" />
5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
@@ -13,8 +13,24 @@ @@ -13,8 +13,24 @@
13 <link rel="icon" href="/favicon.ico" /> 13 <link rel="icon" href="/favicon.ico" />
14 </head> 14 </head>
15 <body> 15 <body>
  16 + <script>
  17 + (() => {
  18 + var htmlRoot = document.getElementById('htmlRoot');
  19 + const theme = window.localStorage.getItem('__APP__DARK__MODE__');
  20 + if (!htmlRoot || !theme) return;
  21 + htmlRoot.setAttribute('data-theme', theme);
  22 + })();
  23 + </script>
16 <div id="app"> 24 <div id="app">
17 <style> 25 <style>
  26 + html[data-theme='dark'] .app-loading {
  27 + background: #2c344a;
  28 + }
  29 +
  30 + html[data-theme='dark'] .app-loading .app-loading-title {
  31 + color: rgba(255, 255, 255, 0.85);
  32 + }
  33 +
18 .app-loading { 34 .app-loading {
19 display: flex; 35 display: flex;
20 width: 100%; 36 width: 100%;
package.json
@@ -35,7 +35,6 @@ @@ -35,7 +35,6 @@
35 "@vueuse/core": "^4.7.0", 35 "@vueuse/core": "^4.7.0",
36 "@zxcvbn-ts/core": "^0.3.0", 36 "@zxcvbn-ts/core": "^0.3.0",
37 "ant-design-vue": "^2.1.2", 37 "ant-design-vue": "^2.1.2",
38 - "apexcharts": "^3.26.0",  
39 "axios": "^0.21.1", 38 "axios": "^0.21.1",
40 "cropperjs": "^1.5.11", 39 "cropperjs": "^1.5.11",
41 "crypto-js": "^4.0.0", 40 "crypto-js": "^4.0.0",
@@ -51,7 +50,7 @@ @@ -51,7 +50,7 @@
51 "vditor": "^3.8.4", 50 "vditor": "^3.8.4",
52 "vue": "3.0.11", 51 "vue": "3.0.11",
53 "vue-i18n": "^9.0.0", 52 "vue-i18n": "^9.0.0",
54 - "vue-router": "^4.0.5", 53 + "vue-router": "^4.0.6",
55 "vue-types": "^3.0.2", 54 "vue-types": "^3.0.2",
56 "vuex": "^4.0.0", 55 "vuex": "^4.0.0",
57 "vuex-module-decorators": "^1.0.1", 56 "vuex-module-decorators": "^1.0.1",
@@ -110,12 +109,12 @@ @@ -110,12 +109,12 @@
110 "vite-plugin-compression": "^0.2.4", 109 "vite-plugin-compression": "^0.2.4",
111 "vite-plugin-html": "^2.0.6", 110 "vite-plugin-html": "^2.0.6",
112 "vite-plugin-imagemin": "^0.3.0", 111 "vite-plugin-imagemin": "^0.3.0",
113 - "vite-plugin-mock": "^2.4.2", 112 + "vite-plugin-mock": "^2.5.0",
114 "vite-plugin-purge-icons": "^0.7.0", 113 "vite-plugin-purge-icons": "^0.7.0",
115 "vite-plugin-pwa": "^0.6.5", 114 "vite-plugin-pwa": "^0.6.5",
116 "vite-plugin-style-import": "^0.9.2", 115 "vite-plugin-style-import": "^0.9.2",
117 "vite-plugin-svg-icons": "^0.4.1", 116 "vite-plugin-svg-icons": "^0.4.1",
118 - "vite-plugin-theme": "^0.5.0", 117 + "vite-plugin-theme": "^0.6.0",
119 "vite-plugin-windicss": "0.12.5", 118 "vite-plugin-windicss": "0.12.5",
120 "vue-eslint-parser": "^7.6.0" 119 "vue-eslint-parser": "^7.6.0"
121 }, 120 },
src/assets/icons/moon.svg 0 → 100644
  1 +<?xml version="1.0" encoding="iso-8859-1"?>
  2 +<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
  3 + viewBox="0 0 499.712 499.712" style="enable-background: new 0 0 499.712 499.712;" xml:space="preserve">
  4 +<path style="fill: #FFD93B;" d="M146.88,375.528c126.272,0,228.624-102.368,228.624-228.64c0-55.952-20.16-107.136-53.52-146.88
  5 + C425.056,33.096,499.696,129.64,499.696,243.704c0,141.392-114.608,256-256,256c-114.064,0-210.608-74.64-243.696-177.712
  6 + C39.744,355.368,90.944,375.528,146.88,375.528z"/>
  7 +<path style="fill: #F4C534;" d="M401.92,42.776c34.24,43.504,54.816,98.272,54.816,157.952c0,141.392-114.608,256-256,256
  8 + c-59.68,0-114.448-20.576-157.952-54.816c46.848,59.472,119.344,97.792,200.928,97.792c141.392,0,256-114.608,256-256
  9 + C499.712,162.12,461.392,89.64,401.92,42.776z"/>
  10 +<g>
  11 + <polygon style="fill: #FFD83B;" points="128.128,99.944 154.496,153.4 213.472,161.96 170.8,203.56 180.864,262.296
  12 + 128.128,234.568 75.376,262.296 85.44,203.56 42.768,161.96 101.744,153.4"/>
  13 + <polygon style="fill: #FFD83B;" points="276.864,82.84 290.528,110.552 321.104,114.984 298.976,136.552 304.208,166.984
  14 + 276.864,152.616 249.52,166.984 254.752,136.552 232.624,114.984 263.2,110.552"/>
  15 +</g>
  16 +</svg>
src/assets/icons/sun.svg 0 → 100644
  1 +<?xml version="1.0" encoding="iso-8859-1"?>
  2 +<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
  3 + viewBox="0 0 60 60" style="enable-background: new 0 0 60 60;" xml:space="preserve">
  4 +<g>
  5 + <path style="fill: #F0C419;" d="M30,0c-0.552,0-1,0.448-1,1v6c0,0.552,0.448,1,1,1s1-0.448,1-1V1C31,0.448,30.552,0,30,0z"/>
  6 + <path style="fill: #F0C419;" d="M30,52c-0.552,0-1,0.448-1,1v6c0,0.552,0.448,1,1,1s1-0.448,1-1v-6C31,52.448,30.552,52,30,52z"/>
  7 + <path style="fill: #F0C419;" d="M59,29h-6c-0.552,0-1,0.448-1,1s0.448,1,1,1h6c0.552,0,1-0.448,1-1S59.552,29,59,29z"/>
  8 + <path style="fill: #F0C419;" d="M8,30c0-0.552-0.448-1-1-1H1c-0.552,0-1,0.448-1,1s0.448,1,1,1h6C7.552,31,8,30.552,8,30z"/>
  9 + <path style="fill: #F0C419;" d="M46.264,14.736c0.256,0,0.512-0.098,0.707-0.293l5.736-5.736c0.391-0.391,0.391-1.023,0-1.414
  10 + s-1.023-0.391-1.414,0l-5.736,5.736c-0.391,0.391-0.391,1.023,0,1.414C45.752,14.639,46.008,14.736,46.264,14.736z"/>
  11 + <path style="fill: #F0C419;" d="M13.029,45.557l-5.736,5.736c-0.391,0.391-0.391,1.023,0,1.414C7.488,52.902,7.744,53,8,53
  12 + s0.512-0.098,0.707-0.293l5.736-5.736c0.391-0.391,0.391-1.023,0-1.414S13.42,45.166,13.029,45.557z"/>
  13 + <path style="fill: #F0C419;" d="M46.971,45.557c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414l5.736,5.736
  14 + C51.488,52.902,51.744,53,52,53s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L46.971,45.557z"/>
  15 + <path style="fill: #F0C419;" d="M8.707,7.293c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414l5.736,5.736
  16 + c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L8.707,7.293z"/>
  17 + <path style="fill: #F0C419;" d="M50.251,21.404c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08l2.762-1.172
  18 + c0.508-0.216,0.746-0.803,0.53-1.311s-0.804-0.746-1.311-0.53l-2.762,1.172C50.272,20.309,50.035,20.896,50.251,21.404z"/>
  19 + <path style="fill: #F0C419;" d="M9.749,38.596c-0.216-0.508-0.803-0.746-1.311-0.53l-2.762,1.172
  20 + c-0.508,0.216-0.746,0.803-0.53,1.311c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08l2.762-1.172
  21 + C9.728,39.691,9.965,39.104,9.749,38.596z"/>
  22 + <path style="fill: #F0C419;" d="M54.481,38.813L51.7,37.688c-0.511-0.207-1.095,0.041-1.302,0.553
  23 + c-0.207,0.512,0.041,1.095,0.553,1.302l2.782,1.124c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626
  24 + C55.241,39.603,54.994,39.02,54.481,38.813z"/>
  25 + <path style="fill: #F0C419;" d="M5.519,21.188L8.3,22.312c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626
  26 + c0.207-0.512-0.041-1.095-0.553-1.302l-2.782-1.124c-0.513-0.207-1.095,0.04-1.302,0.553C4.759,20.397,5.006,20.98,5.519,21.188z"
  27 + />
  28 + <path style="fill: #F0C419;" d="M39.907,50.781c-0.216-0.508-0.803-0.745-1.311-0.53c-0.508,0.216-0.746,0.803-0.53,1.311
  29 + l1.172,2.762c0.162,0.381,0.532,0.61,0.921,0.61c0.13,0,0.263-0.026,0.39-0.08c0.508-0.216,0.746-0.803,0.53-1.311L39.907,50.781z"
  30 + />
  31 + <path style="fill: #F0C419;" d="M21.014,9.829c0.13,0,0.263-0.026,0.39-0.08c0.508-0.216,0.746-0.803,0.53-1.311l-1.172-2.762
  32 + c-0.215-0.509-0.802-0.747-1.311-0.53c-0.508,0.216-0.746,0.803-0.53,1.311l1.172,2.762C20.254,9.6,20.625,9.829,21.014,9.829z"/>
  33 + <path style="fill: #F0C419;" d="M21.759,50.398c-0.511-0.205-1.095,0.04-1.302,0.553l-1.124,2.782
  34 + c-0.207,0.512,0.041,1.095,0.553,1.302c0.123,0.049,0.25,0.073,0.374,0.073c0.396,0,0.771-0.236,0.928-0.626l1.124-2.782
  35 + C22.519,51.188,22.271,50.605,21.759,50.398z"/>
  36 + <path style="fill: #F0C419;" d="M38.615,9.675c0.396,0,0.771-0.236,0.928-0.626l1.124-2.782c0.207-0.512-0.041-1.095-0.553-1.302
  37 + c-0.511-0.207-1.095,0.041-1.302,0.553L37.688,8.3c-0.207,0.512,0.041,1.095,0.553,1.302C38.364,9.651,38.491,9.675,38.615,9.675z"
  38 + />
  39 +</g>
  40 +<circle style="fill: #F0C419;" cx="30" cy="30" r="20"/>
  41 +<circle style="fill: #EDE21B;" cx="30" cy="30" r="15"/>
  42 +</svg>
src/assets/svg/login-bg-dark.svg 0 → 100644
  1 +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="6395" height="1080" viewBox="0 0 6395 1080">
  2 + <defs>
  3 + <clipPath id="clip-path">
  4 + <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
  5 + </clipPath>
  6 + <linearGradient id="linear-gradient" x1="0.631" y1="0.5" x2="0.958" y2="0.488" gradientUnits="objectBoundingBox">
  7 + <stop offset="0" stop-color="#2e364a"/>
  8 + <stop offset="1" stop-color="#2c344a"/>
  9 + </linearGradient>
  10 + </defs>
  11 + <g id="Web_1920_1" data-name="Web 1920 – 1" clip-path="url(#clip-Web_1920_1)">
  12 + <g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)">
  13 + <g id="Group_118" data-name="Group 118" transform="translate(-419.333 -1.126)">
  14 + <path id="Path_142" data-name="Path 142" d="M6271.734-6.176s-222.478,187.809-55.349,583.254c44.957,106.375,81.514,205.964,84.521,277,8.164,192.764-156.046,268.564-156.046,268.564l-653.53-26.8L5475.065-21.625Z" transform="translate(-4876.383)" fill="#2d3750"/>
  15 + <path id="Union_6" data-name="Union 6" d="M-2631.1,1081.8v-1.6H-8230.9V.022h5599.8V0h759.7s-187.845,197.448-91.626,488.844c49.167,148.9,96.309,256.289,104.683,362.118,7.979,100.852-57.98,201.711-168.644,254.286-65.858,31.29-144.552,42.382-223.028,42.383C-2441.2,1147.632-2631.1,1081.8-2631.1,1081.8Z" transform="translate(3259.524 0.803)" fill="url(#linear-gradient)"/>
  16 + </g>
  17 + </g>
  18 + </g>
  19 +</svg>
src/assets/svg/login-bg.svg
@@ -4,8 +4,8 @@ @@ -4,8 +4,8 @@
4 <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/> 4 <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
5 </clipPath> 5 </clipPath>
6 <linearGradient id="linear-gradient" x1="0.747" y1="0.222" x2="0.973" y2="0.807" gradientUnits="objectBoundingBox"> 6 <linearGradient id="linear-gradient" x1="0.747" y1="0.222" x2="0.973" y2="0.807" gradientUnits="objectBoundingBox">
7 - <stop offset="0" stop-color="#2b51b4"/>  
8 - <stop offset="1" stop-color="#1c3faa"/> 7 + <stop offset="0" stop-color="#2c41b4"/>
  8 + <stop offset="1" stop-color="#1b4fab"/>
9 </linearGradient> 9 </linearGradient>
10 </defs> 10 </defs>
11 <g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)"> 11 <g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)">
src/components/Application/index.ts
@@ -2,6 +2,7 @@ import AppLogo from &#39;./src/AppLogo.vue&#39;; @@ -2,6 +2,7 @@ import AppLogo from &#39;./src/AppLogo.vue&#39;;
2 import AppProvider from './src/AppProvider.vue'; 2 import AppProvider from './src/AppProvider.vue';
3 import AppSearch from './src/search/AppSearch.vue'; 3 import AppSearch from './src/search/AppSearch.vue';
4 import AppLocalePicker from './src/AppLocalePicker.vue'; 4 import AppLocalePicker from './src/AppLocalePicker.vue';
  5 +import AppDarkModeToggle from './src/AppDarkModeToggle.vue';
5 6
6 export { useAppProviderContext } from './src/useAppContext'; 7 export { useAppProviderContext } from './src/useAppContext';
7 -export { AppLogo, AppProvider, AppSearch, AppLocalePicker }; 8 +export { AppLogo, AppProvider, AppSearch, AppLocalePicker, AppDarkModeToggle };
src/components/Application/src/AppDarkModeToggle.vue 0 → 100644
  1 +<template>
  2 + <div
  3 + v-if="getShowDarkModeToggle"
  4 + :class="[
  5 + prefixCls,
  6 + `${prefixCls}--${size}`,
  7 + {
  8 + [`${prefixCls}--dark`]: isDark,
  9 + },
  10 + ]"
  11 + @click="toggleDarkMode"
  12 + >
  13 + <div :class="`${prefixCls}-inner`"> </div>
  14 + <SvgIcon size="14" name="sun" />
  15 + <SvgIcon size="14" name="moon" />
  16 + </div>
  17 +</template>
  18 +<script lang="ts">
  19 + import { defineComponent, computed } from 'vue';
  20 +
  21 + import { useDesign } from '/@/hooks/web/useDesign';
  22 +
  23 + import { SvgIcon } from '/@/components/Icon';
  24 + import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  25 + import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
  26 + import { updateDarkTheme } from '/@/logics/theme/dark';
  27 +
  28 + import { ThemeEnum } from '/@/enums/appEnum';
  29 +
  30 + export default defineComponent({
  31 + name: 'DarkModeToggle',
  32 + components: { SvgIcon },
  33 + props: {
  34 + size: {
  35 + type: String,
  36 + default: 'default',
  37 + validate: (val) => ['default', 'large'].includes(val),
  38 + },
  39 + },
  40 + setup() {
  41 + const { prefixCls } = useDesign('dark-mode-toggle');
  42 + const { getDarkMode, setDarkMode, getShowDarkModeToggle } = useRootSetting();
  43 + const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK);
  44 + function toggleDarkMode() {
  45 + const darkMode = getDarkMode.value === ThemeEnum.DARK ? ThemeEnum.LIGHT : ThemeEnum.DARK;
  46 + setDarkMode(darkMode);
  47 + updateDarkTheme(darkMode);
  48 + updateHeaderBgColor();
  49 + updateSidebarBgColor();
  50 + }
  51 +
  52 + return {
  53 + isDark,
  54 + prefixCls,
  55 + toggleDarkMode,
  56 + getShowDarkModeToggle,
  57 + };
  58 + },
  59 + });
  60 +</script>
  61 +<style lang="less" scoped>
  62 + @prefix-cls: ~'@{namespace}-dark-mode-toggle';
  63 +
  64 + html[data-theme='dark'] {
  65 + .@{prefix-cls} {
  66 + border: 1px solid rgb(196, 188, 188);
  67 + }
  68 + }
  69 +
  70 + .@{prefix-cls} {
  71 + position: relative;
  72 + display: flex;
  73 + width: 50px;
  74 + height: 26px;
  75 + padding: 0 6px;
  76 + margin-left: auto;
  77 + cursor: pointer;
  78 + background-color: #151515;
  79 + border-radius: 30px;
  80 + justify-content: space-between;
  81 + align-items: center;
  82 +
  83 + &-inner {
  84 + position: absolute;
  85 + z-index: 1;
  86 + width: 18px;
  87 + height: 18px;
  88 + background-color: #fff;
  89 + border-radius: 50%;
  90 + transition: transform 0.5s, background-color 0.5s;
  91 + will-change: transform;
  92 + }
  93 +
  94 + &--dark {
  95 + .@{prefix-cls}-inner {
  96 + transform: translateX(calc(100% + 2px));
  97 + }
  98 + }
  99 +
  100 + &--large {
  101 + width: 72px;
  102 + height: 34px;
  103 + padding: 0 10px;
  104 +
  105 + .@{prefix-cls}-inner {
  106 + width: 26px;
  107 + height: 26px;
  108 + }
  109 + }
  110 + }
  111 +</style>
src/components/Application/src/search/AppSearchFooter.vue
@@ -42,9 +42,9 @@ @@ -42,9 +42,9 @@
42 padding: 0 16px; 42 padding: 0 16px;
43 font-size: 12px; 43 font-size: 12px;
44 color: #666; 44 color: #666;
45 - background: rgb(255 255 255); 45 + background: @component-background;
  46 + border-top: 1px solid @border-color-base;
46 border-radius: 0 0 16px 16px; 47 border-radius: 0 0 16px 16px;
47 - box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgba(69, 98, 155, 0.12);  
48 align-items: center; 48 align-items: center;
49 flex-shrink: 0; 49 flex-shrink: 0;
50 50
src/components/Application/src/search/AppSearchModal.vue
@@ -190,12 +190,10 @@ @@ -190,12 +190,10 @@
190 &-content { 190 &-content {
191 position: relative; 191 position: relative;
192 width: 632px; 192 width: 632px;
193 - // padding: 14px;  
194 margin: 0 auto auto auto; 193 margin: 0 auto auto auto;
195 - background: #f5f6f7; 194 + background: @component-background;
196 border-radius: 16px; 195 border-radius: 16px;
197 box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); 196 box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
198 - // box-shadow: inset 1px 1px 0 0 hsla(0, 0%, 100%, 0.5), 0 3px 8px 0 #555a64;  
199 flex-direction: column; 197 flex-direction: column;
200 } 198 }
201 199
@@ -253,8 +251,7 @@ @@ -253,8 +251,7 @@
253 font-size: 14px; 251 font-size: 14px;
254 color: @text-color-base; 252 color: @text-color-base;
255 cursor: pointer; 253 cursor: pointer;
256 - // background: @primary-color;  
257 - background: #fff; 254 + background: @component-background;
258 border-radius: 4px; 255 border-radius: 4px;
259 box-shadow: 0 1px 3px 0 #d4d9e1; 256 box-shadow: 0 1px 3px 0 #d4d9e1;
260 align-items: center; 257 align-items: center;
src/components/Container/src/collapse/CollapseContainer.vue
@@ -101,7 +101,7 @@ @@ -101,7 +101,7 @@
101 @prefix-cls: ~'@{namespace}-collapse-container'; 101 @prefix-cls: ~'@{namespace}-collapse-container';
102 102
103 .@{prefix-cls} { 103 .@{prefix-cls} {
104 - background: #fff; 104 + background: @component-background;
105 border-radius: 2px; 105 border-radius: 2px;
106 transition: all 0.3s ease-in-out; 106 transition: all 0.3s ease-in-out;
107 107
src/components/ContextMenu/src/index.less
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 22
23 &:not(.ant-menu-item-disabled):hover { 23 &:not(.ant-menu-item-disabled):hover {
24 color: @text-color-base; 24 color: @text-color-base;
25 - background: #eee; 25 + background: @item-hover-bg;
26 } 26 }
27 } 27 }
28 } 28 }
@@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
36 width: 156px; 36 width: 156px;
37 margin: 0; 37 margin: 0;
38 list-style: none; 38 list-style: none;
39 - background-color: #fff; 39 + background-color: @component-background;
40 border: 1px solid rgba(0, 0, 0, 0.08); 40 border: 1px solid rgba(0, 0, 0, 0.08);
41 border-radius: 0.25rem; 41 border-radius: 0.25rem;
42 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1), 42 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),
src/components/Drawer/src/BasicDrawer.vue
@@ -221,7 +221,7 @@ @@ -221,7 +221,7 @@
221 .ant-drawer-body { 221 .ant-drawer-body {
222 height: calc(100% - @header-height); 222 height: calc(100% - @header-height);
223 padding: 0; 223 padding: 0;
224 - background-color: #fff; 224 + background-color: @component-background;
225 225
226 .scrollbar__wrap { 226 .scrollbar__wrap {
227 padding: 16px !important; 227 padding: 16px !important;
src/components/Drawer/src/components/DrawerFooter.vue
@@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
74 width: 100%; 74 width: 100%;
75 padding: 0 12px 0 20px; 75 padding: 0 12px 0 20px;
76 text-align: right; 76 text-align: right;
77 - background: #fff; 77 + background: @component-background;
78 border-top: 1px solid @border-color-base; 78 border-top: 1px solid @border-color-base;
79 79
80 > * { 80 > * {
src/components/Form/src/components/FormItem.vue
@@ -258,7 +258,7 @@ @@ -258,7 +258,7 @@
258 const { label, helpMessage, helpComponentProps, subLabel } = props.schema; 258 const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
259 const renderLabel = subLabel ? ( 259 const renderLabel = subLabel ? (
260 <span> 260 <span>
261 - {label} <span style="color:#00000073">{subLabel}</span> 261 + {label} <span class="text-secondary">{subLabel}</span>
262 </span> 262 </span>
263 ) : ( 263 ) : (
264 label 264 label
src/components/Loading/src/index.vue
1 <template> 1 <template>
2 - <section class="full-loading" :class="{ absolute }" v-show="loading" :style="getStyle"> 2 + <section class="full-loading" :class="{ absolute }" v-show="loading">
3 <Spin v-bind="$attrs" :tip="tip" :size="size" :spinning="loading" /> 3 <Spin v-bind="$attrs" :tip="tip" :size="size" :spinning="loading" />
4 </section> 4 </section>
5 </template> 5 </template>
6 <script lang="ts"> 6 <script lang="ts">
7 - import { computed, CSSProperties, PropType } from 'vue'; 7 + import { PropType } from 'vue';
8 8
9 import { defineComponent } from 'vue'; 9 import { defineComponent } from 'vue';
10 import { Spin } from 'ant-design-vue'; 10 import { Spin } from 'ant-design-vue';
11 11
12 import { SizeEnum } from '/@/enums/sizeEnum'; 12 import { SizeEnum } from '/@/enums/sizeEnum';
13 - import { ThemeEnum } from '/@/enums/appEnum';  
14 13
15 export default defineComponent({ 14 export default defineComponent({
16 name: 'Loading', 15 name: 'Loading',
@@ -38,25 +37,6 @@ @@ -38,25 +37,6 @@
38 background: { 37 background: {
39 type: String as PropType<string>, 38 type: String as PropType<string>,
40 }, 39 },
41 - theme: {  
42 - type: String as PropType<'dark' | 'light'>,  
43 - default: 'light',  
44 - },  
45 - },  
46 - setup(props) {  
47 - const getStyle = computed(  
48 - (): CSSProperties => {  
49 - const { background, theme } = props;  
50 - const bgColor = background  
51 - ? background  
52 - : theme === ThemeEnum.DARK  
53 - ? 'rgba(0, 0, 0, 0.2)'  
54 - : 'rgba(240, 242, 245, 0.4)';  
55 - return { background: bgColor };  
56 - }  
57 - );  
58 -  
59 - return { getStyle };  
60 }, 40 },
61 }); 41 });
62 </script> 42 </script>
@@ -71,6 +51,7 @@ @@ -71,6 +51,7 @@
71 height: 100%; 51 height: 100%;
72 justify-content: center; 52 justify-content: center;
73 align-items: center; 53 align-items: center;
  54 + background: rgba(240, 242, 245, 0.4);
74 55
75 &.absolute { 56 &.absolute {
76 position: absolute; 57 position: absolute;
@@ -79,4 +60,10 @@ @@ -79,4 +60,10 @@
79 z-index: 300; 60 z-index: 300;
80 } 61 }
81 } 62 }
  63 +
  64 + html[data-theme='dark'] {
  65 + .full-loading {
  66 + background: @modal-mask-bg;
  67 + }
  68 + }
82 </style> 69 </style>
src/components/Markdown/src/index.vue
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 onUnmounted, 10 onUnmounted,
11 nextTick, 11 nextTick,
12 computed, 12 computed,
13 - watchEffect, 13 + watch,
14 } from 'vue'; 14 } from 'vue';
15 import Vditor from 'vditor'; 15 import Vditor from 'vditor';
16 import 'vditor/dist/index.css'; 16 import 'vditor/dist/index.css';
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 import { propTypes } from '/@/utils/propTypes'; 18 import { propTypes } from '/@/utils/propTypes';
19 import { useLocale } from '/@/locales/useLocale'; 19 import { useLocale } from '/@/locales/useLocale';
20 import { useModalContext } from '../../Modal'; 20 import { useModalContext } from '../../Modal';
  21 + import { useRootSetting } from '/@/hooks/setting/useRootSetting';
21 22
22 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined; 23 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
23 export default defineComponent({ 24 export default defineComponent({
@@ -35,8 +36,24 @@ @@ -35,8 +36,24 @@
35 const modalFn = useModalContext(); 36 const modalFn = useModalContext();
36 37
37 const { getLocale } = useLocale(); 38 const { getLocale } = useLocale();
  39 + const { getDarkMode } = useRootSetting();
38 40
39 - watchEffect(() => {}); 41 + watch(
  42 + [() => getDarkMode.value, () => initedRef.value],
  43 + ([val]) => {
  44 + const vditor = unref(vditorRef);
  45 +
  46 + if (!vditor) {
  47 + return;
  48 + }
  49 + const theme = val === 'dark' ? 'dark' : undefined;
  50 + vditor.setTheme(theme as 'dark');
  51 + },
  52 + {
  53 + immediate: true,
  54 + flush: 'post',
  55 + }
  56 + );
40 57
41 const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => { 58 const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
42 let lang: Lang; 59 let lang: Lang;
@@ -60,6 +77,7 @@ @@ -60,6 +77,7 @@
60 if (!wrapEl) return; 77 if (!wrapEl) return;
61 const bindValue = { ...attrs, ...props }; 78 const bindValue = { ...attrs, ...props };
62 vditorRef.value = new Vditor(wrapEl, { 79 vditorRef.value = new Vditor(wrapEl, {
  80 + theme: 'classic',
63 lang: unref(getCurrentLang), 81 lang: unref(getCurrentLang),
64 mode: 'sv', 82 mode: 'sv',
65 preview: { 83 preview: {
src/components/Page/src/PageFooter.vue
@@ -38,8 +38,8 @@ @@ -38,8 +38,8 @@
38 align-items: center; 38 align-items: center;
39 padding: 0 24px; 39 padding: 0 24px;
40 line-height: 44px; 40 line-height: 44px;
41 - background: #fff;  
42 - border-top: 1px solid #f0f0f0; 41 + background: @component-background;
  42 + border-top: 1px solid @border-color-base;
43 box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05), 43 box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),
44 0 -12px 48px 16px rgba(0, 0, 0, 0.03); 44 0 -12px 48px 16px rgba(0, 0, 0, 0.03);
45 transition: width 0.2s; 45 transition: width 0.2s;
src/components/Page/src/PageWrapper.vue
@@ -17,11 +17,7 @@ @@ -17,11 +17,7 @@
17 <slot :name="item" v-bind="data"></slot> 17 <slot :name="item" v-bind="data"></slot>
18 </template> 18 </template>
19 </PageHeader> 19 </PageHeader>
20 - <div  
21 - class="overflow-hidden"  
22 - :class="[`${prefixCls}-content`, contentClass]"  
23 - :style="getContentStyle"  
24 - > 20 + <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle">
25 <slot></slot> 21 <slot></slot>
26 </div> 22 </div>
27 <PageFooter v-if="getShowFooter" ref="footerRef"> 23 <PageFooter v-if="getShowFooter" ref="footerRef">
@@ -87,14 +83,12 @@ @@ -87,14 +83,12 @@
87 83
88 const getContentStyle = computed( 84 const getContentStyle = computed(
89 (): CSSProperties => { 85 (): CSSProperties => {
90 - const { contentBackground, contentFullHeight, contentStyle, fixedHeight } = props;  
91 - const bg = contentBackground ? { backgroundColor: '#fff' } : {}; 86 + const { contentFullHeight, contentStyle, fixedHeight } = props;
92 if (!contentFullHeight) { 87 if (!contentFullHeight) {
93 - return { ...bg, ...contentStyle }; 88 + return { ...contentStyle };
94 } 89 }
95 const height = `${unref(pageHeight)}px`; 90 const height = `${unref(pageHeight)}px`;
96 return { 91 return {
97 - ...bg,  
98 ...contentStyle, 92 ...contentStyle,
99 minHeight: height, 93 minHeight: height,
100 ...(fixedHeight ? { height } : {}), 94 ...(fixedHeight ? { height } : {}),
@@ -103,6 +97,17 @@ @@ -103,6 +97,17 @@
103 } 97 }
104 ); 98 );
105 99
  100 + const getContentClass = computed(() => {
  101 + const { contentBackground, contentClass } = props;
  102 + return [
  103 + `${prefixCls}-content`,
  104 + contentClass,
  105 + {
  106 + [`${prefixCls}-content-bg`]: contentBackground,
  107 + },
  108 + ];
  109 + });
  110 +
106 watch( 111 watch(
107 () => [contentHeight?.value, getShowFooter.value], 112 () => [contentHeight?.value, getShowFooter.value],
108 () => { 113 () => {
@@ -170,6 +175,7 @@ @@ -170,6 +175,7 @@
170 getShowFooter, 175 getShowFooter,
171 pageHeight, 176 pageHeight,
172 omit, 177 omit,
  178 + getContentClass,
173 }; 179 };
174 }, 180 },
175 }); 181 });
@@ -190,6 +196,10 @@ @@ -190,6 +196,10 @@
190 } 196 }
191 } 197 }
192 198
  199 + &-content-bg {
  200 + background: @component-background;
  201 + }
  202 +
193 &--dense { 203 &--dense {
194 .@{prefix-cls}-content { 204 .@{prefix-cls}-content {
195 margin: 0; 205 margin: 0;
src/components/SimpleMenu/src/index.less
@@ -11,9 +11,9 @@ @@ -11,9 +11,9 @@
11 11
12 &-dark&-vertical .@{simple-prefix-cls}__children, 12 &-dark&-vertical .@{simple-prefix-cls}__children,
13 &-dark&-popup .@{simple-prefix-cls}__children { 13 &-dark&-popup .@{simple-prefix-cls}__children {
14 - background-color: @sider-dark-lighten-1-bg-color; 14 + background-color: @sider-dark-lighten-bg-color;
15 > .@{prefix-cls}-submenu-title { 15 > .@{prefix-cls}-submenu-title {
16 - background-color: @sider-dark-lighten-1-bg-color; 16 + background-color: @sider-dark-lighten-bg-color;
17 } 17 }
18 } 18 }
19 19
src/components/Table/src/BasicTable.vue
@@ -298,6 +298,26 @@ @@ -298,6 +298,26 @@
298 298
299 @prefix-cls: ~'@{namespace}-basic-table'; 299 @prefix-cls: ~'@{namespace}-basic-table';
300 300
  301 + html[data-theme='light'] {
  302 + .@{prefix-cls} {
  303 + &-row__striped {
  304 + td {
  305 + background: #fafafa;
  306 + }
  307 + }
  308 + }
  309 + }
  310 +
  311 + html[data-theme='dark'] {
  312 + .@{prefix-cls} {
  313 + &-row__striped {
  314 + td {
  315 + background: rgb(255 255 255 / 4%);
  316 + }
  317 + }
  318 + }
  319 + }
  320 +
301 .@{prefix-cls} { 321 .@{prefix-cls} {
302 &-form-container { 322 &-form-container {
303 padding: 16px; 323 padding: 16px;
@@ -305,17 +325,11 @@ @@ -305,17 +325,11 @@
305 .ant-form { 325 .ant-form {
306 padding: 12px 10px 6px 10px; 326 padding: 12px 10px 6px 10px;
307 margin-bottom: 16px; 327 margin-bottom: 16px;
308 - background: #fff; 328 + background: @component-background;
309 border-radius: 4px; 329 border-radius: 4px;
310 } 330 }
311 } 331 }
312 332
313 - &-row__striped {  
314 - td {  
315 - background: #fafafa;  
316 - }  
317 - }  
318 -  
319 &--inset { 333 &--inset {
320 .ant-table-wrapper { 334 .ant-table-wrapper {
321 padding: 0; 335 padding: 0;
@@ -328,7 +342,7 @@ @@ -328,7 +342,7 @@
328 342
329 .ant-table-wrapper { 343 .ant-table-wrapper {
330 padding: 6px; 344 padding: 6px;
331 - background: #fff; 345 + background: @component-background;
332 border-radius: 2px; 346 border-radius: 2px;
333 347
334 .ant-table-title { 348 .ant-table-title {
@@ -340,7 +354,6 @@ @@ -340,7 +354,6 @@
340 } 354 }
341 } 355 }
342 356
343 - //  
344 .ant-table { 357 .ant-table {
345 width: 100%; 358 width: 100%;
346 overflow-x: hidden; 359 overflow-x: hidden;
src/components/Tree/src/index.vue
@@ -324,7 +324,7 @@ @@ -324,7 +324,7 @@
324 const showTitle = title || toolbar || search || slots.headerTitle; 324 const showTitle = title || toolbar || search || slots.headerTitle;
325 const scrollStyle: CSSProperties = { height: 'calc(100% - 38px)' }; 325 const scrollStyle: CSSProperties = { height: 'calc(100% - 38px)' };
326 return ( 326 return (
327 - <div class={[prefixCls, 'h-full bg-white', attrs.class]}> 327 + <div class={[prefixCls, 'h-full', attrs.class]}>
328 {showTitle && ( 328 {showTitle && (
329 <TreeHeader 329 <TreeHeader
330 checkable={checkable} 330 checkable={checkable}
@@ -361,6 +361,8 @@ @@ -361,6 +361,8 @@
361 @prefix-cls: ~'@{namespace}-basic-tree'; 361 @prefix-cls: ~'@{namespace}-basic-tree';
362 362
363 .@{prefix-cls} { 363 .@{prefix-cls} {
  364 + background: @component-background;
  365 +
364 .ant-tree-node-content-wrapper { 366 .ant-tree-node-content-wrapper {
365 position: relative; 367 position: relative;
366 368
src/components/Upload/src/FileList.less
1 .file-table { 1 .file-table {
2 width: 100%; 2 width: 100%;
3 border-collapse: collapse; 3 border-collapse: collapse;
4 - // border: 1px solid @border-color-light;  
5 4
6 .center { 5 .center {
7 text-align: center; 6 text-align: center;
@@ -21,12 +20,12 @@ @@ -21,12 +20,12 @@
21 } 20 }
22 21
23 thead { 22 thead {
24 - background-color: @background-color-dark; 23 + background-color: @background-color-light;
25 } 24 }
26 25
27 table, 26 table,
28 td, 27 td,
29 th { 28 th {
30 - border: 1px solid @border-color-light; 29 + border: 1px solid @border-color-base;
31 } 30 }
32 } 31 }
src/design/ant/btn.less
@@ -61,9 +61,9 @@ @@ -61,9 +61,9 @@
61 &.ant-btn-link.is-disabled { 61 &.ant-btn-link.is-disabled {
62 color: rgba(0, 0, 0, 0.25) !important; 62 color: rgba(0, 0, 0, 0.25) !important;
63 text-shadow: none; 63 text-shadow: none;
64 - cursor: not-allowed;  
65 - background-color: transparent;  
66 - border-color: transparent; 64 + cursor: not-allowed !important;
  65 + background-color: transparent !important;
  66 + border-color: transparent !important;
67 box-shadow: none; 67 box-shadow: none;
68 } 68 }
69 69
@@ -187,7 +187,7 @@ @@ -187,7 +187,7 @@
187 187
188 &-ghost { 188 &-ghost {
189 color: @button-ghost-color; 189 color: @button-ghost-color;
190 - background-color: @white; 190 + background-color: transparent;
191 border-color: @button-ghost-color; 191 border-color: @button-ghost-color;
192 border-width: 1px; 192 border-width: 1px;
193 193
@@ -205,4 +205,14 @@ @@ -205,4 +205,14 @@
205 border-color: fade(@button-ghost-color, 40%); 205 border-color: fade(@button-ghost-color, 40%);
206 } 206 }
207 } 207 }
  208 +
  209 + &-ghost.ant-btn-link:not([disabled='disabled']) {
  210 + color: @button-ghost-color;
  211 +
  212 + &:hover,
  213 + &:focus {
  214 + color: @button-ghost-hover-color;
  215 + border-color: transparent;
  216 + }
  217 + }
208 } 218 }
src/design/ant/pagination.less
  1 +html[data-theme='dark'] {
  2 + .ant-pagination {
  3 + &.mini {
  4 + .ant-pagination-prev,
  5 + .ant-pagination-next,
  6 + .ant-pagination-item {
  7 + background: rgb(255 255 255 / 4%) !important;
  8 +
  9 + a {
  10 + color: #8b949e !important;
  11 + }
  12 + }
  13 +
  14 + .ant-select-arrow {
  15 + color: @text-color-secondary !important;
  16 + }
  17 +
  18 + .ant-pagination-item-active {
  19 + background: @primary-color !important;
  20 + border: none;
  21 + border-radius: none !important;
  22 +
  23 + a {
  24 + color: @white !important;
  25 + }
  26 + }
  27 + }
  28 + }
  29 +}
  30 +
1 .ant-pagination { 31 .ant-pagination {
2 &.mini { 32 &.mini {
3 .ant-pagination-prev, 33 .ant-pagination-prev,
src/design/color.less
1 -:root { 1 +html {
2 // header 2 // header
3 --header-bg-color: #394664; 3 --header-bg-color: #394664;
4 --header-bg-hover-color: #273352; 4 --header-bg-hover-color: #273352;
@@ -7,16 +7,13 @@ @@ -7,16 +7,13 @@
7 // sider 7 // sider
8 --sider-dark-bg-color: #273352; 8 --sider-dark-bg-color: #273352;
9 --sider-dark-darken-bg-color: #273352; 9 --sider-dark-darken-bg-color: #273352;
10 - --sider-dark-lighten-1-bg-color: #273352;  
11 - --sider-dark-lighten-2-bg-color: #273352; 10 + --sider-dark-lighten-bg-color: #273352;
12 } 11 }
13 12
14 @white: #fff; 13 @white: #fff;
15 14
16 @content-bg: #f4f7f9; 15 @content-bg: #f4f7f9;
17 -// @content-bg: #f0f2f5;  
18 16
19 -@basic-mask-color: fade(@white, 30%);  
20 // :export { 17 // :export {
21 // name: "less"; 18 // name: "less";
22 // mainColor: @mainColor; 19 // mainColor: @mainColor;
@@ -35,10 +32,7 @@ @@ -35,10 +32,7 @@
35 @border-color-shallow-dark: #cececd; 32 @border-color-shallow-dark: #cececd;
36 33
37 // Light-dark 34 // Light-dark
38 -@border-color-light: #ebeef5;  
39 -  
40 -// Light-light  
41 -@border-color-shallow-light: #f2f6fc; 35 +@border-color-light: @border-color-base;
42 36
43 // ================================= 37 // =================================
44 // ==============message============== 38 // ==============message==============
@@ -54,17 +48,6 @@ @@ -54,17 +48,6 @@
54 @danger-background-color: #fef0f0; 48 @danger-background-color: #fef0f0;
55 49
56 // ================================= 50 // =================================
57 -// ==============bg color============  
58 -// =================================  
59 -  
60 -// dark  
61 -@background-color-dark: #f4f7f9;  
62 -// light  
63 -@background-color-light: #f5f7fa;  
64 -// layout content background  
65 -@layout-content-bg-color: #f1f1f6;  
66 -  
67 -// =================================  
68 // ==============Header============= 51 // ==============Header=============
69 // ================================= 52 // =================================
70 53
@@ -83,14 +66,11 @@ @@ -83,14 +66,11 @@
83 // let -menu 66 // let -menu
84 @sider-dark-bg-color: var(--sider-dark-bg-color); 67 @sider-dark-bg-color: var(--sider-dark-bg-color);
85 @sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color); 68 @sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color);
86 -@sider-dark-lighten-1-bg-color: var(--sider-dark-lighten-1-bg-color);  
87 -@sider-dark-lighten-2-bg-color: var(--sider-dark-lighten-2-bg-color); 69 +@sider-dark-lighten-bg-color: var(--sider-dark-lighten-bg-color);
88 70
89 // trigger 71 // trigger
90 @trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2); 72 @trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2);
91 @trigger-dark-bg-color: rgba(255, 255, 255, 0.1); 73 @trigger-dark-bg-color: rgba(255, 255, 255, 0.1);
92 -@trigger-light-bg-color: @white;  
93 -@trigger-light-hover-bg-color: rgba(255, 255, 255, 0.7);  
94 74
95 // ================================= 75 // =================================
96 // ==============tree============ 76 // ==============tree============
@@ -119,9 +99,6 @@ @@ -119,9 +99,6 @@
119 // Auxiliary information color-dark 99 // Auxiliary information color-dark
120 @text-color-help-dark: #909399; 100 @text-color-help-dark: #909399;
121 101
122 -// Auxiliary information color-light color  
123 -@text-color-help-light: #c0c4cc;  
124 -  
125 // ================================= 102 // =================================
126 // ==============breadcrumb========= 103 // ==============breadcrumb=========
127 // ================================= 104 // =================================
src/design/index.less
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 @import 'var/index.less'; 2 @import 'var/index.less';
3 @import 'public.less'; 3 @import 'public.less';
4 @import 'ant/index.less'; 4 @import 'ant/index.less';
  5 +@import './theme.less';
5 6
6 input:-webkit-autofill { 7 input:-webkit-autofill {
7 -webkit-box-shadow: 0 0 0 1000px white inset !important; 8 -webkit-box-shadow: 0 0 0 1000px white inset !important;
src/design/theme.less 0 → 100644
  1 +.bg-white {
  2 + background: @component-background !important;
  3 +}
  4 +
  5 +html[data-theme='light'] {
  6 + .text-secondary {
  7 + color: rgba(0, 0, 0, 0.45);
  8 + }
  9 +}
  10 +
  11 +html[data-theme='dark'] {
  12 + .text-secondary {
  13 + color: #8b949e;
  14 + }
  15 +
  16 + .ant-card-grid-hoverable:hover {
  17 + box-shadow: 0 3px 6px -4px rgb(0 0 0 / 48%), 0 6px 16px 0 rgb(0 0 0 / 32%),
  18 + 0 9px 28px 8px rgb(0 0 0 / 20%);
  19 + }
  20 +
  21 + .ant-alert-message,
  22 + .ant-alert-with-description .ant-alert-message,
  23 + .ant-alert-description {
  24 + color: rgba(0, 0, 0, 0.85);
  25 + }
  26 +
  27 + .ant-checkbox-checked .ant-checkbox-inner::after {
  28 + border-top: 0;
  29 + border-left: 0;
  30 + }
  31 +}
src/directives/loading.ts
@@ -5,14 +5,12 @@ const loadingDirective: Directive = { @@ -5,14 +5,12 @@ const loadingDirective: Directive = {
5 mounted(el, binding) { 5 mounted(el, binding) {
6 const tip = el.getAttribute('loading-tip'); 6 const tip = el.getAttribute('loading-tip');
7 const background = el.getAttribute('loading-background'); 7 const background = el.getAttribute('loading-background');
8 - const theme = el.getAttribute('loading-theme');  
9 const size = el.getAttribute('loading-size'); 8 const size = el.getAttribute('loading-size');
10 const fullscreen = !!binding.modifiers.fullscreen; 9 const fullscreen = !!binding.modifiers.fullscreen;
11 const instance = createLoading( 10 const instance = createLoading(
12 { 11 {
13 tip, 12 tip,
14 background, 13 background,
15 - theme,  
16 size: size || 'large', 14 size: size || 'large',
17 loading: !!binding.value, 15 loading: !!binding.value,
18 absolute: !fullscreen, 16 absolute: !fullscreen,
src/enums/appEnum.ts
@@ -8,17 +8,9 @@ export enum ContentEnum { @@ -8,17 +8,9 @@ export enum ContentEnum {
8 FIXED = 'fixed', 8 FIXED = 'fixed',
9 } 9 }
10 10
11 -// app current theme  
12 -export enum ThemeModeEnum {  
13 - LIGHT = 'light-mode',  
14 - DARK = 'dark-mode',  
15 - SEMI_DARK = 'semi-dark-mode',  
16 -}  
17 -  
18 // menu theme enum 11 // menu theme enum
19 export enum ThemeEnum { 12 export enum ThemeEnum {
20 DARK = 'dark', 13 DARK = 'dark',
21 -  
22 LIGHT = 'light', 14 LIGHT = 'light',
23 } 15 }
24 16
src/enums/cacheEnum.ts
@@ -15,6 +15,8 @@ export const PROJ_CFG_KEY = &#39;PROJ__CFG__KEY__&#39;; @@ -15,6 +15,8 @@ export const PROJ_CFG_KEY = &#39;PROJ__CFG__KEY__&#39;;
15 // lock info 15 // lock info
16 export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__'; 16 export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__';
17 17
  18 +export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__';
  19 +
18 // base global local key 20 // base global local key
19 export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__'; 21 export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__';
20 22
src/hooks/setting/useRootSetting.ts
@@ -4,6 +4,7 @@ import { computed, unref } from &#39;vue&#39;; @@ -4,6 +4,7 @@ import { computed, unref } from &#39;vue&#39;;
4 4
5 import { appStore } from '/@/store/modules/app'; 5 import { appStore } from '/@/store/modules/app';
6 import { ContentEnum } from '/@/enums/appEnum'; 6 import { ContentEnum } from '/@/enums/appEnum';
  7 +import { ThemeEnum } from '../../enums/appEnum';
7 8
8 type RootSetting = Omit< 9 type RootSetting = Omit<
9 ProjectConfig, 10 ProjectConfig,
@@ -48,6 +49,10 @@ const getGrayMode = computed(() =&gt; unref(getRootSetting).grayMode); @@ -48,6 +49,10 @@ const getGrayMode = computed(() =&gt; unref(getRootSetting).grayMode);
48 49
49 const getLockTime = computed(() => unref(getRootSetting).lockTime); 50 const getLockTime = computed(() => unref(getRootSetting).lockTime);
50 51
  52 +const getShowDarkModeToggle = computed(() => unref(getRootSetting).showDarkModeToggle);
  53 +
  54 +const getDarkMode = computed(() => appStore.getDarkMode);
  55 +
51 const getLayoutContentMode = computed(() => 56 const getLayoutContentMode = computed(() =>
52 unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED 57 unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
53 ); 58 );
@@ -56,6 +61,10 @@ function setRootSetting(setting: Partial&lt;RootSetting&gt;) { @@ -56,6 +61,10 @@ function setRootSetting(setting: Partial&lt;RootSetting&gt;) {
56 appStore.commitProjectConfigState(setting); 61 appStore.commitProjectConfigState(setting);
57 } 62 }
58 63
  64 +function setDarkMode(mode: ThemeEnum) {
  65 + appStore.commitDarkMode(mode);
  66 +}
  67 +
59 export function useRootSetting() { 68 export function useRootSetting() {
60 return { 69 return {
61 setRootSetting, 70 setRootSetting,
@@ -80,5 +89,8 @@ export function useRootSetting() { @@ -80,5 +89,8 @@ export function useRootSetting() {
80 getContentMode, 89 getContentMode,
81 getLockTime, 90 getLockTime,
82 getThemeColor, 91 getThemeColor,
  92 + getDarkMode,
  93 + setDarkMode,
  94 + getShowDarkModeToggle,
83 }; 95 };
84 } 96 }
src/hooks/web/useApexCharts.ts deleted 100644 → 0
1 -import { useTimeoutFn } from '/@/hooks/core/useTimeout';  
2 -import { unref, Ref, nextTick } from 'vue';  
3 -import { tryOnUnmounted } from '@vueuse/core';  
4 -  
5 -interface CallBackFn {  
6 - (instance: Nullable<ApexCharts>): void;  
7 -}  
8 -  
9 -export function useApexCharts(elRef: Ref<HTMLDivElement>) {  
10 - let chartInstance: Nullable<ApexCharts> = null;  
11 -  
12 - function setOptions(options: any, callback?: CallBackFn) {  
13 - nextTick(() => {  
14 - useTimeoutFn(async () => {  
15 - const el = unref(elRef);  
16 -  
17 - if (!el || !unref(el)) return;  
18 - const ApexCharts = await (await import('apexcharts')).default;  
19 - chartInstance = new ApexCharts(el, options);  
20 -  
21 - chartInstance && chartInstance.render();  
22 -  
23 - // The callback method is added to setOptions to return the chartInstance to facilitate the re-operation of the chart, such as calling the updateOptions method to update the chart  
24 - callback && callback(chartInstance);  
25 - }, 30);  
26 - });  
27 - }  
28 -  
29 - // Call the updateOptions method of ApexCharts to update the chart  
30 - function updateOptions(  
31 - chartInstance: Nullable<ApexCharts>,  
32 - options: any,  
33 - redraw = false,  
34 - animate = true,  
35 - updateSyncedCharts = true,  
36 - callback: CallBackFn  
37 - ) {  
38 - nextTick(() => {  
39 - useTimeoutFn(() => {  
40 - chartInstance && chartInstance.updateOptions(options, redraw, animate, updateSyncedCharts);  
41 -  
42 - callback && callback(chartInstance);  
43 - }, 30);  
44 - });  
45 - }  
46 -  
47 - tryOnUnmounted(() => {  
48 - if (!chartInstance) return;  
49 - chartInstance?.destroy?.();  
50 - chartInstance = null;  
51 - });  
52 -  
53 - return {  
54 - setOptions,  
55 - updateOptions,  
56 - };  
57 -}  
src/hooks/web/useECharts.ts
1 import { useTimeoutFn } from '/@/hooks/core/useTimeout'; 1 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
2 import { tryOnUnmounted } from '@vueuse/core'; 2 import { tryOnUnmounted } from '@vueuse/core';
3 -import { unref, Ref, nextTick } from 'vue'; 3 +import { unref, Ref, nextTick, watch, computed, ref } from 'vue';
4 import type { EChartsOption } from 'echarts'; 4 import type { EChartsOption } from 'echarts';
5 import { useDebounce } from '/@/hooks/core/useDebounce'; 5 import { useDebounce } from '/@/hooks/core/useDebounce';
6 import { useEventListener } from '/@/hooks/event/useEventListener'; 6 import { useEventListener } from '/@/hooks/event/useEventListener';
7 import { useBreakpoint } from '/@/hooks/event/useBreakpoint'; 7 import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
8 8
9 import echarts from '/@/plugins/echarts'; 9 import echarts from '/@/plugins/echarts';
  10 +import { useRootSetting } from '../setting/useRootSetting';
10 11
11 export function useECharts( 12 export function useECharts(
12 elRef: Ref<HTMLDivElement>, 13 elRef: Ref<HTMLDivElement>,
13 theme: 'light' | 'dark' | 'default' = 'light' 14 theme: 'light' | 'dark' | 'default' = 'light'
14 ) { 15 ) {
  16 + const { getDarkMode } = useRootSetting();
15 let chartInstance: echarts.ECharts | null = null; 17 let chartInstance: echarts.ECharts | null = null;
16 let resizeFn: Fn = resize; 18 let resizeFn: Fn = resize;
  19 + const cacheOptions = ref<EChartsOption>({});
17 let removeResizeFn: Fn = () => {}; 20 let removeResizeFn: Fn = () => {};
18 21
19 const [debounceResize] = useDebounce(resize, 200); 22 const [debounceResize] = useDebounce(resize, 200);
20 resizeFn = debounceResize; 23 resizeFn = debounceResize;
21 24
22 - function initCharts() { 25 + const getOptions = computed(
  26 + (): EChartsOption => {
  27 + if (getDarkMode.value !== 'dark') {
  28 + return cacheOptions.value;
  29 + }
  30 + return {
  31 + backgroundColor: '#151515',
  32 + ...cacheOptions.value,
  33 + };
  34 + }
  35 + );
  36 +
  37 + function initCharts(t = theme) {
23 const el = unref(elRef); 38 const el = unref(elRef);
24 if (!el || !unref(el)) { 39 if (!el || !unref(el)) {
25 return; 40 return;
26 } 41 }
27 42
28 - chartInstance = echarts.init(el, theme); 43 + chartInstance = echarts.init(el, t);
29 const { removeEvent } = useEventListener({ 44 const { removeEvent } = useEventListener({
30 el: window, 45 el: window,
31 name: 'resize', 46 name: 'resize',
@@ -41,22 +56,23 @@ export function useECharts( @@ -41,22 +56,23 @@ export function useECharts(
41 } 56 }
42 57
43 function setOptions(options: EChartsOption, clear = true) { 58 function setOptions(options: EChartsOption, clear = true) {
  59 + cacheOptions.value = options;
44 if (unref(elRef)?.offsetHeight === 0) { 60 if (unref(elRef)?.offsetHeight === 0) {
45 useTimeoutFn(() => { 61 useTimeoutFn(() => {
46 - setOptions(options); 62 + setOptions(unref(getOptions));
47 }, 30); 63 }, 30);
48 return; 64 return;
49 } 65 }
50 nextTick(() => { 66 nextTick(() => {
51 useTimeoutFn(() => { 67 useTimeoutFn(() => {
52 if (!chartInstance) { 68 if (!chartInstance) {
53 - initCharts(); 69 + initCharts(getDarkMode.value);
54 70
55 if (!chartInstance) return; 71 if (!chartInstance) return;
56 } 72 }
57 clear && chartInstance?.clear(); 73 clear && chartInstance?.clear();
58 74
59 - chartInstance?.setOption(options); 75 + chartInstance?.setOption(unref(getOptions));
60 }, 30); 76 }, 30);
61 }); 77 });
62 } 78 }
@@ -65,6 +81,17 @@ export function useECharts( @@ -65,6 +81,17 @@ export function useECharts(
65 chartInstance?.resize(); 81 chartInstance?.resize();
66 } 82 }
67 83
  84 + watch(
  85 + () => getDarkMode.value,
  86 + (theme) => {
  87 + if (chartInstance) {
  88 + chartInstance.dispose();
  89 + initCharts(theme);
  90 + setOptions(cacheOptions.value);
  91 + }
  92 + }
  93 + );
  94 +
68 tryOnUnmounted(() => { 95 tryOnUnmounted(() => {
69 if (!chartInstance) return; 96 if (!chartInstance) return;
70 removeResizeFn(); 97 removeResizeFn();
src/layouts/default/header/MultipleHeader.vue
@@ -112,7 +112,6 @@ @@ -112,7 +112,6 @@
112 @prefix-cls: ~'@{namespace}-layout-multiple-header'; 112 @prefix-cls: ~'@{namespace}-layout-multiple-header';
113 113
114 .@{prefix-cls} { 114 .@{prefix-cls} {
115 - // margin-left: 1px;  
116 transition: width 0.2s; 115 transition: width 0.2s;
117 flex: 0 0 auto; 116 flex: 0 0 auto;
118 117
src/layouts/default/header/components/lock/LockModal.vue
@@ -91,7 +91,6 @@ @@ -91,7 +91,6 @@
91 position: relative; 91 position: relative;
92 height: 240px; 92 height: 240px;
93 padding: 130px 30px 60px 30px; 93 padding: 130px 30px 60px 30px;
94 - background: #fff;  
95 border-radius: 10px; 94 border-radius: 10px;
96 } 95 }
97 96
src/layouts/default/header/components/user-dropdown/index.vue
@@ -131,10 +131,6 @@ @@ -131,10 +131,6 @@
131 cursor: pointer; 131 cursor: pointer;
132 align-items: center; 132 align-items: center;
133 133
134 - &:hover {  
135 - background: @header-light-bg-hover-color;  
136 - }  
137 -  
138 img { 134 img {
139 width: 24px; 135 width: 24px;
140 height: 24px; 136 height: 24px;
src/layouts/default/header/index.less
@@ -131,7 +131,7 @@ @@ -131,7 +131,7 @@
131 } 131 }
132 132
133 &--light { 133 &--light {
134 - background: @white; 134 + background: @white !important;
135 border-bottom: 1px solid @header-light-bottom-border-color; 135 border-bottom: 1px solid @header-light-bottom-border-color;
136 border-left: 1px solid @header-light-bottom-border-color; 136 border-left: 1px solid @header-light-bottom-border-color;
137 137
@@ -165,8 +165,9 @@ @@ -165,8 +165,9 @@
165 } 165 }
166 166
167 &--dark { 167 &--dark {
168 - background: @header-dark-bg-color;  
169 - 168 + background: @header-dark-bg-color !important;
  169 + border-bottom: 1px solid @border-color-base;
  170 + border-left: 1px solid @border-color-base;
170 .@{header-prefix-cls}-logo { 171 .@{header-prefix-cls}-logo {
171 &:hover { 172 &:hover {
172 background: @header-dark-bg-hover-color; 173 background: @header-dark-bg-hover-color;
src/layouts/default/setting/SettingDrawer.tsx
@@ -3,13 +3,15 @@ import { BasicDrawer } from &#39;/@/components/Drawer/index&#39;; @@ -3,13 +3,15 @@ import { BasicDrawer } from &#39;/@/components/Drawer/index&#39;;
3 import { Divider } from 'ant-design-vue'; 3 import { Divider } from 'ant-design-vue';
4 import { 4 import {
5 TypePicker, 5 TypePicker,
6 - ThemePicker, 6 + ThemeColorPicker,
7 SettingFooter, 7 SettingFooter,
8 SwitchItem, 8 SwitchItem,
9 SelectItem, 9 SelectItem,
10 InputNumberItem, 10 InputNumberItem,
11 } from './components'; 11 } from './components';
12 12
  13 +import { AppDarkModeToggle } from '/@/components/Application';
  14 +
13 import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; 15 import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
14 16
15 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 17 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
@@ -52,6 +54,7 @@ export default defineComponent({ @@ -52,6 +54,7 @@ export default defineComponent({
52 getColorWeak, 54 getColorWeak,
53 getGrayMode, 55 getGrayMode,
54 getLockTime, 56 getLockTime,
  57 + getShowDarkModeToggle,
55 getThemeColor, 58 getThemeColor,
56 } = useRootSetting(); 59 } = useRootSetting();
57 60
@@ -116,7 +119,7 @@ export default defineComponent({ @@ -116,7 +119,7 @@ export default defineComponent({
116 119
117 function renderHeaderTheme() { 120 function renderHeaderTheme() {
118 return ( 121 return (
119 - <ThemePicker 122 + <ThemeColorPicker
120 colorList={HEADER_PRESET_BG_COLOR_LIST} 123 colorList={HEADER_PRESET_BG_COLOR_LIST}
121 def={unref(getHeaderBgColor)} 124 def={unref(getHeaderBgColor)}
122 event={HandlerEnum.HEADER_THEME} 125 event={HandlerEnum.HEADER_THEME}
@@ -126,7 +129,7 @@ export default defineComponent({ @@ -126,7 +129,7 @@ export default defineComponent({
126 129
127 function renderSiderTheme() { 130 function renderSiderTheme() {
128 return ( 131 return (
129 - <ThemePicker 132 + <ThemeColorPicker
130 colorList={SIDE_BAR_BG_COLOR_LIST} 133 colorList={SIDE_BAR_BG_COLOR_LIST}
131 def={unref(getMenuBgColor)} 134 def={unref(getMenuBgColor)}
132 event={HandlerEnum.MENU_THEME} 135 event={HandlerEnum.MENU_THEME}
@@ -136,7 +139,7 @@ export default defineComponent({ @@ -136,7 +139,7 @@ export default defineComponent({
136 139
137 function renderMainTheme() { 140 function renderMainTheme() {
138 return ( 141 return (
139 - <ThemePicker 142 + <ThemeColorPicker
140 colorList={APP_PRESET_COLOR_LIST} 143 colorList={APP_PRESET_COLOR_LIST}
141 def={unref(getThemeColor)} 144 def={unref(getThemeColor)}
142 event={HandlerEnum.CHANGE_THEME_COLOR} 145 event={HandlerEnum.CHANGE_THEME_COLOR}
@@ -404,6 +407,8 @@ export default defineComponent({ @@ -404,6 +407,8 @@ export default defineComponent({
404 width={330} 407 width={330}
405 wrapClassName="setting-drawer" 408 wrapClassName="setting-drawer"
406 > 409 >
  410 + {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
  411 + {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" size="large" />}
407 <Divider>{() => t('layout.setting.navMode')}</Divider> 412 <Divider>{() => t('layout.setting.navMode')}</Divider>
408 {renderSidebar()} 413 {renderSidebar()}
409 <Divider>{() => t('layout.setting.sysTheme')}</Divider> 414 <Divider>{() => t('layout.setting.sysTheme')}</Divider>
src/layouts/default/setting/components/ThemePicker.vue renamed to src/layouts/default/setting/components/ThemeColorPicker.vue
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 import { HandlerEnum } from '../enum'; 26 import { HandlerEnum } from '../enum';
27 27
28 export default defineComponent({ 28 export default defineComponent({
29 - name: 'ThemePicker', 29 + name: 'ThemeColorPicker',
30 components: { CheckOutlined }, 30 components: { CheckOutlined },
31 props: { 31 props: {
32 colorList: { 32 colorList: {
src/layouts/default/setting/components/TypePicker.vue
@@ -74,7 +74,8 @@ @@ -74,7 +74,8 @@
74 content: ''; 74 content: '';
75 } 75 }
76 76
77 - &--sidebar { 77 + &--sidebar,
  78 + &--light {
78 &::before { 79 &::before {
79 top: 0; 80 top: 0;
80 left: 0; 81 left: 0;
@@ -124,6 +125,10 @@ @@ -124,6 +125,10 @@
124 } 125 }
125 } 126 }
126 127
  128 + &--dark {
  129 + background-color: #273352;
  130 + }
  131 +
127 &--mix-sidebar { 132 &--mix-sidebar {
128 &::before { 133 &::before {
129 top: 0; 134 top: 0;
@@ -152,17 +157,6 @@ @@ -152,17 +157,6 @@
152 } 157 }
153 } 158 }
154 159
155 - // &::after {  
156 - // position: absolute;  
157 - // top: 50%;  
158 - // left: 50%;  
159 - // width: 0;  
160 - // height: 0;  
161 - // content: '';  
162 - // opacity: 0;  
163 - // transition: all 0.3s;  
164 - // }  
165 -  
166 &:hover, 160 &:hover,
167 &--active { 161 &--active {
168 padding: 12px; 162 padding: 12px;
src/layouts/default/setting/components/index.ts
1 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; 1 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
2 2
3 export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue')); 3 export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
4 -export const ThemePicker = createAsyncComponent(() => import('./ThemePicker.vue')); 4 +export const ThemeColorPicker = createAsyncComponent(() => import('./ThemeColorPicker.vue'));
5 export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue')); 5 export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue'));
6 export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue')); 6 export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue'));
7 export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue')); 7 export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue'));
src/layouts/default/setting/enum.ts
@@ -14,6 +14,7 @@ const { t } = useI18n(); @@ -14,6 +14,7 @@ const { t } = useI18n();
14 export enum HandlerEnum { 14 export enum HandlerEnum {
15 CHANGE_LAYOUT, 15 CHANGE_LAYOUT,
16 CHANGE_THEME_COLOR, 16 CHANGE_THEME_COLOR,
  17 + CHANGE_THEME,
17 // menu 18 // menu
18 MENU_HAS_DRAG, 19 MENU_HAS_DRAG,
19 MENU_ACCORDION, 20 MENU_ACCORDION,
src/layouts/default/setting/handler.ts
@@ -6,15 +6,20 @@ import { updateGrayMode } from &#39;/@/logics/theme/updateGrayMode&#39;; @@ -6,15 +6,20 @@ import { updateGrayMode } from &#39;/@/logics/theme/updateGrayMode&#39;;
6 import { appStore } from '/@/store/modules/app'; 6 import { appStore } from '/@/store/modules/app';
7 import { ProjectConfig } from '/#/config'; 7 import { ProjectConfig } from '/#/config';
8 import { changeTheme } from '/@/logics/theme'; 8 import { changeTheme } from '/@/logics/theme';
  9 +import { updateDarkTheme } from '/@/logics/theme/dark';
9 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 10 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
10 11
11 export function baseHandler(event: HandlerEnum, value: any) { 12 export function baseHandler(event: HandlerEnum, value: any) {
12 const config = handler(event, value); 13 const config = handler(event, value);
13 appStore.commitProjectConfigState(config); 14 appStore.commitProjectConfigState(config);
  15 + if (event === HandlerEnum.CHANGE_THEME) {
  16 + updateHeaderBgColor();
  17 + updateSidebarBgColor();
  18 + }
14 } 19 }
15 20
16 export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> { 21 export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
17 - const { getThemeColor } = useRootSetting(); 22 + const { getThemeColor, getDarkMode } = useRootSetting();
18 switch (event) { 23 switch (event) {
19 case HandlerEnum.CHANGE_LAYOUT: 24 case HandlerEnum.CHANGE_LAYOUT:
20 const { mode, type, split } = value; 25 const { mode, type, split } = value;
@@ -36,8 +41,17 @@ export function handler(event: HandlerEnum, value: any): DeepPartial&lt;ProjectConf @@ -36,8 +41,17 @@ export function handler(event: HandlerEnum, value: any): DeepPartial&lt;ProjectConf
36 return {}; 41 return {};
37 } 42 }
38 changeTheme(value); 43 changeTheme(value);
  44 +
39 return { themeColor: value }; 45 return { themeColor: value };
40 46
  47 + case HandlerEnum.CHANGE_THEME:
  48 + if (getDarkMode.value === value) {
  49 + return {};
  50 + }
  51 + updateDarkTheme(value);
  52 +
  53 + return { darkMode: value };
  54 +
41 case HandlerEnum.MENU_HAS_DRAG: 55 case HandlerEnum.MENU_HAS_DRAG:
42 return { menuSetting: { canDrag: value } }; 56 return { menuSetting: { canDrag: value } };
43 57
src/layouts/default/sider/MixSider.vue
@@ -403,7 +403,7 @@ @@ -403,7 +403,7 @@
403 } 403 }
404 } 404 }
405 } 405 }
406 - @border-color: @sider-dark-lighten-1-bg-color; 406 + @border-color: @sider-dark-lighten-bg-color;
407 407
408 &.dark { 408 &.dark {
409 &.open { 409 &.open {
src/layouts/default/tabs/index.less
1 @prefix-cls: ~'@{namespace}-multiple-tabs'; 1 @prefix-cls: ~'@{namespace}-multiple-tabs';
2 2
  3 +html[data-theme='dark'] {
  4 + .@{prefix-cls} {
  5 + .ant-tabs-tab {
  6 + border-bottom: 1px solid @border-color-base;
  7 + }
  8 + }
  9 +}
  10 +
3 .@{prefix-cls} { 11 .@{prefix-cls} {
4 z-index: 10; 12 z-index: 10;
5 height: @multiple-height + 2; 13 height: @multiple-height + 2;
6 line-height: @multiple-height + 2; 14 line-height: @multiple-height + 2;
7 - background: @white; 15 + background: @component-background;
  16 + border-bottom: 1px solid @border-color-base;
8 box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05); 17 box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
9 18
10 .ant-tabs-small { 19 .ant-tabs-small {
@@ -15,7 +24,7 @@ @@ -15,7 +24,7 @@
15 .ant-tabs-card-bar { 24 .ant-tabs-card-bar {
16 height: @multiple-height; 25 height: @multiple-height;
17 margin: 0; 26 margin: 0;
18 - background: @white; 27 + background: @component-background;
19 border: 0; 28 border: 0;
20 box-shadow: none; 29 box-shadow: none;
21 30
@@ -28,35 +37,14 @@ @@ -28,35 +37,14 @@
28 height: calc(@multiple-height - 2px); 37 height: calc(@multiple-height - 2px);
29 padding-right: 12px; 38 padding-right: 12px;
30 line-height: calc(@multiple-height - 2px); 39 line-height: calc(@multiple-height - 2px);
31 - color: @text-color-call-out;  
32 - background: @white;  
33 - border-bottom: 1px solid @header-light-bottom-border-color; 40 + color: @text-color-base;
  41 + background: @component-background;
34 transition: none; 42 transition: none;
35 43
36 - // &:not(.ant-tabs-tab-active)::before {  
37 - // position: absolute;  
38 - // top: -1px;  
39 - // left: 50%;  
40 - // width: 100%;  
41 - // height: 2px;  
42 - // background-color: @primary-color;  
43 - // content: '';  
44 - // opacity: 0;  
45 - // transform: translate(-50%, 0) scaleX(0);  
46 - // transform-origin: center;  
47 - // transition: none;  
48 - // }  
49 -  
50 &:hover { 44 &:hover {
51 .ant-tabs-close-x { 45 .ant-tabs-close-x {
52 opacity: 1; 46 opacity: 1;
53 } 47 }
54 -  
55 - // &:not(.ant-tabs-tab-active)::before {  
56 - // opacity: 1;  
57 - // transform: translate(-50%, 0) scaleX(1);  
58 - // transition: all 0.3s ease-in-out;  
59 - // }  
60 } 48 }
61 49
62 .ant-tabs-close-x { 50 .ant-tabs-close-x {
@@ -85,26 +73,20 @@ @@ -85,26 +73,20 @@
85 } 73 }
86 } 74 }
87 75
  76 + .ant-tabs-tab:not(.ant-tabs-tab-active) {
  77 + &:hover {
  78 + color: @primary-color;
  79 + }
  80 + }
  81 +
88 .ant-tabs-tab-active { 82 .ant-tabs-tab-active {
89 position: relative; 83 position: relative;
90 - padding-left: 26px; 84 + padding-left: 18px;
91 color: @white; 85 color: @white;
92 - background: fade(@primary-color, 100%); 86 + background: @primary-color;
93 border: 0; 87 border: 0;
94 transition: none; 88 transition: none;
95 89
96 - &::before {  
97 - position: absolute;  
98 - top: calc(50% - 3px);  
99 - left: 8px;  
100 - width: 6px;  
101 - height: 6px;  
102 - background: #fff;  
103 - border-radius: 50%;  
104 - content: '';  
105 - transition: none;  
106 - }  
107 -  
108 .ant-tabs-close-x { 90 .ant-tabs-close-x {
109 opacity: 1; 91 opacity: 1;
110 } 92 }
@@ -158,10 +140,10 @@ @@ -158,10 +140,10 @@
158 width: 36px; 140 width: 36px;
159 height: @multiple-height; 141 height: @multiple-height;
160 line-height: @multiple-height; 142 line-height: @multiple-height;
161 - color: #666; 143 + color: @text-color-secondary;
162 text-align: center; 144 text-align: center;
163 cursor: pointer; 145 cursor: pointer;
164 - border-left: 1px solid #eee; 146 + border-left: 1px solid @border-color-base;
165 147
166 &:hover { 148 &:hover {
167 color: @text-color-base; 149 color: @text-color-base;
src/locales/lang/en/common.ts
@@ -14,4 +14,7 @@ export default { @@ -14,4 +14,7 @@ export default {
14 14
15 redo: 'Refresh', 15 redo: 'Refresh',
16 back: 'Back', 16 back: 'Back',
  17 +
  18 + light: 'Light',
  19 + dark: 'Dark',
17 }; 20 };
src/locales/lang/en/layout/setting.ts
@@ -30,6 +30,7 @@ export default { @@ -30,6 +30,7 @@ export default {
30 30
31 drawerTitle: 'Configuration', 31 drawerTitle: 'Configuration',
32 32
  33 + darkMode: 'Dark mode',
33 navMode: 'Navigation mode', 34 navMode: 'Navigation mode',
34 interfaceFunction: 'Interface function', 35 interfaceFunction: 'Interface function',
35 interfaceDisplay: 'Interface display', 36 interfaceDisplay: 'Interface display',
src/locales/lang/en/routes/demo/charts.ts
@@ -6,5 +6,4 @@ export default { @@ -6,5 +6,4 @@ export default {
6 map: 'Map', 6 map: 'Map',
7 line: 'Line', 7 line: 'Line',
8 pie: 'Pie', 8 pie: 'Pie',
9 - apexChart: 'ApexChart',  
10 }; 9 };
src/locales/lang/zh_CN/common.ts
@@ -14,4 +14,7 @@ export default { @@ -14,4 +14,7 @@ export default {
14 14
15 redo: '刷新', 15 redo: '刷新',
16 back: '返回', 16 back: '返回',
  17 +
  18 + light: '亮色主题',
  19 + dark: '黑暗主题',
17 }; 20 };
src/locales/lang/zh_CN/layout/setting.ts
@@ -29,6 +29,7 @@ export default { @@ -29,6 +29,7 @@ export default {
29 29
30 drawerTitle: '项目配置', 30 drawerTitle: '项目配置',
31 31
  32 + darkMode: '主题',
32 navMode: '导航栏模式', 33 navMode: '导航栏模式',
33 interfaceFunction: '界面功能', 34 interfaceFunction: '界面功能',
34 interfaceDisplay: '界面显示', 35 interfaceDisplay: '界面显示',
src/locales/lang/zh_CN/routes/demo/charts.ts
@@ -6,5 +6,4 @@ export default { @@ -6,5 +6,4 @@ export default {
6 map: '地图', 6 map: '地图',
7 line: '折线图', 7 line: '折线图',
8 pie: '饼图', 8 pie: '饼图',
9 - apexChart: 'ApexChart',  
10 }; 9 };
src/logics/initAppConfig.ts
@@ -9,6 +9,7 @@ import projectSetting from &#39;/@/settings/projectSetting&#39;; @@ -9,6 +9,7 @@ import projectSetting from &#39;/@/settings/projectSetting&#39;;
9 import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground'; 9 import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
10 import { updateColorWeak } from '/@/logics/theme/updateColorWeak'; 10 import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
11 import { updateGrayMode } from '/@/logics/theme/updateGrayMode'; 11 import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
  12 +import { updateDarkTheme } from '/@/logics/theme/dark';
12 import { changeTheme } from '/@/logics/theme'; 13 import { changeTheme } from '/@/logics/theme';
13 14
14 import { appStore } from '/@/store/modules/app'; 15 import { appStore } from '/@/store/modules/app';
@@ -19,30 +20,43 @@ import { getCommonStoragePrefix, getStorageShortName } from &#39;/@/utils/env&#39;; @@ -19,30 +20,43 @@ import { getCommonStoragePrefix, getStorageShortName } from &#39;/@/utils/env&#39;;
19 import { primaryColor } from '../../build/config/themeConfig'; 20 import { primaryColor } from '../../build/config/themeConfig';
20 import { Persistent } from '/@/utils/cache/persistent'; 21 import { Persistent } from '/@/utils/cache/persistent';
21 import { deepMerge } from '/@/utils'; 22 import { deepMerge } from '/@/utils';
  23 +import { ThemeEnum } from '../enums/appEnum';
22 24
23 // Initial project configuration 25 // Initial project configuration
24 export function initAppConfigStore() { 26 export function initAppConfigStore() {
25 let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig; 27 let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
26 projCfg = deepMerge(projectSetting, projCfg || {}); 28 projCfg = deepMerge(projectSetting, projCfg || {});
  29 + const darkMode = appStore.getDarkMode;
  30 + const {
  31 + colorWeak,
  32 + grayMode,
  33 + themeColor,
  34 +
  35 + headerSetting: { bgColor: headerBgColor } = {},
  36 + menuSetting: { bgColor } = {},
  37 + } = projCfg;
27 try { 38 try {
28 - const {  
29 - colorWeak,  
30 - grayMode,  
31 - themeColor,  
32 - headerSetting: { bgColor: headerBgColor } = {},  
33 - menuSetting: { bgColor } = {},  
34 - } = projCfg;  
35 if (themeColor && themeColor !== primaryColor) { 39 if (themeColor && themeColor !== primaryColor) {
36 changeTheme(themeColor); 40 changeTheme(themeColor);
37 } 41 }
38 - headerBgColor && updateHeaderBgColor(headerBgColor);  
39 - bgColor && updateSidebarBgColor(bgColor); 42 +
40 grayMode && updateGrayMode(grayMode); 43 grayMode && updateGrayMode(grayMode);
41 colorWeak && updateColorWeak(colorWeak); 44 colorWeak && updateColorWeak(colorWeak);
42 } catch (error) { 45 } catch (error) {
43 console.log(error); 46 console.log(error);
44 } 47 }
45 appStore.commitProjectConfigState(projCfg); 48 appStore.commitProjectConfigState(projCfg);
  49 +
  50 + // init dark mode
  51 + updateDarkTheme(darkMode);
  52 + if (darkMode === ThemeEnum.DARK) {
  53 + updateHeaderBgColor();
  54 + updateSidebarBgColor();
  55 + } else {
  56 + headerBgColor && updateHeaderBgColor(headerBgColor);
  57 + bgColor && updateSidebarBgColor(bgColor);
  58 + }
  59 + // init store
46 localeStore.initLocale(); 60 localeStore.initLocale();
47 61
48 setTimeout(() => { 62 setTimeout(() => {
src/logics/theme/dark.ts 0 → 100644
  1 +import { darkCssIsReady, loadDarkThemeCss } from 'vite-plugin-theme/es/client';
  2 +
  3 +export async function updateDarkTheme(mode: string | null = 'light') {
  4 + const htmlRoot = document.getElementById('htmlRoot');
  5 + if (mode === 'dark') {
  6 + if (import.meta.env.PROD && !darkCssIsReady) {
  7 + await loadDarkThemeCss();
  8 + }
  9 + htmlRoot?.setAttribute('data-theme', 'dark');
  10 + } else {
  11 + htmlRoot?.setAttribute('data-theme', 'light');
  12 + }
  13 +}
src/logics/theme/index.ts
1 -import { getThemeColors, ThemeMode, generateColors } from '../../../build/config/themeConfig'; 1 +import { getThemeColors, generateColors } from '../../../build/config/themeConfig';
2 2
3 import { replaceStyleVariables } from 'vite-plugin-theme/es/client'; 3 import { replaceStyleVariables } from 'vite-plugin-theme/es/client';
4 import { mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme/es/colorUtils'; 4 import { mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme/es/colorUtils';
5 5
6 -export async function changeTheme(color: string, theme?: ThemeMode) { 6 +export async function changeTheme(color: string) {
7 const colors = generateColors({ 7 const colors = generateColors({
8 mixDarken, 8 mixDarken,
9 mixLighten, 9 mixLighten,
@@ -12,6 +12,6 @@ export async function changeTheme(color: string, theme?: ThemeMode) { @@ -12,6 +12,6 @@ export async function changeTheme(color: string, theme?: ThemeMode) {
12 }); 12 });
13 13
14 return await replaceStyleVariables({ 14 return await replaceStyleVariables({
15 - colorVariables: [...getThemeColors(color, theme), ...colors], 15 + colorVariables: [...getThemeColors(color), ...colors],
16 }); 16 });
17 } 17 }
src/logics/theme/updateBackground.ts
1 -import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color'; 1 +import { colorIsDark, lighten, darken } from '/@/utils/color';
2 import { appStore } from '/@/store/modules/app'; 2 import { appStore } from '/@/store/modules/app';
3 import { ThemeEnum } from '/@/enums/appEnum'; 3 import { ThemeEnum } from '/@/enums/appEnum';
4 import { setCssVar } from './util'; 4 import { setCssVar } from './util';
@@ -9,29 +9,35 @@ const HEADER_MENU_ACTIVE_BG_COLOR_VAR = &#39;--header-active-menu-bg-color&#39;; @@ -9,29 +9,35 @@ const HEADER_MENU_ACTIVE_BG_COLOR_VAR = &#39;--header-active-menu-bg-color&#39;;
9 9
10 const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color'; 10 const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color';
11 const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color'; 11 const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color';
12 -const SIDER_LIGHTEN_1_BG_COLOR = '--sider-dark-lighten-1-bg-color';  
13 -const SIDER_LIGHTEN_2_BG_COLOR = '--sider-dark-lighten-2-bg-color'; 12 +const SIDER_LIGHTEN_BG_COLOR = '--sider-dark-lighten-bg-color';
14 13
15 /** 14 /**
16 * Change the background color of the top header 15 * Change the background color of the top header
17 * @param color 16 * @param color
18 */ 17 */
19 -export function updateHeaderBgColor(color: string) {  
20 - if (!isHexColor(color)) return; 18 +export function updateHeaderBgColor(color?: string) {
  19 + const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
  20 + if (!color) {
  21 + if (darkMode) {
  22 + color = '#151515';
  23 + } else {
  24 + color = appStore.getProjectConfig.headerSetting.bgColor;
  25 + }
  26 + }
21 // bg color 27 // bg color
22 setCssVar(HEADER_BG_COLOR_VAR, color); 28 setCssVar(HEADER_BG_COLOR_VAR, color);
23 29
24 // hover color 30 // hover color
25 - const hoverColor = lighten(color, 6); 31 + const hoverColor = lighten(color!, 6);
26 setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor); 32 setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
27 setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor); 33 setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
28 34
29 // Determine the depth of the color value and automatically switch the theme 35 // Determine the depth of the color value and automatically switch the theme
30 - const isDark = colorIsDark(color); 36 + const isDark = colorIsDark(color!);
31 37
32 appStore.commitProjectConfigState({ 38 appStore.commitProjectConfigState({
33 headerSetting: { 39 headerSetting: {
34 - theme: isDark ? ThemeEnum.DARK : ThemeEnum.LIGHT, 40 + theme: isDark || darkMode ? ThemeEnum.DARK : ThemeEnum.LIGHT,
35 }, 41 },
36 }); 42 });
37 } 43 }
@@ -40,21 +46,27 @@ export function updateHeaderBgColor(color: string) { @@ -40,21 +46,27 @@ export function updateHeaderBgColor(color: string) {
40 * Change the background color of the left menu 46 * Change the background color of the left menu
41 * @param color bg color 47 * @param color bg color
42 */ 48 */
43 -export function updateSidebarBgColor(color: string) {  
44 - if (!isHexColor(color)) return;  
45 - 49 +export function updateSidebarBgColor(color?: string) {
  50 + // if (!isHexColor(color)) return;
  51 + const darkMode = appStore.getDarkMode === ThemeEnum.DARK;
  52 + if (!color) {
  53 + if (darkMode) {
  54 + color = '#212121';
  55 + } else {
  56 + color = appStore.getProjectConfig.menuSetting.bgColor;
  57 + }
  58 + }
46 setCssVar(SIDER_DARK_BG_COLOR, color); 59 setCssVar(SIDER_DARK_BG_COLOR, color);
47 - setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color, 6));  
48 - setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 5));  
49 - setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8)); 60 + setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color!, 6));
  61 + setCssVar(SIDER_LIGHTEN_BG_COLOR, lighten(color!, 5));
50 62
51 // only #ffffff is light 63 // only #ffffff is light
52 // Only when the background color is #fff, the theme of the menu will be changed to light 64 // Only when the background color is #fff, the theme of the menu will be changed to light
53 - const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase()); 65 + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase());
54 66
55 appStore.commitProjectConfigState({ 67 appStore.commitProjectConfigState({
56 menuSetting: { 68 menuSetting: {
57 - theme: isLight ? ThemeEnum.LIGHT : ThemeEnum.DARK, 69 + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK,
58 }, 70 },
59 }); 71 });
60 } 72 }
src/router/menus/modules/demo/charts.ts
@@ -22,11 +22,6 @@ const menu: MenuModule = { @@ -22,11 +22,6 @@ const menu: MenuModule = {
22 name: t('routes.demo.charts.googleMap'), 22 name: t('routes.demo.charts.googleMap'),
23 }, 23 },
24 { 24 {
25 - path: 'apexChart',  
26 - name: t('routes.demo.charts.apexChart'),  
27 - },  
28 -  
29 - {  
30 path: 'echarts', 25 path: 'echarts',
31 name: 'Echarts', 26 name: 'Echarts',
32 children: [ 27 children: [
src/router/routes/modules/demo/charts.ts
@@ -39,14 +39,6 @@ const charts: AppRouteModule = { @@ -39,14 +39,6 @@ const charts: AppRouteModule = {
39 }, 39 },
40 40
41 { 41 {
42 - path: 'apexChart',  
43 - name: 'ApexChart',  
44 - meta: {  
45 - title: t('routes.demo.charts.apexChart'),  
46 - },  
47 - component: () => import('/@/views/demo/charts/apex/index.vue'),  
48 - },  
49 - {  
50 path: 'echarts', 42 path: 'echarts',
51 name: 'Echarts', 43 name: 'Echarts',
52 component: getParentLayout('Echarts'), 44 component: getParentLayout('Echarts'),
src/settings/designSetting.ts
  1 +import { ThemeEnum } from '../enums/appEnum';
1 export default { 2 export default {
2 prefixCls: 'vben', 3 prefixCls: 'vben',
3 }; 4 };
4 5
  6 +export const darkMode = ThemeEnum.LIGHT;
  7 +
5 // app theme preset color 8 // app theme preset color
6 export const APP_PRESET_COLOR_LIST: string[] = [ 9 export const APP_PRESET_COLOR_LIST: string[] = [
7 '#0960bd', 10 '#0960bd',
@@ -18,6 +21,7 @@ export const APP_PRESET_COLOR_LIST: string[] = [ @@ -18,6 +21,7 @@ export const APP_PRESET_COLOR_LIST: string[] = [
18 // header preset color 21 // header preset color
19 export const HEADER_PRESET_BG_COLOR_LIST: string[] = [ 22 export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
20 '#ffffff', 23 '#ffffff',
  24 + '#151515',
21 '#009688', 25 '#009688',
22 '#5172DC', 26 '#5172DC',
23 '#018ffb', 27 '#018ffb',
@@ -32,6 +36,7 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [ @@ -32,6 +36,7 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
32 // sider preset color 36 // sider preset color
33 export const SIDE_BAR_BG_COLOR_LIST: string[] = [ 37 export const SIDE_BAR_BG_COLOR_LIST: string[] = [
34 '#001529', 38 '#001529',
  39 + '#212121',
35 '#273352', 40 '#273352',
36 '#ffffff', 41 '#ffffff',
37 '#191b24', 42 '#191b24',
src/settings/projectSetting.ts
@@ -9,13 +9,16 @@ import { @@ -9,13 +9,16 @@ import {
9 SettingButtonPositionEnum, 9 SettingButtonPositionEnum,
10 } from '/@/enums/appEnum'; 10 } from '/@/enums/appEnum';
11 import { SIDE_BAR_BG_COLOR_LIST, HEADER_PRESET_BG_COLOR_LIST } from './designSetting'; 11 import { SIDE_BAR_BG_COLOR_LIST, HEADER_PRESET_BG_COLOR_LIST } from './designSetting';
12 -import { primaryColor, themeMode } from '../../build/config/themeConfig'; 12 +import { primaryColor } from '../../build/config/themeConfig';
13 13
14 // ! You need to clear the browser cache after the change 14 // ! You need to clear the browser cache after the change
15 const setting: ProjectConfig = { 15 const setting: ProjectConfig = {
16 // Whether to show the configuration button 16 // Whether to show the configuration button
17 showSettingButton: true, 17 showSettingButton: true,
18 18
  19 + // Whether to show the theme switch button
  20 + showDarkModeToggle: true,
  21 +
19 // `Settings` button position 22 // `Settings` button position
20 settingButtonPosition: SettingButtonPositionEnum.AUTO, 23 settingButtonPosition: SettingButtonPositionEnum.AUTO,
21 24
@@ -28,9 +31,6 @@ const setting: ProjectConfig = { @@ -28,9 +31,6 @@ const setting: ProjectConfig = {
28 // color 31 // color
29 themeColor: primaryColor, 32 themeColor: primaryColor,
30 33
31 - // TODO dark theme  
32 - themeMode: themeMode,  
33 -  
34 // Website gray mode, open for possible mourning dates 34 // Website gray mode, open for possible mourning dates
35 grayMode: false, 35 grayMode: false,
36 36
src/store/modules/app.ts
@@ -4,13 +4,16 @@ import type { BeforeMiniState } from &#39;../types&#39;; @@ -4,13 +4,16 @@ import type { BeforeMiniState } from &#39;../types&#39;;
4 import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'; 4 import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
5 import store from '/@/store'; 5 import store from '/@/store';
6 6
7 -import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; 7 +import { PROJ_CFG_KEY, APP_DARK_MODE_KEY_ } from '/@/enums/cacheEnum';
8 8
9 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; 9 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
10 import { Persistent } from '/@/utils/cache/persistent'; 10 import { Persistent } from '/@/utils/cache/persistent';
11 import { deepMerge } from '/@/utils'; 11 import { deepMerge } from '/@/utils';
12 12
13 import { resetRouter } from '/@/router'; 13 import { resetRouter } from '/@/router';
  14 +import { ThemeEnum } from '../../enums/appEnum';
  15 +
  16 +import { darkMode } from '/@/settings/designSetting';
14 17
15 export interface LockInfo { 18 export interface LockInfo {
16 pwd: string | undefined; 19 pwd: string | undefined;
@@ -22,6 +25,8 @@ const NAME = &#39;app&#39;; @@ -22,6 +25,8 @@ const NAME = &#39;app&#39;;
22 hotModuleUnregisterModule(NAME); 25 hotModuleUnregisterModule(NAME);
23 @Module({ dynamic: true, namespaced: true, store, name: NAME }) 26 @Module({ dynamic: true, namespaced: true, store, name: NAME })
24 export default class App extends VuexModule { 27 export default class App extends VuexModule {
  28 + private darkMode;
  29 +
25 // Page loading status 30 // Page loading status
26 private pageLoadingState = false; 31 private pageLoadingState = false;
27 32
@@ -38,6 +43,10 @@ export default class App extends VuexModule { @@ -38,6 +43,10 @@ export default class App extends VuexModule {
38 return this.pageLoadingState; 43 return this.pageLoadingState;
39 } 44 }
40 45
  46 + get getDarkMode() {
  47 + return this.darkMode || localStorage.getItem(APP_DARK_MODE_KEY_) || darkMode;
  48 + }
  49 +
41 get getBeforeMiniState() { 50 get getBeforeMiniState() {
42 return this.beforeMiniState; 51 return this.beforeMiniState;
43 } 52 }
@@ -56,6 +65,12 @@ export default class App extends VuexModule { @@ -56,6 +65,12 @@ export default class App extends VuexModule {
56 } 65 }
57 66
58 @Mutation 67 @Mutation
  68 + commitDarkMode(mode: ThemeEnum): void {
  69 + this.darkMode = mode;
  70 + localStorage.setItem(APP_DARK_MODE_KEY_, mode);
  71 + }
  72 +
  73 + @Mutation
59 commitBeforeMiniState(state: BeforeMiniState): void { 74 commitBeforeMiniState(state: BeforeMiniState): void {
60 this.beforeMiniState = state; 75 this.beforeMiniState = state;
61 } 76 }
src/views/dashboard/analysis/components/VisitRadar.vue
@@ -32,7 +32,6 @@ @@ -32,7 +32,6 @@
32 return; 32 return;
33 } 33 }
34 setOptions({ 34 setOptions({
35 - backgroundColor: '#fff',  
36 legend: { 35 legend: {
37 bottom: 0, 36 bottom: 0,
38 data: ['访问', '购买'], 37 data: ['访问', '购买'],
src/views/dashboard/workbench/components/SaleRadar.vue
@@ -32,7 +32,6 @@ @@ -32,7 +32,6 @@
32 return; 32 return;
33 } 33 }
34 setOptions({ 34 setOptions({
35 - backgroundColor: '#fff',  
36 legend: { 35 legend: {
37 bottom: 0, 36 bottom: 0,
38 data: ['Visits', 'Sales'], 37 data: ['Visits', 'Sales'],
src/views/demo/charts/SaleRadar.vue
@@ -32,7 +32,6 @@ @@ -32,7 +32,6 @@
32 return; 32 return;
33 } 33 }
34 setOptions({ 34 setOptions({
35 - backgroundColor: '#fff',  
36 legend: { 35 legend: {
37 bottom: 0, 36 bottom: 0,
38 data: ['Visits', 'Sales'], 37 data: ['Visits', 'Sales'],
src/views/demo/charts/apex/Area.vue deleted 100644 → 0
1 -<template>  
2 - <div ref="chartRef" :style="{ width: '100%' }"></div>  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent, ref, Ref, onMounted } from 'vue';  
6 -  
7 - import { useApexCharts } from '/@/hooks/web/useApexCharts';  
8 -  
9 - export default defineComponent({  
10 - setup() {  
11 - const chartRef = ref<HTMLDivElement | null>(null);  
12 - const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);  
13 -  
14 - onMounted(() => {  
15 - setOptions({  
16 - series: [  
17 - {  
18 - name: 'series1',  
19 - data: [31, 40, 28, 51, 42, 109, 100],  
20 - },  
21 - {  
22 - name: 'series2',  
23 - data: [11, 32, 45, 32, 34, 52, 41],  
24 - },  
25 - ],  
26 - chart: {  
27 - height: 350,  
28 - type: 'area',  
29 - },  
30 - dataLabels: {  
31 - enabled: false,  
32 - },  
33 - stroke: {  
34 - curve: 'smooth',  
35 - },  
36 - xaxis: {  
37 - type: 'datetime',  
38 - categories: [  
39 - '2018-09-19T00:00:00.000Z',  
40 - '2018-09-19T01:30:00.000Z',  
41 - '2018-09-19T02:30:00.000Z',  
42 - '2018-09-19T03:30:00.000Z',  
43 - '2018-09-19T04:30:00.000Z',  
44 - '2018-09-19T05:30:00.000Z',  
45 - '2018-09-19T06:30:00.000Z',  
46 - ],  
47 - },  
48 - tooltip: {  
49 - x: {  
50 - format: 'dd/MM/yy HH:mm',  
51 - },  
52 - },  
53 - });  
54 - });  
55 - return { chartRef };  
56 - },  
57 - });  
58 -</script>  
src/views/demo/charts/apex/Bar.vue deleted 100644 → 0
1 -<template>  
2 - <div ref="chartRef" :style="{ width: '100%' }"></div>  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent, ref, Ref, onMounted } from 'vue';  
6 -  
7 - import { useApexCharts } from '/@/hooks/web/useApexCharts';  
8 -  
9 - export default defineComponent({  
10 - setup() {  
11 - const chartRef = ref<HTMLDivElement | null>(null);  
12 - const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);  
13 -  
14 - onMounted(() => {  
15 - setOptions({  
16 - series: [  
17 - {  
18 - data: [400, 430, 448, 470, 540, 580, 690, 1100, 1200, 1380],  
19 - },  
20 - ],  
21 - chart: {  
22 - type: 'bar',  
23 - height: 350,  
24 - },  
25 - plotOptions: {  
26 - bar: {  
27 - horizontal: true,  
28 - },  
29 - },  
30 - dataLabels: {  
31 - enabled: false,  
32 - },  
33 - xaxis: {  
34 - categories: [  
35 - 'South Korea',  
36 - 'Canada',  
37 - 'United Kingdom',  
38 - 'Netherlands',  
39 - 'Italy',  
40 - 'France',  
41 - 'Japan',  
42 - 'United States',  
43 - 'China',  
44 - 'Germany',  
45 - ],  
46 - },  
47 - });  
48 - });  
49 - return { chartRef };  
50 - },  
51 - });  
52 -</script>  
src/views/demo/charts/apex/Line.vue deleted 100644 → 0
1 -<template>  
2 - <div ref="chartRef" :style="{ width: '100%' }"></div>  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent, ref, Ref, onMounted } from 'vue';  
6 -  
7 - import { useApexCharts } from '/@/hooks/web/useApexCharts';  
8 -  
9 - export default defineComponent({  
10 - setup() {  
11 - const chartRef = ref<HTMLDivElement | null>(null);  
12 - const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);  
13 -  
14 - onMounted(() => {  
15 - setOptions({  
16 - series: [  
17 - {  
18 - name: 'Desktops',  
19 - data: [10, 41, 35, 51, 49, 62, 69, 91, 148],  
20 - },  
21 - ],  
22 - chart: {  
23 - height: 350,  
24 - type: 'line',  
25 - zoom: {  
26 - enabled: false,  
27 - },  
28 - },  
29 - dataLabels: {  
30 - enabled: false,  
31 - },  
32 - stroke: {  
33 - curve: 'straight',  
34 - },  
35 - title: {  
36 - text: 'Product Trends by Month',  
37 - align: 'left',  
38 - },  
39 - grid: {  
40 - row: {  
41 - colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns  
42 - opacity: 0.5,  
43 - },  
44 - },  
45 - xaxis: {  
46 - categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'],  
47 - },  
48 - });  
49 - });  
50 - return { chartRef };  
51 - },  
52 - });  
53 -</script>  
src/views/demo/charts/apex/Mixed.vue deleted 100644 → 0
1 -<template>  
2 - <div ref="chartRef" :style="{ width: '100%' }"></div>  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent, ref, Ref, onMounted } from 'vue';  
6 -  
7 - import { useApexCharts } from '/@/hooks/web/useApexCharts';  
8 -  
9 - export default defineComponent({  
10 - setup() {  
11 - const chartRef = ref<HTMLDivElement | null>(null);  
12 - const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);  
13 -  
14 - onMounted(() => {  
15 - setOptions({  
16 - series: [  
17 - {  
18 - name: 'Income',  
19 - type: 'column',  
20 - data: [1.4, 2, 2.5, 1.5, 2.5, 2.8, 3.8, 4.6],  
21 - },  
22 - {  
23 - name: 'Cashflow',  
24 - type: 'column',  
25 - data: [1.1, 3, 3.1, 4, 4.1, 4.9, 6.5, 8.5],  
26 - },  
27 - {  
28 - name: 'Revenue',  
29 - type: 'line',  
30 - data: [20, 29, 37, 36, 44, 45, 50, 58],  
31 - },  
32 - ],  
33 - chart: {  
34 - height: 350,  
35 - type: 'line',  
36 - stacked: false,  
37 - },  
38 - dataLabels: {  
39 - enabled: false,  
40 - },  
41 - stroke: {  
42 - width: [1, 1, 4],  
43 - },  
44 - title: {  
45 - text: 'XYZ - Stock Analysis (2009 - 2016)',  
46 - align: 'left',  
47 - offsetX: 110,  
48 - },  
49 - xaxis: {  
50 - categories: [2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016],  
51 - },  
52 - yaxis: [  
53 - {  
54 - axisTicks: {  
55 - show: true,  
56 - },  
57 - axisBorder: {  
58 - show: true,  
59 - color: '#008FFB',  
60 - },  
61 - labels: {  
62 - style: {  
63 - colors: '#008FFB',  
64 - },  
65 - },  
66 - title: {  
67 - text: 'Income (thousand crores)',  
68 - style: {  
69 - color: '#008FFB',  
70 - },  
71 - },  
72 - tooltip: {  
73 - enabled: true,  
74 - },  
75 - },  
76 - {  
77 - seriesName: 'Income',  
78 - opposite: true,  
79 - axisTicks: {  
80 - show: true,  
81 - },  
82 - axisBorder: {  
83 - show: true,  
84 - color: '#00E396',  
85 - },  
86 - labels: {  
87 - style: {  
88 - colors: '#00E396',  
89 - },  
90 - },  
91 - title: {  
92 - text: 'Operating Cashflow (thousand crores)',  
93 - style: {  
94 - color: '#00E396',  
95 - },  
96 - },  
97 - },  
98 - {  
99 - seriesName: 'Revenue',  
100 - opposite: true,  
101 - axisTicks: {  
102 - show: true,  
103 - },  
104 - axisBorder: {  
105 - show: true,  
106 - color: '#FEB019',  
107 - },  
108 - labels: {  
109 - style: {  
110 - colors: '#FEB019',  
111 - },  
112 - },  
113 - title: {  
114 - text: 'Revenue (thousand crores)',  
115 - style: {  
116 - color: '#FEB019',  
117 - },  
118 - },  
119 - },  
120 - ],  
121 - tooltip: {  
122 - fixed: {  
123 - enabled: true,  
124 - position: 'topLeft', // topRight, topLeft, bottomRight, bottomLeft  
125 - offsetY: 30,  
126 - offsetX: 60,  
127 - },  
128 - },  
129 - legend: {  
130 - horizontalAlign: 'left',  
131 - offsetX: 40,  
132 - },  
133 - });  
134 - });  
135 - return { chartRef };  
136 - },  
137 - });  
138 -</script>  
src/views/demo/charts/apex/SaleRadar.vue deleted 100644 → 0
1 -<template>  
2 - <div ref="chartRef" :style="{ width: '100%' }"></div>  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent, Ref, ref, onMounted } from 'vue';  
6 -  
7 - import { useApexCharts } from '/@/hooks/web/useApexCharts';  
8 -  
9 - export default defineComponent({  
10 - setup() {  
11 - const chartRef = ref<HTMLDivElement | null>(null);  
12 - const { setOptions } = useApexCharts(chartRef as Ref<HTMLDivElement>);  
13 - onMounted(() => {  
14 - setOptions({  
15 - series: [  
16 - { name: 'Visits', data: [90, 50, 86, 40, 100, 20] },  
17 - { name: 'Sales', data: [70, 75, 70, 76, 20, 85] },  
18 - ],  
19 - chart: {  
20 - height: 350,  
21 - type: 'radar',  
22 - toolbar: {  
23 - show: false,  
24 - },  
25 - },  
26 - yaxis: {  
27 - show: false,  
28 - },  
29 -  
30 - title: {  
31 - show: false,  
32 - },  
33 - markers: {  
34 - // size: 0,  
35 - },  
36 - xaxis: {  
37 - categories: ['2016', '2017', '2018', '2019', '2020', '2021'],  
38 - },  
39 - stroke: {  
40 - width: 0,  
41 - },  
42 - colors: ['#9f8ed7', '#1edec5'],  
43 -  
44 - fill: {  
45 - type: 'gradient',  
46 - gradient: {  
47 - shade: 'dark',  
48 - gradientToColors: ['#8e9ad6', '#1fcadb'],  
49 - shadeIntensity: 1,  
50 - type: 'horizontal',  
51 - opacityFrom: 1,  
52 - opacityTo: 1,  
53 - stops: [0, 100, 100, 100],  
54 - },  
55 - },  
56 - });  
57 - });  
58 - return { chartRef };  
59 - },  
60 - });  
61 -</script>  
src/views/demo/charts/apex/index.vue deleted 100644 → 0
1 -<template>  
2 - <div class="apex-demo p-4">  
3 - <div class="demo-box">  
4 - <Line />  
5 - </div>  
6 - <div class="demo-box">  
7 - <Bar />  
8 - </div>  
9 - <div class="demo-box">  
10 - <Area />  
11 - </div>  
12 - <div class="demo-box">  
13 - <Mixed />  
14 - </div>  
15 - <div class="demo-box">  
16 - <SaleRadar />  
17 - </div>  
18 - </div>  
19 -</template>  
20 -<script>  
21 - import { defineComponent } from 'vue';  
22 -  
23 - import Line from './Line.vue';  
24 - import Bar from './Bar.vue';  
25 - import Area from './Area.vue';  
26 - import Mixed from './Mixed.vue';  
27 - import SaleRadar from './SaleRadar.vue';  
28 - export default defineComponent({  
29 - components: { Line, Bar, Area, Mixed, SaleRadar },  
30 - setup() {},  
31 - });  
32 -</script>  
33 -<style lang="less" scoped>  
34 - .apex-demo {  
35 - display: flex;  
36 - flex-wrap: wrap;  
37 - justify-content: space-between;  
38 -  
39 - .demo-box {  
40 - width: 49%;  
41 - margin-bottom: 20px;  
42 - background: #fff;  
43 - border-radius: 10px;  
44 - }  
45 - }  
46 -</style>  
src/views/demo/comp/lazy/Transition.vue
@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 height: 2000px; 29 height: 2000px;
30 margin: 20px auto; 30 margin: 20px auto;
31 text-align: center; 31 text-align: center;
32 - background: #fff; 32 + background: @component-background;
33 justify-content: center; 33 justify-content: center;
34 flex-direction: column; 34 flex-direction: column;
35 align-items: center; 35 align-items: center;
src/views/demo/comp/lazy/index.vue
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 height: 2000px; 33 height: 2000px;
34 margin: 20px auto; 34 margin: 20px auto;
35 text-align: center; 35 text-align: center;
36 - background: #fff; 36 + background: @component-background;
37 justify-content: center; 37 justify-content: center;
38 flex-direction: column; 38 flex-direction: column;
39 align-items: center; 39 align-items: center;
src/views/demo/comp/scroll/Action.vue
@@ -54,6 +54,6 @@ @@ -54,6 +54,6 @@
54 .scroll-wrap { 54 .scroll-wrap {
55 width: 50%; 55 width: 50%;
56 height: 300px; 56 height: 300px;
57 - background: #fff; 57 + background: @component-background;
58 } 58 }
59 </style> 59 </style>
src/views/demo/comp/scroll/VirtualScroll.vue
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 &-wrap { 50 &-wrap {
51 display: flex; 51 display: flex;
52 margin: 0 30%; 52 margin: 0 30%;
53 - background: #fff; 53 + background: @component-background;
54 justify-content: center; 54 justify-content: center;
55 } 55 }
56 56
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 height: 40px; 58 height: 40px;
59 padding: 0 20px; 59 padding: 0 20px;
60 line-height: 40px; 60 line-height: 40px;
61 - border-bottom: 1px solid #ddd; 61 + border-bottom: 1px solid @border-color-base;
62 } 62 }
63 } 63 }
64 </style> 64 </style>
src/views/demo/comp/scroll/index.vue
@@ -26,6 +26,6 @@ @@ -26,6 +26,6 @@
26 .scroll-wrap { 26 .scroll-wrap {
27 width: 50%; 27 width: 50%;
28 height: 300px; 28 height: 300px;
29 - background: #fff; 29 + background: @component-background;
30 } 30 }
31 </style> 31 </style>
src/views/demo/comp/strength-meter/index.vue
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 <style lang="less" scoped> 26 <style lang="less" scoped>
27 .demo-wrap { 27 .demo-wrap {
28 width: 50%; 28 width: 50%;
29 - background: #fff; 29 + background: @component-background;
30 border-radius: 10px; 30 border-radius: 10px;
31 } 31 }
32 </style> 32 </style>
src/views/demo/feat/tab-params/index.vue
@@ -3,17 +3,18 @@ @@ -3,17 +3,18 @@
3 Current Param : {{ params }} 3 Current Param : {{ params }}
4 <br /> 4 <br />
5 Keep Alive 5 Keep Alive
6 - <input /> 6 + <Input />
7 </PageWrapper> 7 </PageWrapper>
8 </template> 8 </template>
9 <script lang="ts"> 9 <script lang="ts">
10 import { computed, defineComponent, unref } from 'vue'; 10 import { computed, defineComponent, unref } from 'vue';
11 import { useRouter } from 'vue-router'; 11 import { useRouter } from 'vue-router';
12 import { PageWrapper } from '/@/components/Page'; 12 import { PageWrapper } from '/@/components/Page';
  13 + import { Input } from 'ant-design-vue';
13 14
14 export default defineComponent({ 15 export default defineComponent({
15 name: 'TestTab', 16 name: 'TestTab',
16 - components: { PageWrapper }, 17 + components: { PageWrapper, Input },
17 setup() { 18 setup() {
18 const { currentRoute } = useRouter(); 19 const { currentRoute } = useRouter();
19 return { 20 return {
src/views/demo/level/Menu111.vue
@@ -2,10 +2,11 @@ @@ -2,10 +2,11 @@
2 <div class="p-5"> 2 <div class="p-5">
3 多层级缓存-页面1-1-1 3 多层级缓存-页面1-1-1
4 <br /> 4 <br />
5 - <input /> 5 + <Input />
6 </div> 6 </div>
7 </template> 7 </template>
8 <script lang="ts"> 8 <script lang="ts">
9 import { defineComponent } from 'vue'; 9 import { defineComponent } from 'vue';
10 - export default defineComponent({ name: 'Menu111Demo' }); 10 + import { Input } from 'ant-design-vue';
  11 + export default defineComponent({ name: 'Menu111Demo', components: { Input } });
11 </script> 12 </script>
src/views/demo/level/Menu12.vue
@@ -2,10 +2,11 @@ @@ -2,10 +2,11 @@
2 <div class="p-5"> 2 <div class="p-5">
3 多层级缓存-页面1-2 3 多层级缓存-页面1-2
4 <br /> 4 <br />
5 - <input /> 5 + <Input />
6 </div> 6 </div>
7 </template> 7 </template>
8 <script lang="ts"> 8 <script lang="ts">
9 import { defineComponent } from 'vue'; 9 import { defineComponent } from 'vue';
10 - export default defineComponent({ name: 'Menu12Demo' }); 10 + import { Input } from 'ant-design-vue';
  11 + export default defineComponent({ name: 'Menu12Demo', components: { Input } });
11 </script> 12 </script>
src/views/demo/level/Menu2.vue
@@ -2,12 +2,14 @@ @@ -2,12 +2,14 @@
2 <div class="p-5"> 2 <div class="p-5">
3 多层级缓存-页面2 3 多层级缓存-页面2
4 <br /> 4 <br />
5 - <input /> 5 + <Input />
6 </div> 6 </div>
7 </template> 7 </template>
8 <script lang="ts"> 8 <script lang="ts">
9 import { defineComponent } from 'vue'; 9 import { defineComponent } from 'vue';
  10 + import { Input } from 'ant-design-vue';
10 export default defineComponent({ 11 export default defineComponent({
11 name: 'Menu2Demo', 12 name: 'Menu2Demo',
  13 + components: { Input },
12 }); 14 });
13 </script> 15 </script>
src/views/demo/page/account/center/Application.vue
@@ -64,7 +64,6 @@ @@ -64,7 +64,6 @@
64 margin-bottom: 5px; 64 margin-bottom: 5px;
65 font-size: 16px; 65 font-size: 16px;
66 font-weight: 500; 66 font-weight: 500;
67 - color: rgba(0, 0, 0, 0.85);  
68 67
69 .icon { 68 .icon {
70 margin-top: -5px; 69 margin-top: -5px;
@@ -75,19 +74,18 @@ @@ -75,19 +74,18 @@
75 &-num { 74 &-num {
76 margin-left: 24px; 75 margin-left: 24px;
77 line-height: 36px; 76 line-height: 36px;
78 - color: #7d7a7a; 77 + color: @text-color-secondary;
79 78
80 span { 79 span {
81 margin-left: 5px; 80 margin-left: 5px;
82 font-size: 18px; 81 font-size: 18px;
83 - color: #000;  
84 } 82 }
85 } 83 }
86 84
87 &-download { 85 &-download {
88 float: right; 86 float: right;
89 font-size: 20px !important; 87 font-size: 20px !important;
90 - color: #1890ff; 88 + color: @primary-color;
91 } 89 }
92 } 90 }
93 } 91 }
src/views/demo/page/account/center/index.vue
@@ -102,7 +102,7 @@ @@ -102,7 +102,7 @@
102 &-top { 102 &-top {
103 padding: 10px; 103 padding: 10px;
104 margin: 16px 16px 12px 16px; 104 margin: 16px 16px 12px 16px;
105 - background: #fff; 105 + background: @component-background;
106 border-radius: 3px; 106 border-radius: 3px;
107 107
108 &__avatar { 108 &__avatar {
@@ -144,7 +144,7 @@ @@ -144,7 +144,7 @@
144 &-bottom { 144 &-bottom {
145 padding: 10px; 145 padding: 10px;
146 margin: 0 16px 16px 16px; 146 margin: 0 16px 16px 16px;
147 - background: #fff; 147 + background: @component-background;
148 border-radius: 3px; 148 border-radius: 3px;
149 } 149 }
150 } 150 }
src/views/demo/page/account/setting/index.vue
@@ -48,14 +48,14 @@ @@ -48,14 +48,14 @@
48 <style lang="less"> 48 <style lang="less">
49 .account-setting { 49 .account-setting {
50 margin: 12px; 50 margin: 12px;
51 - background: #fff; 51 + background: @component-background;
52 52
53 .base-title { 53 .base-title {
54 padding-left: 0; 54 padding-left: 0;
55 } 55 }
56 56
57 .ant-tabs-tab-active { 57 .ant-tabs-tab-active {
58 - background-color: #e6f7ff; 58 + background-color: @item-active-bg;
59 } 59 }
60 } 60 }
61 </style> 61 </style>
src/views/demo/page/desc/basic/index.vue
@@ -93,6 +93,6 @@ @@ -93,6 +93,6 @@
93 <style lang="less" scoped> 93 <style lang="less" scoped>
94 .desc-wrap { 94 .desc-wrap {
95 padding: 16px; 95 padding: 16px;
96 - background: #fff; 96 + background: @component-background;
97 } 97 }
98 </style> 98 </style>
src/views/demo/page/form/basic/index.vue
@@ -62,6 +62,6 @@ @@ -62,6 +62,6 @@
62 <style lang="less" scoped> 62 <style lang="less" scoped>
63 .form-wrap { 63 .form-wrap {
64 padding: 24px; 64 padding: 24px;
65 - background: #fff; 65 + background: @component-background;
66 } 66 }
67 </style> 67 </style>
src/views/demo/page/form/step/Step1.vue
@@ -78,18 +78,18 @@ @@ -78,18 +78,18 @@
78 margin: 0 0 12px; 78 margin: 0 0 12px;
79 font-size: 16px; 79 font-size: 16px;
80 line-height: 32px; 80 line-height: 32px;
81 - color: rgba(0, 0, 0, 0.45); 81 + color: @text-color;
82 } 82 }
83 83
84 h4 { 84 h4 {
85 margin: 0 0 4px; 85 margin: 0 0 4px;
86 font-size: 14px; 86 font-size: 14px;
87 line-height: 22px; 87 line-height: 22px;
88 - color: rgba(0, 0, 0, 0.45); 88 + color: @text-color;
89 } 89 }
90 90
91 p { 91 p {
92 - color: rgba(0, 0, 0, 0.45); 92 + color: @text-color;
93 } 93 }
94 } 94 }
95 95
src/views/demo/page/form/step/Step3.vue
@@ -44,6 +44,6 @@ @@ -44,6 +44,6 @@
44 .desc-wrap { 44 .desc-wrap {
45 padding: 24px 40px; 45 padding: 24px 40px;
46 margin-top: 24px; 46 margin-top: 24px;
47 - background: #fafafa; 47 + background: @background-color-light;
48 } 48 }
49 </style> 49 </style>
src/views/demo/page/form/step/index.vue
@@ -85,7 +85,7 @@ @@ -85,7 +85,7 @@
85 <style lang="less" scoped> 85 <style lang="less" scoped>
86 .step-form-content { 86 .step-form-content {
87 padding: 24px; 87 padding: 24px;
88 - background: #fff; 88 + background: @component-background;
89 } 89 }
90 90
91 .step-form-form { 91 .step-form-form {
src/views/demo/page/list/basic/index.vue
@@ -86,25 +86,25 @@ @@ -86,25 +86,25 @@
86 &__top { 86 &__top {
87 padding: 24px; 87 padding: 24px;
88 text-align: center; 88 text-align: center;
89 - background: #fff; 89 + background: @component-background;
90 90
91 &-col { 91 &-col {
92 &:not(:last-child) { 92 &:not(:last-child) {
93 - border-right: 1px dashed rgba(206, 206, 206, 0.4); 93 + border-right: 1px dashed @border-color-base;
94 } 94 }
95 95
96 div { 96 div {
97 margin-bottom: 12px; 97 margin-bottom: 12px;
98 font-size: 14px; 98 font-size: 14px;
99 line-height: 22px; 99 line-height: 22px;
100 - color: rgba(0, 0, 0, 0.45); 100 + color: @text-color;
101 } 101 }
102 102
103 p { 103 p {
104 margin: 0; 104 margin: 0;
105 font-size: 24px; 105 font-size: 24px;
106 line-height: 32px; 106 line-height: 32px;
107 - color: rgba(0, 0, 0, 0.85); 107 + color: @text-color;
108 } 108 }
109 } 109 }
110 } 110 }
@@ -112,7 +112,7 @@ @@ -112,7 +112,7 @@
112 &__content { 112 &__content {
113 padding: 24px; 113 padding: 24px;
114 margin-top: 12px; 114 margin-top: 12px;
115 - background: #fff; 115 + background: @component-background;
116 116
117 .list { 117 .list {
118 position: relative; 118 position: relative;
@@ -127,7 +127,7 @@ @@ -127,7 +127,7 @@
127 top: 20px; 127 top: 20px;
128 right: 15px; 128 right: 15px;
129 font-weight: normal; 129 font-weight: normal;
130 - color: #1890ff; 130 + color: @primary-color;
131 cursor: pointer; 131 cursor: pointer;
132 } 132 }
133 133
src/views/demo/page/list/card/index.vue
@@ -84,7 +84,7 @@ @@ -84,7 +84,7 @@
84 margin-bottom: 5px; 84 margin-bottom: 5px;
85 font-size: 16px; 85 font-size: 16px;
86 font-weight: 500; 86 font-weight: 500;
87 - color: rgba(0, 0, 0, 0.85); 87 + color: @text-color;
88 88
89 .icon { 89 .icon {
90 margin-top: -5px; 90 margin-top: -5px;
@@ -97,7 +97,7 @@ @@ -97,7 +97,7 @@
97 padding-top: 10px; 97 padding-top: 10px;
98 padding-left: 30px; 98 padding-left: 30px;
99 font-size: 14px; 99 font-size: 14px;
100 - color: rgba(0, 0, 0, 0.5); 100 + color: @text-color-secondary;
101 } 101 }
102 } 102 }
103 } 103 }
src/views/demo/page/list/search/index.vue
@@ -91,7 +91,7 @@ @@ -91,7 +91,7 @@
91 91
92 &__container { 92 &__container {
93 padding: 12px; 93 padding: 12px;
94 - background: #fff; 94 + background: @component-background;
95 } 95 }
96 96
97 &__title { 97 &__title {
@@ -100,7 +100,7 @@ @@ -100,7 +100,7 @@
100 } 100 }
101 101
102 &__content { 102 &__content {
103 - color: rgba(0, 0, 0, 0.65); 103 + color: @text-color-secondary;
104 } 104 }
105 105
106 &__action { 106 &__action {
@@ -109,7 +109,7 @@ @@ -109,7 +109,7 @@
109 &-item { 109 &-item {
110 display: inline-block; 110 display: inline-block;
111 padding: 0 16px; 111 padding: 0 16px;
112 - color: rgba(0, 0, 0, 0.45); 112 + color: @text-color-secondary;
113 113
114 &:nth-child(1) { 114 &:nth-child(1) {
115 padding-left: 0; 115 padding-left: 0;
@@ -117,7 +117,7 @@ @@ -117,7 +117,7 @@
117 117
118 &:nth-child(1), 118 &:nth-child(1),
119 &:nth-child(2) { 119 &:nth-child(2) {
120 - border-right: 1px solid rgba(206, 206, 206, 0.4); 120 + border-right: 1px solid @border-color-base;
121 } 121 }
122 } 122 }
123 123
src/views/demo/page/result/fail/index.vue
@@ -34,17 +34,16 @@ @@ -34,17 +34,16 @@
34 <style lang="less" scoped> 34 <style lang="less" scoped>
35 .result-error { 35 .result-error {
36 padding: 48px 32px; 36 padding: 48px 32px;
37 - background: #fff; 37 + background: @component-background;
38 38
39 &__content { 39 &__content {
40 padding: 24px 40px; 40 padding: 24px 40px;
41 - background: #fafafa; 41 + background: @background-color-light;
42 42
43 &-title { 43 &-title {
44 margin-bottom: 16px; 44 margin-bottom: 16px;
45 font-size: 16px; 45 font-size: 16px;
46 font-weight: 500; 46 font-weight: 500;
47 - color: rgba(0, 0, 0, 0.85);  
48 } 47 }
49 48
50 &-icon { 49 &-icon {
src/views/demo/page/result/success/index.vue
@@ -48,11 +48,11 @@ @@ -48,11 +48,11 @@
48 <style lang="less" scoped> 48 <style lang="less" scoped>
49 .result-success { 49 .result-success {
50 padding: 48px 32px; 50 padding: 48px 32px;
51 - background: #fff; 51 + background: @component-background;
52 52
53 &__content { 53 &__content {
54 padding: 24px 40px; 54 padding: 24px 40px;
55 - background: #fafafa; 55 + background: @background-color-light;
56 } 56 }
57 } 57 }
58 </style> 58 </style>
src/views/demo/permission/back/Btn.vue
@@ -83,6 +83,6 @@ @@ -83,6 +83,6 @@
83 </script> 83 </script>
84 <style lang="less" scoped> 84 <style lang="less" scoped>
85 .demo { 85 .demo {
86 - background: #fff; 86 + background: @component-background;
87 } 87 }
88 </style> 88 </style>
src/views/demo/permission/back/index.vue
@@ -38,6 +38,6 @@ @@ -38,6 +38,6 @@
38 </script> 38 </script>
39 <style lang="less" scoped> 39 <style lang="less" scoped>
40 .demo { 40 .demo {
41 - background: #fff; 41 + background: @component-background;
42 } 42 }
43 </style> 43 </style>