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 11 - 移除 useFullScreen 函数
12 12 - tinymce 由 Cdn 改为 npm(打包体积偏大)
13 13 - Dashboard 重构
  14 +- 移除 ApexCharts 及示例
14 15  
15 16 ### 🐛 Bug Fixes
16 17  
... ...
build/config/themeConfig.ts
... ... @@ -2,11 +2,7 @@ import { generate } from '@ant-design/colors';
2 2  
3 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 7 type Fn = (...arg: any) => any;
12 8  
... ... @@ -17,18 +13,17 @@ export interface GenerateColorsParams {
17 13 color?: string;
18 14 }
19 15  
20   -export function generateAntColors(color: string, mode: ThemeMode) {
  16 +export function generateAntColors(color: string) {
21 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 23 const tc = color || primaryColor;
28   - const tm = theme || themeMode;
29   - const colors = generateAntColors(tc, tm);
  24 + const colors = generateAntColors(tc);
30 25 const primary = colors[5];
31   - const modeColors = generateAntColors(primary, tm === 'dark' ? 'light' : 'dark');
  26 + const modeColors = generateAntColors(primary);
32 27  
33 28 return [...colors, ...modeColors];
34 29 }
... ... @@ -71,36 +66,3 @@ export function generateColors({
71 66 .filter((item) => item !== '#000000');
72 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 62 vitePlugins.push(configVisualizerConfig());
63 63  
64 64 //vite-plugin-theme
65   - vitePlugins.push(configThemePlugin());
  65 + vitePlugins.push(configThemePlugin(isBuild));
66 66  
67 67 // The following plugins only work in the production environment
68 68 if (isBuild) {
... ...
build/vite/plugin/theme.ts
... ... @@ -2,18 +2,50 @@
2 2 * Vite plugin for website theme color switching
3 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 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 17 const colors = generateColors({
10 18 mixDarken,
11 19 mixLighten,
12 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 1 <!DOCTYPE html>
2   -<html lang="en">
  2 +<html lang="en" id="htmlRoot">
3 3 <head>
4 4 <meta charset="UTF-8" />
5 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
... ... @@ -13,8 +13,24 @@
13 13 <link rel="icon" href="/favicon.ico" />
14 14 </head>
15 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 24 <div id="app">
17 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 34 .app-loading {
19 35 display: flex;
20 36 width: 100%;
... ...
package.json
... ... @@ -35,7 +35,6 @@
35 35 "@vueuse/core": "^4.7.0",
36 36 "@zxcvbn-ts/core": "^0.3.0",
37 37 "ant-design-vue": "^2.1.2",
38   - "apexcharts": "^3.26.0",
39 38 "axios": "^0.21.1",
40 39 "cropperjs": "^1.5.11",
41 40 "crypto-js": "^4.0.0",
... ... @@ -51,7 +50,7 @@
51 50 "vditor": "^3.8.4",
52 51 "vue": "3.0.11",
53 52 "vue-i18n": "^9.0.0",
54   - "vue-router": "^4.0.5",
  53 + "vue-router": "^4.0.6",
55 54 "vue-types": "^3.0.2",
56 55 "vuex": "^4.0.0",
57 56 "vuex-module-decorators": "^1.0.1",
... ... @@ -110,12 +109,12 @@
110 109 "vite-plugin-compression": "^0.2.4",
111 110 "vite-plugin-html": "^2.0.6",
112 111 "vite-plugin-imagemin": "^0.3.0",
113   - "vite-plugin-mock": "^2.4.2",
  112 + "vite-plugin-mock": "^2.5.0",
114 113 "vite-plugin-purge-icons": "^0.7.0",
115 114 "vite-plugin-pwa": "^0.6.5",
116 115 "vite-plugin-style-import": "^0.9.2",
117 116 "vite-plugin-svg-icons": "^0.4.1",
118   - "vite-plugin-theme": "^0.5.0",
  117 + "vite-plugin-theme": "^0.6.0",
119 118 "vite-plugin-windicss": "0.12.5",
120 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 4 <rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
5 5 </clipPath>
6 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 9 </linearGradient>
10 10 </defs>
11 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 2 import AppProvider from './src/AppProvider.vue';
3 3 import AppSearch from './src/search/AppSearch.vue';
4 4 import AppLocalePicker from './src/AppLocalePicker.vue';
  5 +import AppDarkModeToggle from './src/AppDarkModeToggle.vue';
5 6  
6 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 42 padding: 0 16px;
43 43 font-size: 12px;
44 44 color: #666;
45   - background: rgb(255 255 255);
  45 + background: @component-background;
  46 + border-top: 1px solid @border-color-base;
46 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 48 align-items: center;
49 49 flex-shrink: 0;
50 50  
... ...
src/components/Application/src/search/AppSearchModal.vue
... ... @@ -190,12 +190,10 @@
190 190 &-content {
191 191 position: relative;
192 192 width: 632px;
193   - // padding: 14px;
194 193 margin: 0 auto auto auto;
195   - background: #f5f6f7;
  194 + background: @component-background;
196 195 border-radius: 16px;
197 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 197 flex-direction: column;
200 198 }
201 199  
... ... @@ -253,8 +251,7 @@
253 251 font-size: 14px;
254 252 color: @text-color-base;
255 253 cursor: pointer;
256   - // background: @primary-color;
257   - background: #fff;
  254 + background: @component-background;
258 255 border-radius: 4px;
259 256 box-shadow: 0 1px 3px 0 #d4d9e1;
260 257 align-items: center;
... ...
src/components/Container/src/collapse/CollapseContainer.vue
... ... @@ -101,7 +101,7 @@
101 101 @prefix-cls: ~'@{namespace}-collapse-container';
102 102  
103 103 .@{prefix-cls} {
104   - background: #fff;
  104 + background: @component-background;
105 105 border-radius: 2px;
106 106 transition: all 0.3s ease-in-out;
107 107  
... ...
src/components/ContextMenu/src/index.less
... ... @@ -22,7 +22,7 @@
22 22  
23 23 &:not(.ant-menu-item-disabled):hover {
24 24 color: @text-color-base;
25   - background: #eee;
  25 + background: @item-hover-bg;
26 26 }
27 27 }
28 28 }
... ... @@ -36,7 +36,7 @@
36 36 width: 156px;
37 37 margin: 0;
38 38 list-style: none;
39   - background-color: #fff;
  39 + background-color: @component-background;
40 40 border: 1px solid rgba(0, 0, 0, 0.08);
41 41 border-radius: 0.25rem;
42 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 221 .ant-drawer-body {
222 222 height: calc(100% - @header-height);
223 223 padding: 0;
224   - background-color: #fff;
  224 + background-color: @component-background;
225 225  
226 226 .scrollbar__wrap {
227 227 padding: 16px !important;
... ...
src/components/Drawer/src/components/DrawerFooter.vue
... ... @@ -74,7 +74,7 @@
74 74 width: 100%;
75 75 padding: 0 12px 0 20px;
76 76 text-align: right;
77   - background: #fff;
  77 + background: @component-background;
78 78 border-top: 1px solid @border-color-base;
79 79  
80 80 > * {
... ...
src/components/Form/src/components/FormItem.vue
... ... @@ -258,7 +258,7 @@
258 258 const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
259 259 const renderLabel = subLabel ? (
260 260 <span>
261   - {label} <span style="color:#00000073">{subLabel}</span>
  261 + {label} <span class="text-secondary">{subLabel}</span>
262 262 </span>
263 263 ) : (
264 264 label
... ...
src/components/Loading/src/index.vue
1 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 3 <Spin v-bind="$attrs" :tip="tip" :size="size" :spinning="loading" />
4 4 </section>
5 5 </template>
6 6 <script lang="ts">
7   - import { computed, CSSProperties, PropType } from 'vue';
  7 + import { PropType } from 'vue';
8 8  
9 9 import { defineComponent } from 'vue';
10 10 import { Spin } from 'ant-design-vue';
11 11  
12 12 import { SizeEnum } from '/@/enums/sizeEnum';
13   - import { ThemeEnum } from '/@/enums/appEnum';
14 13  
15 14 export default defineComponent({
16 15 name: 'Loading',
... ... @@ -38,25 +37,6 @@
38 37 background: {
39 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 42 </script>
... ... @@ -71,6 +51,7 @@
71 51 height: 100%;
72 52 justify-content: center;
73 53 align-items: center;
  54 + background: rgba(240, 242, 245, 0.4);
74 55  
75 56 &.absolute {
76 57 position: absolute;
... ... @@ -79,4 +60,10 @@
79 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 69 </style>
... ...
src/components/Markdown/src/index.vue
... ... @@ -10,7 +10,7 @@
10 10 onUnmounted,
11 11 nextTick,
12 12 computed,
13   - watchEffect,
  13 + watch,
14 14 } from 'vue';
15 15 import Vditor from 'vditor';
16 16 import 'vditor/dist/index.css';
... ... @@ -18,6 +18,7 @@
18 18 import { propTypes } from '/@/utils/propTypes';
19 19 import { useLocale } from '/@/locales/useLocale';
20 20 import { useModalContext } from '../../Modal';
  21 + import { useRootSetting } from '/@/hooks/setting/useRootSetting';
21 22  
22 23 type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
23 24 export default defineComponent({
... ... @@ -35,8 +36,24 @@
35 36 const modalFn = useModalContext();
36 37  
37 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 58 const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
42 59 let lang: Lang;
... ... @@ -60,6 +77,7 @@
60 77 if (!wrapEl) return;
61 78 const bindValue = { ...attrs, ...props };
62 79 vditorRef.value = new Vditor(wrapEl, {
  80 + theme: 'classic',
63 81 lang: unref(getCurrentLang),
64 82 mode: 'sv',
65 83 preview: {
... ...
src/components/Page/src/PageFooter.vue
... ... @@ -38,8 +38,8 @@
38 38 align-items: center;
39 39 padding: 0 24px;
40 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 43 box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),
44 44 0 -12px 48px 16px rgba(0, 0, 0, 0.03);
45 45 transition: width 0.2s;
... ...
src/components/Page/src/PageWrapper.vue
... ... @@ -17,11 +17,7 @@
17 17 <slot :name="item" v-bind="data"></slot>
18 18 </template>
19 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 21 <slot></slot>
26 22 </div>
27 23 <PageFooter v-if="getShowFooter" ref="footerRef">
... ... @@ -87,14 +83,12 @@
87 83  
88 84 const getContentStyle = computed(
89 85 (): CSSProperties => {
90   - const { contentBackground, contentFullHeight, contentStyle, fixedHeight } = props;
91   - const bg = contentBackground ? { backgroundColor: '#fff' } : {};
  86 + const { contentFullHeight, contentStyle, fixedHeight } = props;
92 87 if (!contentFullHeight) {
93   - return { ...bg, ...contentStyle };
  88 + return { ...contentStyle };
94 89 }
95 90 const height = `${unref(pageHeight)}px`;
96 91 return {
97   - ...bg,
98 92 ...contentStyle,
99 93 minHeight: height,
100 94 ...(fixedHeight ? { height } : {}),
... ... @@ -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 111 watch(
107 112 () => [contentHeight?.value, getShowFooter.value],
108 113 () => {
... ... @@ -170,6 +175,7 @@
170 175 getShowFooter,
171 176 pageHeight,
172 177 omit,
  178 + getContentClass,
173 179 };
174 180 },
175 181 });
... ... @@ -190,6 +196,10 @@
190 196 }
191 197 }
192 198  
  199 + &-content-bg {
  200 + background: @component-background;
  201 + }
  202 +
193 203 &--dense {
194 204 .@{prefix-cls}-content {
195 205 margin: 0;
... ...
src/components/SimpleMenu/src/index.less
... ... @@ -11,9 +11,9 @@
11 11  
12 12 &-dark&-vertical .@{simple-prefix-cls}__children,
13 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 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 298  
299 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 321 .@{prefix-cls} {
302 322 &-form-container {
303 323 padding: 16px;
... ... @@ -305,17 +325,11 @@
305 325 .ant-form {
306 326 padding: 12px 10px 6px 10px;
307 327 margin-bottom: 16px;
308   - background: #fff;
  328 + background: @component-background;
309 329 border-radius: 4px;
310 330 }
311 331 }
312 332  
313   - &-row__striped {
314   - td {
315   - background: #fafafa;
316   - }
317   - }
318   -
319 333 &--inset {
320 334 .ant-table-wrapper {
321 335 padding: 0;
... ... @@ -328,7 +342,7 @@
328 342  
329 343 .ant-table-wrapper {
330 344 padding: 6px;
331   - background: #fff;
  345 + background: @component-background;
332 346 border-radius: 2px;
333 347  
334 348 .ant-table-title {
... ... @@ -340,7 +354,6 @@
340 354 }
341 355 }
342 356  
343   - //
344 357 .ant-table {
345 358 width: 100%;
346 359 overflow-x: hidden;
... ...
src/components/Tree/src/index.vue
... ... @@ -324,7 +324,7 @@
324 324 const showTitle = title || toolbar || search || slots.headerTitle;
325 325 const scrollStyle: CSSProperties = { height: 'calc(100% - 38px)' };
326 326 return (
327   - <div class={[prefixCls, 'h-full bg-white', attrs.class]}>
  327 + <div class={[prefixCls, 'h-full', attrs.class]}>
328 328 {showTitle && (
329 329 <TreeHeader
330 330 checkable={checkable}
... ... @@ -361,6 +361,8 @@
361 361 @prefix-cls: ~'@{namespace}-basic-tree';
362 362  
363 363 .@{prefix-cls} {
  364 + background: @component-background;
  365 +
364 366 .ant-tree-node-content-wrapper {
365 367 position: relative;
366 368  
... ...
src/components/Upload/src/FileList.less
1 1 .file-table {
2 2 width: 100%;
3 3 border-collapse: collapse;
4   - // border: 1px solid @border-color-light;
5 4  
6 5 .center {
7 6 text-align: center;
... ... @@ -21,12 +20,12 @@
21 20 }
22 21  
23 22 thead {
24   - background-color: @background-color-dark;
  23 + background-color: @background-color-light;
25 24 }
26 25  
27 26 table,
28 27 td,
29 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 61 &.ant-btn-link.is-disabled {
62 62 color: rgba(0, 0, 0, 0.25) !important;
63 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 67 box-shadow: none;
68 68 }
69 69  
... ... @@ -187,7 +187,7 @@
187 187  
188 188 &-ghost {
189 189 color: @button-ghost-color;
190   - background-color: @white;
  190 + background-color: transparent;
191 191 border-color: @button-ghost-color;
192 192 border-width: 1px;
193 193  
... ... @@ -205,4 +205,14 @@
205 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 31 .ant-pagination {
2 32 &.mini {
3 33 .ant-pagination-prev,
... ...
src/design/color.less
1   -:root {
  1 +html {
2 2 // header
3 3 --header-bg-color: #394664;
4 4 --header-bg-hover-color: #273352;
... ... @@ -7,16 +7,13 @@
7 7 // sider
8 8 --sider-dark-bg-color: #273352;
9 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 13 @white: #fff;
15 14  
16 15 @content-bg: #f4f7f9;
17   -// @content-bg: #f0f2f5;
18 16  
19   -@basic-mask-color: fade(@white, 30%);
20 17 // :export {
21 18 // name: "less";
22 19 // mainColor: @mainColor;
... ... @@ -35,10 +32,7 @@
35 32 @border-color-shallow-dark: #cececd;
36 33  
37 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 38 // ==============message==============
... ... @@ -54,17 +48,6 @@
54 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 51 // ==============Header=============
69 52 // =================================
70 53  
... ... @@ -83,14 +66,11 @@
83 66 // let -menu
84 67 @sider-dark-bg-color: var(--sider-dark-bg-color);
85 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 71 // trigger
90 72 @trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2);
91 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 76 // ==============tree============
... ... @@ -119,9 +99,6 @@
119 99 // Auxiliary information color-dark
120 100 @text-color-help-dark: #909399;
121 101  
122   -// Auxiliary information color-light color
123   -@text-color-help-light: #c0c4cc;
124   -
125 102 // =================================
126 103 // ==============breadcrumb=========
127 104 // =================================
... ...
src/design/index.less
... ... @@ -2,6 +2,7 @@
2 2 @import 'var/index.less';
3 3 @import 'public.less';
4 4 @import 'ant/index.less';
  5 +@import './theme.less';
5 6  
6 7 input:-webkit-autofill {
7 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 5 mounted(el, binding) {
6 6 const tip = el.getAttribute('loading-tip');
7 7 const background = el.getAttribute('loading-background');
8   - const theme = el.getAttribute('loading-theme');
9 8 const size = el.getAttribute('loading-size');
10 9 const fullscreen = !!binding.modifiers.fullscreen;
11 10 const instance = createLoading(
12 11 {
13 12 tip,
14 13 background,
15   - theme,
16 14 size: size || 'large',
17 15 loading: !!binding.value,
18 16 absolute: !fullscreen,
... ...
src/enums/appEnum.ts
... ... @@ -8,17 +8,9 @@ export enum ContentEnum {
8 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 11 // menu theme enum
19 12 export enum ThemeEnum {
20 13 DARK = 'dark',
21   -
22 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 15 // lock info
16 16 export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__';
17 17  
  18 +export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__';
  19 +
18 20 // base global local key
19 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 4  
5 5 import { appStore } from '/@/store/modules/app';
6 6 import { ContentEnum } from '/@/enums/appEnum';
  7 +import { ThemeEnum } from '../../enums/appEnum';
7 8  
8 9 type RootSetting = Omit<
9 10 ProjectConfig,
... ... @@ -48,6 +49,10 @@ const getGrayMode = computed(() =&gt; unref(getRootSetting).grayMode);
48 49  
49 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 56 const getLayoutContentMode = computed(() =>
52 57 unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
53 58 );
... ... @@ -56,6 +61,10 @@ function setRootSetting(setting: Partial&lt;RootSetting&gt;) {
56 61 appStore.commitProjectConfigState(setting);
57 62 }
58 63  
  64 +function setDarkMode(mode: ThemeEnum) {
  65 + appStore.commitDarkMode(mode);
  66 +}
  67 +
59 68 export function useRootSetting() {
60 69 return {
61 70 setRootSetting,
... ... @@ -80,5 +89,8 @@ export function useRootSetting() {
80 89 getContentMode,
81 90 getLockTime,
82 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 1 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
2 2 import { tryOnUnmounted } from '@vueuse/core';
3   -import { unref, Ref, nextTick } from 'vue';
  3 +import { unref, Ref, nextTick, watch, computed, ref } from 'vue';
4 4 import type { EChartsOption } from 'echarts';
5 5 import { useDebounce } from '/@/hooks/core/useDebounce';
6 6 import { useEventListener } from '/@/hooks/event/useEventListener';
7 7 import { useBreakpoint } from '/@/hooks/event/useBreakpoint';
8 8  
9 9 import echarts from '/@/plugins/echarts';
  10 +import { useRootSetting } from '../setting/useRootSetting';
10 11  
11 12 export function useECharts(
12 13 elRef: Ref<HTMLDivElement>,
13 14 theme: 'light' | 'dark' | 'default' = 'light'
14 15 ) {
  16 + const { getDarkMode } = useRootSetting();
15 17 let chartInstance: echarts.ECharts | null = null;
16 18 let resizeFn: Fn = resize;
  19 + const cacheOptions = ref<EChartsOption>({});
17 20 let removeResizeFn: Fn = () => {};
18 21  
19 22 const [debounceResize] = useDebounce(resize, 200);
20 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 38 const el = unref(elRef);
24 39 if (!el || !unref(el)) {
25 40 return;
26 41 }
27 42  
28   - chartInstance = echarts.init(el, theme);
  43 + chartInstance = echarts.init(el, t);
29 44 const { removeEvent } = useEventListener({
30 45 el: window,
31 46 name: 'resize',
... ... @@ -41,22 +56,23 @@ export function useECharts(
41 56 }
42 57  
43 58 function setOptions(options: EChartsOption, clear = true) {
  59 + cacheOptions.value = options;
44 60 if (unref(elRef)?.offsetHeight === 0) {
45 61 useTimeoutFn(() => {
46   - setOptions(options);
  62 + setOptions(unref(getOptions));
47 63 }, 30);
48 64 return;
49 65 }
50 66 nextTick(() => {
51 67 useTimeoutFn(() => {
52 68 if (!chartInstance) {
53   - initCharts();
  69 + initCharts(getDarkMode.value);
54 70  
55 71 if (!chartInstance) return;
56 72 }
57 73 clear && chartInstance?.clear();
58 74  
59   - chartInstance?.setOption(options);
  75 + chartInstance?.setOption(unref(getOptions));
60 76 }, 30);
61 77 });
62 78 }
... ... @@ -65,6 +81,17 @@ export function useECharts(
65 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 95 tryOnUnmounted(() => {
69 96 if (!chartInstance) return;
70 97 removeResizeFn();
... ...
src/layouts/default/header/MultipleHeader.vue
... ... @@ -112,7 +112,6 @@
112 112 @prefix-cls: ~'@{namespace}-layout-multiple-header';
113 113  
114 114 .@{prefix-cls} {
115   - // margin-left: 1px;
116 115 transition: width 0.2s;
117 116 flex: 0 0 auto;
118 117  
... ...
src/layouts/default/header/components/lock/LockModal.vue
... ... @@ -91,7 +91,6 @@
91 91 position: relative;
92 92 height: 240px;
93 93 padding: 130px 30px 60px 30px;
94   - background: #fff;
95 94 border-radius: 10px;
96 95 }
97 96  
... ...
src/layouts/default/header/components/user-dropdown/index.vue
... ... @@ -131,10 +131,6 @@
131 131 cursor: pointer;
132 132 align-items: center;
133 133  
134   - &:hover {
135   - background: @header-light-bg-hover-color;
136   - }
137   -
138 134 img {
139 135 width: 24px;
140 136 height: 24px;
... ...
src/layouts/default/header/index.less
... ... @@ -131,7 +131,7 @@
131 131 }
132 132  
133 133 &--light {
134   - background: @white;
  134 + background: @white !important;
135 135 border-bottom: 1px solid @header-light-bottom-border-color;
136 136 border-left: 1px solid @header-light-bottom-border-color;
137 137  
... ... @@ -165,8 +165,9 @@
165 165 }
166 166  
167 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 171 .@{header-prefix-cls}-logo {
171 172 &:hover {
172 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 3 import { Divider } from 'ant-design-vue';
4 4 import {
5 5 TypePicker,
6   - ThemePicker,
  6 + ThemeColorPicker,
7 7 SettingFooter,
8 8 SwitchItem,
9 9 SelectItem,
10 10 InputNumberItem,
11 11 } from './components';
12 12  
  13 +import { AppDarkModeToggle } from '/@/components/Application';
  14 +
13 15 import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
14 16  
15 17 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
... ... @@ -52,6 +54,7 @@ export default defineComponent({
52 54 getColorWeak,
53 55 getGrayMode,
54 56 getLockTime,
  57 + getShowDarkModeToggle,
55 58 getThemeColor,
56 59 } = useRootSetting();
57 60  
... ... @@ -116,7 +119,7 @@ export default defineComponent({
116 119  
117 120 function renderHeaderTheme() {
118 121 return (
119   - <ThemePicker
  122 + <ThemeColorPicker
120 123 colorList={HEADER_PRESET_BG_COLOR_LIST}
121 124 def={unref(getHeaderBgColor)}
122 125 event={HandlerEnum.HEADER_THEME}
... ... @@ -126,7 +129,7 @@ export default defineComponent({
126 129  
127 130 function renderSiderTheme() {
128 131 return (
129   - <ThemePicker
  132 + <ThemeColorPicker
130 133 colorList={SIDE_BAR_BG_COLOR_LIST}
131 134 def={unref(getMenuBgColor)}
132 135 event={HandlerEnum.MENU_THEME}
... ... @@ -136,7 +139,7 @@ export default defineComponent({
136 139  
137 140 function renderMainTheme() {
138 141 return (
139   - <ThemePicker
  142 + <ThemeColorPicker
140 143 colorList={APP_PRESET_COLOR_LIST}
141 144 def={unref(getThemeColor)}
142 145 event={HandlerEnum.CHANGE_THEME_COLOR}
... ... @@ -404,6 +407,8 @@ export default defineComponent({
404 407 width={330}
405 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 412 <Divider>{() => t('layout.setting.navMode')}</Divider>
408 413 {renderSidebar()}
409 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 26 import { HandlerEnum } from '../enum';
27 27  
28 28 export default defineComponent({
29   - name: 'ThemePicker',
  29 + name: 'ThemeColorPicker',
30 30 components: { CheckOutlined },
31 31 props: {
32 32 colorList: {
... ...
src/layouts/default/setting/components/TypePicker.vue
... ... @@ -74,7 +74,8 @@
74 74 content: '';
75 75 }
76 76  
77   - &--sidebar {
  77 + &--sidebar,
  78 + &--light {
78 79 &::before {
79 80 top: 0;
80 81 left: 0;
... ... @@ -124,6 +125,10 @@
124 125 }
125 126 }
126 127  
  128 + &--dark {
  129 + background-color: #273352;
  130 + }
  131 +
127 132 &--mix-sidebar {
128 133 &::before {
129 134 top: 0;
... ... @@ -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 160 &:hover,
167 161 &--active {
168 162 padding: 12px;
... ...
src/layouts/default/setting/components/index.ts
1 1 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
2 2  
3 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 5 export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue'));
6 6 export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue'));
7 7 export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue'));
... ...
src/layouts/default/setting/enum.ts
... ... @@ -14,6 +14,7 @@ const { t } = useI18n();
14 14 export enum HandlerEnum {
15 15 CHANGE_LAYOUT,
16 16 CHANGE_THEME_COLOR,
  17 + CHANGE_THEME,
17 18 // menu
18 19 MENU_HAS_DRAG,
19 20 MENU_ACCORDION,
... ...
src/layouts/default/setting/handler.ts
... ... @@ -6,15 +6,20 @@ import { updateGrayMode } from &#39;/@/logics/theme/updateGrayMode&#39;;
6 6 import { appStore } from '/@/store/modules/app';
7 7 import { ProjectConfig } from '/#/config';
8 8 import { changeTheme } from '/@/logics/theme';
  9 +import { updateDarkTheme } from '/@/logics/theme/dark';
9 10 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
10 11  
11 12 export function baseHandler(event: HandlerEnum, value: any) {
12 13 const config = handler(event, value);
13 14 appStore.commitProjectConfigState(config);
  15 + if (event === HandlerEnum.CHANGE_THEME) {
  16 + updateHeaderBgColor();
  17 + updateSidebarBgColor();
  18 + }
14 19 }
15 20  
16 21 export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
17   - const { getThemeColor } = useRootSetting();
  22 + const { getThemeColor, getDarkMode } = useRootSetting();
18 23 switch (event) {
19 24 case HandlerEnum.CHANGE_LAYOUT:
20 25 const { mode, type, split } = value;
... ... @@ -36,8 +41,17 @@ export function handler(event: HandlerEnum, value: any): DeepPartial&lt;ProjectConf
36 41 return {};
37 42 }
38 43 changeTheme(value);
  44 +
39 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 55 case HandlerEnum.MENU_HAS_DRAG:
42 56 return { menuSetting: { canDrag: value } };
43 57  
... ...
src/layouts/default/sider/MixSider.vue
... ... @@ -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 408 &.dark {
409 409 &.open {
... ...
src/layouts/default/tabs/index.less
1 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 11 .@{prefix-cls} {
4 12 z-index: 10;
5 13 height: @multiple-height + 2;
6 14 line-height: @multiple-height + 2;
7   - background: @white;
  15 + background: @component-background;
  16 + border-bottom: 1px solid @border-color-base;
8 17 box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
9 18  
10 19 .ant-tabs-small {
... ... @@ -15,7 +24,7 @@
15 24 .ant-tabs-card-bar {
16 25 height: @multiple-height;
17 26 margin: 0;
18   - background: @white;
  27 + background: @component-background;
19 28 border: 0;
20 29 box-shadow: none;
21 30  
... ... @@ -28,35 +37,14 @@
28 37 height: calc(@multiple-height - 2px);
29 38 padding-right: 12px;
30 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 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 44 &:hover {
51 45 .ant-tabs-close-x {
52 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 50 .ant-tabs-close-x {
... ... @@ -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 82 .ant-tabs-tab-active {
89 83 position: relative;
90   - padding-left: 26px;
  84 + padding-left: 18px;
91 85 color: @white;
92   - background: fade(@primary-color, 100%);
  86 + background: @primary-color;
93 87 border: 0;
94 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 90 .ant-tabs-close-x {
109 91 opacity: 1;
110 92 }
... ... @@ -158,10 +140,10 @@
158 140 width: 36px;
159 141 height: @multiple-height;
160 142 line-height: @multiple-height;
161   - color: #666;
  143 + color: @text-color-secondary;
162 144 text-align: center;
163 145 cursor: pointer;
164   - border-left: 1px solid #eee;
  146 + border-left: 1px solid @border-color-base;
165 147  
166 148 &:hover {
167 149 color: @text-color-base;
... ...
src/locales/lang/en/common.ts
... ... @@ -14,4 +14,7 @@ export default {
14 14  
15 15 redo: 'Refresh',
16 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 30  
31 31 drawerTitle: 'Configuration',
32 32  
  33 + darkMode: 'Dark mode',
33 34 navMode: 'Navigation mode',
34 35 interfaceFunction: 'Interface function',
35 36 interfaceDisplay: 'Interface display',
... ...
src/locales/lang/en/routes/demo/charts.ts
... ... @@ -6,5 +6,4 @@ export default {
6 6 map: 'Map',
7 7 line: 'Line',
8 8 pie: 'Pie',
9   - apexChart: 'ApexChart',
10 9 };
... ...
src/locales/lang/zh_CN/common.ts
... ... @@ -14,4 +14,7 @@ export default {
14 14  
15 15 redo: '刷新',
16 16 back: '返回',
  17 +
  18 + light: '亮色主题',
  19 + dark: '黑暗主题',
17 20 };
... ...
src/locales/lang/zh_CN/layout/setting.ts
... ... @@ -29,6 +29,7 @@ export default {
29 29  
30 30 drawerTitle: '项目配置',
31 31  
  32 + darkMode: '主题',
32 33 navMode: '导航栏模式',
33 34 interfaceFunction: '界面功能',
34 35 interfaceDisplay: '界面显示',
... ...
src/locales/lang/zh_CN/routes/demo/charts.ts
... ... @@ -6,5 +6,4 @@ export default {
6 6 map: '地图',
7 7 line: '折线图',
8 8 pie: '饼图',
9   - apexChart: 'ApexChart',
10 9 };
... ...
src/logics/initAppConfig.ts
... ... @@ -9,6 +9,7 @@ import projectSetting from &#39;/@/settings/projectSetting&#39;;
9 9 import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
10 10 import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
11 11 import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
  12 +import { updateDarkTheme } from '/@/logics/theme/dark';
12 13 import { changeTheme } from '/@/logics/theme';
13 14  
14 15 import { appStore } from '/@/store/modules/app';
... ... @@ -19,30 +20,43 @@ import { getCommonStoragePrefix, getStorageShortName } from &#39;/@/utils/env&#39;;
19 20 import { primaryColor } from '../../build/config/themeConfig';
20 21 import { Persistent } from '/@/utils/cache/persistent';
21 22 import { deepMerge } from '/@/utils';
  23 +import { ThemeEnum } from '../enums/appEnum';
22 24  
23 25 // Initial project configuration
24 26 export function initAppConfigStore() {
25 27 let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
26 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 38 try {
28   - const {
29   - colorWeak,
30   - grayMode,
31   - themeColor,
32   - headerSetting: { bgColor: headerBgColor } = {},
33   - menuSetting: { bgColor } = {},
34   - } = projCfg;
35 39 if (themeColor && themeColor !== primaryColor) {
36 40 changeTheme(themeColor);
37 41 }
38   - headerBgColor && updateHeaderBgColor(headerBgColor);
39   - bgColor && updateSidebarBgColor(bgColor);
  42 +
40 43 grayMode && updateGrayMode(grayMode);
41 44 colorWeak && updateColorWeak(colorWeak);
42 45 } catch (error) {
43 46 console.log(error);
44 47 }
45 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 60 localeStore.initLocale();
47 61  
48 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 3 import { replaceStyleVariables } from 'vite-plugin-theme/es/client';
4 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 7 const colors = generateColors({
8 8 mixDarken,
9 9 mixLighten,
... ... @@ -12,6 +12,6 @@ export async function changeTheme(color: string, theme?: ThemeMode) {
12 12 });
13 13  
14 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 2 import { appStore } from '/@/store/modules/app';
3 3 import { ThemeEnum } from '/@/enums/appEnum';
4 4 import { setCssVar } from './util';
... ... @@ -9,29 +9,35 @@ const HEADER_MENU_ACTIVE_BG_COLOR_VAR = &#39;--header-active-menu-bg-color&#39;;
9 9  
10 10 const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color';
11 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 15 * Change the background color of the top header
17 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 27 // bg color
22 28 setCssVar(HEADER_BG_COLOR_VAR, color);
23 29  
24 30 // hover color
25   - const hoverColor = lighten(color, 6);
  31 + const hoverColor = lighten(color!, 6);
26 32 setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
27 33 setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
28 34  
29 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 38 appStore.commitProjectConfigState({
33 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 46 * Change the background color of the left menu
41 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 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 63 // only #ffffff is light
52 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 67 appStore.commitProjectConfigState({
56 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 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 25 path: 'echarts',
31 26 name: 'Echarts',
32 27 children: [
... ...
src/router/routes/modules/demo/charts.ts
... ... @@ -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 42 path: 'echarts',
51 43 name: 'Echarts',
52 44 component: getParentLayout('Echarts'),
... ...
src/settings/designSetting.ts
  1 +import { ThemeEnum } from '../enums/appEnum';
1 2 export default {
2 3 prefixCls: 'vben',
3 4 };
4 5  
  6 +export const darkMode = ThemeEnum.LIGHT;
  7 +
5 8 // app theme preset color
6 9 export const APP_PRESET_COLOR_LIST: string[] = [
7 10 '#0960bd',
... ... @@ -18,6 +21,7 @@ export const APP_PRESET_COLOR_LIST: string[] = [
18 21 // header preset color
19 22 export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
20 23 '#ffffff',
  24 + '#151515',
21 25 '#009688',
22 26 '#5172DC',
23 27 '#018ffb',
... ... @@ -32,6 +36,7 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
32 36 // sider preset color
33 37 export const SIDE_BAR_BG_COLOR_LIST: string[] = [
34 38 '#001529',
  39 + '#212121',
35 40 '#273352',
36 41 '#ffffff',
37 42 '#191b24',
... ...
src/settings/projectSetting.ts
... ... @@ -9,13 +9,16 @@ import {
9 9 SettingButtonPositionEnum,
10 10 } from '/@/enums/appEnum';
11 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 14 // ! You need to clear the browser cache after the change
15 15 const setting: ProjectConfig = {
16 16 // Whether to show the configuration button
17 17 showSettingButton: true,
18 18  
  19 + // Whether to show the theme switch button
  20 + showDarkModeToggle: true,
  21 +
19 22 // `Settings` button position
20 23 settingButtonPosition: SettingButtonPositionEnum.AUTO,
21 24  
... ... @@ -28,9 +31,6 @@ const setting: ProjectConfig = {
28 31 // color
29 32 themeColor: primaryColor,
30 33  
31   - // TODO dark theme
32   - themeMode: themeMode,
33   -
34 34 // Website gray mode, open for possible mourning dates
35 35 grayMode: false,
36 36  
... ...
src/store/modules/app.ts
... ... @@ -4,13 +4,16 @@ import type { BeforeMiniState } from &#39;../types&#39;;
4 4 import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
5 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 9 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
10 10 import { Persistent } from '/@/utils/cache/persistent';
11 11 import { deepMerge } from '/@/utils';
12 12  
13 13 import { resetRouter } from '/@/router';
  14 +import { ThemeEnum } from '../../enums/appEnum';
  15 +
  16 +import { darkMode } from '/@/settings/designSetting';
14 17  
15 18 export interface LockInfo {
16 19 pwd: string | undefined;
... ... @@ -22,6 +25,8 @@ const NAME = &#39;app&#39;;
22 25 hotModuleUnregisterModule(NAME);
23 26 @Module({ dynamic: true, namespaced: true, store, name: NAME })
24 27 export default class App extends VuexModule {
  28 + private darkMode;
  29 +
25 30 // Page loading status
26 31 private pageLoadingState = false;
27 32  
... ... @@ -38,6 +43,10 @@ export default class App extends VuexModule {
38 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 50 get getBeforeMiniState() {
42 51 return this.beforeMiniState;
43 52 }
... ... @@ -56,6 +65,12 @@ export default class App extends VuexModule {
56 65 }
57 66  
58 67 @Mutation
  68 + commitDarkMode(mode: ThemeEnum): void {
  69 + this.darkMode = mode;
  70 + localStorage.setItem(APP_DARK_MODE_KEY_, mode);
  71 + }
  72 +
  73 + @Mutation
59 74 commitBeforeMiniState(state: BeforeMiniState): void {
60 75 this.beforeMiniState = state;
61 76 }
... ...
src/views/dashboard/analysis/components/VisitRadar.vue
... ... @@ -32,7 +32,6 @@
32 32 return;
33 33 }
34 34 setOptions({
35   - backgroundColor: '#fff',
36 35 legend: {
37 36 bottom: 0,
38 37 data: ['访问', '购买'],
... ...
src/views/dashboard/workbench/components/SaleRadar.vue
... ... @@ -32,7 +32,6 @@
32 32 return;
33 33 }
34 34 setOptions({
35   - backgroundColor: '#fff',
36 35 legend: {
37 36 bottom: 0,
38 37 data: ['Visits', 'Sales'],
... ...
src/views/demo/charts/SaleRadar.vue
... ... @@ -32,7 +32,6 @@
32 32 return;
33 33 }
34 34 setOptions({
35   - backgroundColor: '#fff',
36 35 legend: {
37 36 bottom: 0,
38 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 29 height: 2000px;
30 30 margin: 20px auto;
31 31 text-align: center;
32   - background: #fff;
  32 + background: @component-background;
33 33 justify-content: center;
34 34 flex-direction: column;
35 35 align-items: center;
... ...
src/views/demo/comp/lazy/index.vue
... ... @@ -33,7 +33,7 @@
33 33 height: 2000px;
34 34 margin: 20px auto;
35 35 text-align: center;
36   - background: #fff;
  36 + background: @component-background;
37 37 justify-content: center;
38 38 flex-direction: column;
39 39 align-items: center;
... ...
src/views/demo/comp/scroll/Action.vue
... ... @@ -54,6 +54,6 @@
54 54 .scroll-wrap {
55 55 width: 50%;
56 56 height: 300px;
57   - background: #fff;
  57 + background: @component-background;
58 58 }
59 59 </style>
... ...
src/views/demo/comp/scroll/VirtualScroll.vue
... ... @@ -50,7 +50,7 @@
50 50 &-wrap {
51 51 display: flex;
52 52 margin: 0 30%;
53   - background: #fff;
  53 + background: @component-background;
54 54 justify-content: center;
55 55 }
56 56  
... ... @@ -58,7 +58,7 @@
58 58 height: 40px;
59 59 padding: 0 20px;
60 60 line-height: 40px;
61   - border-bottom: 1px solid #ddd;
  61 + border-bottom: 1px solid @border-color-base;
62 62 }
63 63 }
64 64 </style>
... ...
src/views/demo/comp/scroll/index.vue
... ... @@ -26,6 +26,6 @@
26 26 .scroll-wrap {
27 27 width: 50%;
28 28 height: 300px;
29   - background: #fff;
  29 + background: @component-background;
30 30 }
31 31 </style>
... ...
src/views/demo/comp/strength-meter/index.vue
... ... @@ -26,7 +26,7 @@
26 26 <style lang="less" scoped>
27 27 .demo-wrap {
28 28 width: 50%;
29   - background: #fff;
  29 + background: @component-background;
30 30 border-radius: 10px;
31 31 }
32 32 </style>
... ...
src/views/demo/feat/tab-params/index.vue
... ... @@ -3,17 +3,18 @@
3 3 Current Param : {{ params }}
4 4 <br />
5 5 Keep Alive
6   - <input />
  6 + <Input />
7 7 </PageWrapper>
8 8 </template>
9 9 <script lang="ts">
10 10 import { computed, defineComponent, unref } from 'vue';
11 11 import { useRouter } from 'vue-router';
12 12 import { PageWrapper } from '/@/components/Page';
  13 + import { Input } from 'ant-design-vue';
13 14  
14 15 export default defineComponent({
15 16 name: 'TestTab',
16   - components: { PageWrapper },
  17 + components: { PageWrapper, Input },
17 18 setup() {
18 19 const { currentRoute } = useRouter();
19 20 return {
... ...
src/views/demo/level/Menu111.vue
... ... @@ -2,10 +2,11 @@
2 2 <div class="p-5">
3 3 多层级缓存-页面1-1-1
4 4 <br />
5   - <input />
  5 + <Input />
6 6 </div>
7 7 </template>
8 8 <script lang="ts">
9 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 12 </script>
... ...
src/views/demo/level/Menu12.vue
... ... @@ -2,10 +2,11 @@
2 2 <div class="p-5">
3 3 多层级缓存-页面1-2
4 4 <br />
5   - <input />
  5 + <Input />
6 6 </div>
7 7 </template>
8 8 <script lang="ts">
9 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 12 </script>
... ...
src/views/demo/level/Menu2.vue
... ... @@ -2,12 +2,14 @@
2 2 <div class="p-5">
3 3 多层级缓存-页面2
4 4 <br />
5   - <input />
  5 + <Input />
6 6 </div>
7 7 </template>
8 8 <script lang="ts">
9 9 import { defineComponent } from 'vue';
  10 + import { Input } from 'ant-design-vue';
10 11 export default defineComponent({
11 12 name: 'Menu2Demo',
  13 + components: { Input },
12 14 });
13 15 </script>
... ...
src/views/demo/page/account/center/Application.vue
... ... @@ -64,7 +64,6 @@
64 64 margin-bottom: 5px;
65 65 font-size: 16px;
66 66 font-weight: 500;
67   - color: rgba(0, 0, 0, 0.85);
68 67  
69 68 .icon {
70 69 margin-top: -5px;
... ... @@ -75,19 +74,18 @@
75 74 &-num {
76 75 margin-left: 24px;
77 76 line-height: 36px;
78   - color: #7d7a7a;
  77 + color: @text-color-secondary;
79 78  
80 79 span {
81 80 margin-left: 5px;
82 81 font-size: 18px;
83   - color: #000;
84 82 }
85 83 }
86 84  
87 85 &-download {
88 86 float: right;
89 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 102 &-top {
103 103 padding: 10px;
104 104 margin: 16px 16px 12px 16px;
105   - background: #fff;
  105 + background: @component-background;
106 106 border-radius: 3px;
107 107  
108 108 &__avatar {
... ... @@ -144,7 +144,7 @@
144 144 &-bottom {
145 145 padding: 10px;
146 146 margin: 0 16px 16px 16px;
147   - background: #fff;
  147 + background: @component-background;
148 148 border-radius: 3px;
149 149 }
150 150 }
... ...
src/views/demo/page/account/setting/index.vue
... ... @@ -48,14 +48,14 @@
48 48 <style lang="less">
49 49 .account-setting {
50 50 margin: 12px;
51   - background: #fff;
  51 + background: @component-background;
52 52  
53 53 .base-title {
54 54 padding-left: 0;
55 55 }
56 56  
57 57 .ant-tabs-tab-active {
58   - background-color: #e6f7ff;
  58 + background-color: @item-active-bg;
59 59 }
60 60 }
61 61 </style>
... ...
src/views/demo/page/desc/basic/index.vue
... ... @@ -93,6 +93,6 @@
93 93 <style lang="less" scoped>
94 94 .desc-wrap {
95 95 padding: 16px;
96   - background: #fff;
  96 + background: @component-background;
97 97 }
98 98 </style>
... ...
src/views/demo/page/form/basic/index.vue
... ... @@ -62,6 +62,6 @@
62 62 <style lang="less" scoped>
63 63 .form-wrap {
64 64 padding: 24px;
65   - background: #fff;
  65 + background: @component-background;
66 66 }
67 67 </style>
... ...
src/views/demo/page/form/step/Step1.vue
... ... @@ -78,18 +78,18 @@
78 78 margin: 0 0 12px;
79 79 font-size: 16px;
80 80 line-height: 32px;
81   - color: rgba(0, 0, 0, 0.45);
  81 + color: @text-color;
82 82 }
83 83  
84 84 h4 {
85 85 margin: 0 0 4px;
86 86 font-size: 14px;
87 87 line-height: 22px;
88   - color: rgba(0, 0, 0, 0.45);
  88 + color: @text-color;
89 89 }
90 90  
91 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 44 .desc-wrap {
45 45 padding: 24px 40px;
46 46 margin-top: 24px;
47   - background: #fafafa;
  47 + background: @background-color-light;
48 48 }
49 49 </style>
... ...
src/views/demo/page/form/step/index.vue
... ... @@ -85,7 +85,7 @@
85 85 <style lang="less" scoped>
86 86 .step-form-content {
87 87 padding: 24px;
88   - background: #fff;
  88 + background: @component-background;
89 89 }
90 90  
91 91 .step-form-form {
... ...
src/views/demo/page/list/basic/index.vue
... ... @@ -86,25 +86,25 @@
86 86 &__top {
87 87 padding: 24px;
88 88 text-align: center;
89   - background: #fff;
  89 + background: @component-background;
90 90  
91 91 &-col {
92 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 96 div {
97 97 margin-bottom: 12px;
98 98 font-size: 14px;
99 99 line-height: 22px;
100   - color: rgba(0, 0, 0, 0.45);
  100 + color: @text-color;
101 101 }
102 102  
103 103 p {
104 104 margin: 0;
105 105 font-size: 24px;
106 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 112 &__content {
113 113 padding: 24px;
114 114 margin-top: 12px;
115   - background: #fff;
  115 + background: @component-background;
116 116  
117 117 .list {
118 118 position: relative;
... ... @@ -127,7 +127,7 @@
127 127 top: 20px;
128 128 right: 15px;
129 129 font-weight: normal;
130   - color: #1890ff;
  130 + color: @primary-color;
131 131 cursor: pointer;
132 132 }
133 133  
... ...
src/views/demo/page/list/card/index.vue
... ... @@ -84,7 +84,7 @@
84 84 margin-bottom: 5px;
85 85 font-size: 16px;
86 86 font-weight: 500;
87   - color: rgba(0, 0, 0, 0.85);
  87 + color: @text-color;
88 88  
89 89 .icon {
90 90 margin-top: -5px;
... ... @@ -97,7 +97,7 @@
97 97 padding-top: 10px;
98 98 padding-left: 30px;
99 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 91  
92 92 &__container {
93 93 padding: 12px;
94   - background: #fff;
  94 + background: @component-background;
95 95 }
96 96  
97 97 &__title {
... ... @@ -100,7 +100,7 @@
100 100 }
101 101  
102 102 &__content {
103   - color: rgba(0, 0, 0, 0.65);
  103 + color: @text-color-secondary;
104 104 }
105 105  
106 106 &__action {
... ... @@ -109,7 +109,7 @@
109 109 &-item {
110 110 display: inline-block;
111 111 padding: 0 16px;
112   - color: rgba(0, 0, 0, 0.45);
  112 + color: @text-color-secondary;
113 113  
114 114 &:nth-child(1) {
115 115 padding-left: 0;
... ... @@ -117,7 +117,7 @@
117 117  
118 118 &:nth-child(1),
119 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 34 <style lang="less" scoped>
35 35 .result-error {
36 36 padding: 48px 32px;
37   - background: #fff;
  37 + background: @component-background;
38 38  
39 39 &__content {
40 40 padding: 24px 40px;
41   - background: #fafafa;
  41 + background: @background-color-light;
42 42  
43 43 &-title {
44 44 margin-bottom: 16px;
45 45 font-size: 16px;
46 46 font-weight: 500;
47   - color: rgba(0, 0, 0, 0.85);
48 47 }
49 48  
50 49 &-icon {
... ...
src/views/demo/page/result/success/index.vue
... ... @@ -48,11 +48,11 @@
48 48 <style lang="less" scoped>
49 49 .result-success {
50 50 padding: 48px 32px;
51   - background: #fff;
  51 + background: @component-background;
52 52  
53 53 &__content {
54 54 padding: 24px 40px;
55   - background: #fafafa;
  55 + background: @background-color-light;
56 56 }
57 57 }
58 58 </style>
... ...
src/views/demo/permission/back/Btn.vue
... ... @@ -83,6 +83,6 @@
83 83 </script>
84 84 <style lang="less" scoped>
85 85 .demo {
86   - background: #fff;
  86 + background: @component-background;
87 87 }
88 88 </style>
... ...
src/views/demo/permission/back/index.vue
... ... @@ -38,6 +38,6 @@
38 38 </script>
39 39 <style lang="less" scoped>
40 40 .demo {
41   - background: #fff;
  41 + background: @component-background;
42 42 }
43 43 </style>
... ...