Commit 5b8eb4a49a097a47caf491c44df427522ab58daa
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
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 './src/AppLogo.vue'; |
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
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
src/components/Drawer/src/components/DrawerFooter.vue
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
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 = 'PROJ__CFG__KEY__'; |
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 'vue'; |
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(() => 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<RootSetting>) { |
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
src/layouts/default/header/components/lock/LockModal.vue
src/layouts/default/header/components/user-dropdown/index.vue
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 '/@/components/Drawer/index'; |
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
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
src/layouts/default/setting/handler.ts
... | ... | @@ -6,15 +6,20 @@ import { updateGrayMode } from '/@/logics/theme/updateGrayMode'; |
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<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
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
src/locales/lang/en/layout/setting.ts
src/locales/lang/en/routes/demo/charts.ts
src/locales/lang/zh_CN/common.ts
src/locales/lang/zh_CN/layout/setting.ts
src/locales/lang/zh_CN/routes/demo/charts.ts
src/logics/initAppConfig.ts
... | ... | @@ -9,6 +9,7 @@ import projectSetting from '/@/settings/projectSetting'; |
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 '/@/utils/env'; |
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 = '--header-active-menu-bg-color'; |
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
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 '../types'; |
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 = 'app'; |
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
src/views/dashboard/workbench/components/SaleRadar.vue
src/views/demo/charts/SaleRadar.vue
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
src/views/demo/comp/lazy/index.vue
src/views/demo/comp/scroll/Action.vue
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
src/views/demo/comp/strength-meter/index.vue
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
src/views/demo/page/form/basic/index.vue
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
src/views/demo/page/form/step/index.vue
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