diff --git a/package.json b/package.json
index cf700b09..bf37383e 100644
--- a/package.json
+++ b/package.json
@@ -23,9 +23,11 @@
"dependencies": {
"@vueuse/core": "^7.5.1",
"axios": "^0.24.0",
+ "colord": "^2.9.2",
"crypto-js": "^4.1.1",
"dayjs": "^1.10.7",
"form-data": "^4.0.0",
+ "lodash-es": "^4.17.21",
"naive-ui": "^2.23.2",
"pinia": "^2.0.9",
"qs": "^6.10.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f41ca153..86cdc563 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,6 +15,7 @@ specifiers:
'@vue/eslint-config-typescript': ^10.0.0
'@vueuse/core': ^7.5.1
axios: ^0.24.0
+ colord: ^2.9.2
commitizen: ^4.2.4
cross-env: ^7.0.3
crypto-js: ^4.1.1
@@ -30,6 +31,7 @@ specifiers:
form-data: ^4.0.0
husky: ^7.0.4
lint-staged: ^12.1.4
+ lodash-es: ^4.17.21
mockjs: ^1.1.0
naive-ui: ^2.23.2
patch-package: ^6.4.7
@@ -55,9 +57,11 @@ specifiers:
dependencies:
'@vueuse/core': registry.npmmirror.com/@vueuse/core/7.5.1_vue@3.2.26
axios: registry.npmmirror.com/axios/0.24.0
+ colord: registry.npmmirror.com/colord/2.9.2
crypto-js: registry.npmmirror.com/crypto-js/4.1.1
dayjs: registry.npmmirror.com/dayjs/1.10.7
form-data: registry.nlark.com/form-data/4.0.0
+ lodash-es: registry.npmmirror.com/lodash-es/4.17.21
naive-ui: registry.npmmirror.com/naive-ui/2.23.2_vue@3.2.26
pinia: registry.npmmirror.com/pinia/2.0.9_typescript@4.5.4+vue@3.2.26
qs: registry.npmmirror.com/qs/6.10.2
@@ -4217,6 +4221,12 @@ packages:
dependencies:
color-name: registry.nlark.com/color-name/1.1.4
+ registry.npmmirror.com/colord/2.9.2:
+ resolution: {integrity: sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/colord/download/colord-2.9.2.tgz}
+ name: colord
+ version: 2.9.2
+ dev: false
+
registry.npmmirror.com/colorette/2.0.16:
resolution: {integrity: sha1-cTua+E/bAAE58EVGvUqT9ipQhdo=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/colorette/download/colorette-2.0.16.tgz?cache=0&sync_timestamp=1633673609067&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcolorette%2Fdownload%2Fcolorette-2.0.16.tgz}
name: colorette
diff --git a/src/App.vue b/src/App.vue
index e905dd5b..9edec8f8 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,6 +1,19 @@
-
+
+
+
-
+
diff --git a/src/assets/base.css b/src/assets/base.css
deleted file mode 100644
index 71dc55a3..00000000
--- a/src/assets/base.css
+++ /dev/null
@@ -1,74 +0,0 @@
-/* color palette from */
-:root {
- --vt-c-white: #ffffff;
- --vt-c-white-soft: #f8f8f8;
- --vt-c-white-mute: #f2f2f2;
-
- --vt-c-black: #181818;
- --vt-c-black-soft: #222222;
- --vt-c-black-mute: #282828;
-
- --vt-c-indigo: #2c3e50;
-
- --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
- --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
- --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
- --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
-
- --vt-c-text-light-1: var(--vt-c-indigo);
- --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
- --vt-c-text-dark-1: var(--vt-c-white);
- --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
-}
-
-/* semantic color variables for this project */
-:root {
- --color-background: var(--vt-c-white);
- --color-background-soft: var(--vt-c-white-soft);
- --color-background-mute: var(--vt-c-white-mute);
-
- --color-border: var(--vt-c-divider-light-2);
- --color-border-hover: var(--vt-c-divider-light-1);
-
- --color-heading: var(--vt-c-text-light-1);
- --color-text: var(--vt-c-text-light-1);
-
- --section-gap: 160px;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --color-background: var(--vt-c-black);
- --color-background-soft: var(--vt-c-black-soft);
- --color-background-mute: var(--vt-c-black-mute);
-
- --color-border: var(--vt-c-divider-dark-2);
- --color-border-hover: var(--vt-c-divider-dark-1);
-
- --color-heading: var(--vt-c-text-dark-1);
- --color-text: var(--vt-c-text-dark-2);
- }
-}
-
-*,
-*::before,
-*::after {
- box-sizing: border-box;
- margin: 0;
- position: relative;
- font-weight: normal;
-}
-
-body {
- min-height: 100vh;
- color: var(--color-text);
- background: var(--color-background);
- transition: color 0.5s, background-color 0.5s;
- line-height: 1.6;
- font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
- Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
- font-size: 15px;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
diff --git a/src/assets/logo.svg b/src/assets/logo.svg
deleted file mode 100644
index bc826fed..00000000
--- a/src/assets/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 07ace1c4..69e55df9 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,10 +4,6 @@ import { setupRouter } from '@/router';
import { setupStore } from '@/store';
import App from './App.vue';
-function setupPlugins() {
- setupAssets();
-}
-
async function setupApp() {
const app = createApp(App);
@@ -21,5 +17,6 @@ async function setupApp() {
app.mount('#app');
}
-setupPlugins();
+setupAssets();
+
setupApp();
diff --git a/src/store/modules/theme/helpers.ts b/src/store/modules/theme/helpers.ts
new file mode 100644
index 00000000..271b8dd3
--- /dev/null
+++ b/src/store/modules/theme/helpers.ts
@@ -0,0 +1,40 @@
+import { colord } from 'colord';
+import { getColorPalette } from '@/utils';
+
+type ColorType = 'primary' | 'info' | 'success' | 'warning' | 'error';
+
+type ColorScene = '' | 'Suppl' | 'Hover' | 'Pressed' | 'Active';
+
+type ColorKey = `${ColorType}Color${ColorScene}`;
+
+type ThemeColor = {
+ [key in ColorKey]?: string;
+};
+
+interface ColorAction {
+ scene: ColorScene;
+ handler: (color: string) => string;
+}
+
+/** 获取主题颜色的各种场景对应的颜色 */
+export function getThemeColors(colors: [ColorType, string][]) {
+ const colorActions: ColorAction[] = [
+ { scene: '', handler: color => color },
+ { scene: 'Suppl', handler: color => color },
+ { scene: 'Hover', handler: color => getColorPalette(color, 5) },
+ { scene: 'Pressed', handler: color => getColorPalette(color, 7) },
+ { scene: 'Active', handler: color => colord(color).alpha(0.1).toHex() }
+ ];
+
+ const themeColor: ThemeColor = {};
+
+ colors.forEach(color => {
+ colorActions.forEach(action => {
+ const [colorType, colorValue] = color;
+ const colorKey: ColorKey = `${colorType}Color${action.scene}`;
+ themeColor[colorKey] = action.handler(colorValue);
+ });
+ });
+
+ return themeColor;
+}
diff --git a/src/store/modules/theme/index.ts b/src/store/modules/theme/index.ts
index 1d5a0fe0..23884f08 100644
--- a/src/store/modules/theme/index.ts
+++ b/src/store/modules/theme/index.ts
@@ -1,7 +1,87 @@
+import { ref, computed } from 'vue';
+import type { Ref, ComputedRef } from 'vue';
import { defineStore } from 'pinia';
+import { useThemeVars } from 'naive-ui';
+import type { GlobalThemeOverrides } from 'naive-ui';
+import { kebabCase } from 'lodash-es';
+import { getColorPalette } from '@/utils';
+import { getThemeColors } from './helpers';
-// interface ThemeStore {
-// primary: string;
-// }
+interface OtherColor {
+ /** 信息 */
+ info: string;
+ /** 成功 */
+ success: string;
+ /** 警告 */
+ warning: string;
+ /** 错误 */
+ error: string;
+}
-export const useThemeStore = defineStore('theme-store', () => {});
+interface ThemeStore {
+ /** 主题颜色 */
+ themeColor: Ref;
+ /** 其他颜色 */
+ otherColor: ComputedRef;
+ /** naiveUI的主题配置 */
+ naiveThemeOverrides: ComputedRef;
+ /** 添加css vars至html */
+ addThemeCssVarsToRoot(): void;
+}
+
+type ThemeVarsKeys = keyof Exclude;
+
+export const useThemeStore = defineStore('theme-store', () => {
+ const themeVars = useThemeVars();
+
+ const themeColor = ref('#1890ff');
+ const otherColor = computed(() => ({
+ info: getColorPalette(themeColor.value, 7),
+ success: '#52c41a',
+ warning: '#faad14',
+ error: '#f5222d'
+ }));
+
+ const naiveThemeOverrides = computed(() => {
+ const { info, success, warning, error } = otherColor.value;
+ const themeColors = getThemeColors([
+ ['primary', themeColor.value],
+ ['info', info],
+ ['success', success],
+ ['warning', warning],
+ ['error', error]
+ ]);
+
+ const colorLoading = themeColor.value;
+
+ return {
+ common: {
+ ...themeColors
+ },
+ LoadingBar: {
+ colorLoading
+ }
+ };
+ });
+
+ function addThemeCssVarsToRoot() {
+ const updatedThemeVars = { ...themeVars.value };
+ Object.assign(updatedThemeVars, naiveThemeOverrides.value.common);
+ const keys = Object.keys(updatedThemeVars) as ThemeVarsKeys[];
+ const style: string[] = [];
+ keys.forEach(key => {
+ style.push(`--${kebabCase(key)}: ${updatedThemeVars[key]}`);
+ });
+ const styleStr = style.join(';');
+ document.documentElement.style.cssText += styleStr;
+ }
+
+ const themeStore: ThemeStore = {
+ themeColor,
+ otherColor,
+ naiveThemeOverrides,
+ addThemeCssVarsToRoot
+ };
+
+ return themeStore;
+});
diff --git a/src/utils/common/color.ts b/src/utils/common/color.ts
new file mode 100644
index 00000000..29a42176
--- /dev/null
+++ b/src/utils/common/color.ts
@@ -0,0 +1,116 @@
+import { colord } from 'colord';
+import type { HsvColor } from 'colord';
+
+type ColorIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
+
+const hueStep = 2;
+const saturationStep = 16;
+const saturationStep2 = 5;
+const brightnessStep1 = 5;
+const brightnessStep2 = 15;
+const lightColorCount = 5;
+const darkColorCount = 4;
+
+/**
+ * 根据颜色获取调色板颜色(从左至右颜色从浅到深,6为主色号)
+ * @param color - 颜色
+ * @param index - 调色板的对应的色号(6为主色号)
+ * @description 算法实现从ant-design调色板算法中借鉴 https://github.com/ant-design/ant-design/blob/master/components/style/color/colorPalette.less
+ */
+export function getColorPalette(color: string, index: ColorIndex) {
+ if (index === 6) return color;
+
+ const isLight = index < 6;
+ const hsv = colord(color).toHsv();
+ const i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;
+
+ const newHsv: HsvColor = {
+ h: getHue(hsv, i, isLight),
+ s: getSaturation(hsv, i, isLight),
+ v: getValue(hsv, i, isLight)
+ };
+
+ return colord(newHsv).toHex();
+}
+
+/**
+ * 根据颜色获取调色板颜色所有颜色
+ * @param color - 颜色
+ */
+export function getAllColorPalette(color: string) {
+ const indexs: ColorIndex[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ return indexs.map(index => getColorPalette(color, index));
+}
+
+/**
+ * 获取色相渐变
+ * @param hsv - hsv格式颜色值
+ * @param i - 与6的相对距离
+ * @param isLight - 是否是亮颜色
+ */
+function getHue(hsv: HsvColor, i: number, isLight: boolean) {
+ let hue: number;
+ if (hsv.h >= 60 && hsv.h <= 240) {
+ // 冷色调
+ // 减淡变亮 色相顺时针旋转 更暖
+ // 加深变暗 色相逆时针旋转 更冷
+ hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i;
+ } else {
+ // 暖色调
+ // 减淡变亮 色相逆时针旋转 更暖
+ // 加深变暗 色相顺时针旋转 更冷
+ hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i;
+ }
+ if (hue < 0) {
+ hue += 360;
+ } else if (hue >= 360) {
+ hue -= 360;
+ }
+ return hue;
+}
+
+/**
+ * 获取饱和度渐变
+ * @param hsv - hsv格式颜色值
+ * @param i - 与6的相对距离
+ * @param isLight - 是否是亮颜色
+ */
+function getSaturation(hsv: HsvColor, i: number, isLight: boolean) {
+ let saturation: number;
+ if (isLight) {
+ saturation = hsv.s - saturationStep * i;
+ } else if (i === darkColorCount) {
+ saturation = hsv.s + saturationStep;
+ } else {
+ saturation = hsv.s + saturationStep2 * i;
+ }
+ if (saturation > 100) {
+ saturation = 100;
+ }
+ if (isLight && i === lightColorCount && saturation > 10) {
+ saturation = 10;
+ }
+ if (saturation < 6) {
+ saturation = 6;
+ }
+ return saturation;
+}
+
+/**
+ * 获取明度渐变
+ * @param hsv - hsv格式颜色值
+ * @param i - 与6的相对距离
+ * @param isLight - 是否是亮颜色
+ */
+function getValue(hsv: HsvColor, i: number, isLight: boolean) {
+ let value: number;
+ if (isLight) {
+ value = hsv.v + brightnessStep1 * i;
+ } else {
+ value = hsv.v - brightnessStep2 * i;
+ }
+ if (value > 100) {
+ value = 100;
+ }
+ return value;
+}
diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts
index 6502676e..72ad0c66 100644
--- a/src/utils/common/index.ts
+++ b/src/utils/common/index.ts
@@ -1,3 +1,4 @@
export * from './typeof';
export * from './console';
+export * from './color';
export * from './design-pattern';
diff --git a/src/views/system/login/index.vue b/src/views/system/login/index.vue
index a49ec556..0813c3ca 100644
--- a/src/views/system/login/index.vue
+++ b/src/views/system/login/index.vue
@@ -1,5 +1,7 @@
-
+
+
Login
+
diff --git a/windi.config.ts b/windi.config.ts
index 49a1b798..94f59d86 100644
--- a/windi.config.ts
+++ b/windi.config.ts
@@ -42,7 +42,30 @@ export default defineConfig({
'ellipsis-text': 'nowrap-hidden overflow-ellipsis'
},
theme: {
- extend: {}
+ extend: {
+ colors: {
+ primary: 'var(--primary-color)',
+ 'primary-hover': 'var(--primary-color-hover)',
+ 'primary-pressed': 'var(--primary-color-pressed)',
+ 'primary-active': 'var(--primary-color-active)',
+ info: 'var(--info-color)',
+ 'info-hover': 'var(--info-color-hover)',
+ 'info-pressed': 'var(--info-color-pressed)',
+ 'info-active': 'var(--info-color-active)',
+ success: 'var(--success-color)',
+ 'success-hover': 'var(--success-color-hover)',
+ 'success-pressed': 'var(--success-color-pressed)',
+ 'success-active': 'var(--success-color-active)',
+ warning: 'var(--warning-color)',
+ 'warning-hover': 'var(--warning-color-hover)',
+ 'warning-pressed': 'var(--warning-color-pressed)',
+ 'warning-active': 'var(--warning-color-active)',
+ error: 'var(--error-color)',
+ 'error-hover': 'var(--error-color-hover)',
+ 'error-pressed': 'var(--error-color-pressed)',
+ 'error-active': 'var(--error-color-active)'
+ }
+ }
},
variants: {},
plugins: []