Browse Source

feat: 修改主题

dev-zw-notification
zhaowei 5 months ago
parent
commit
c9d4aba825
6 changed files with 202 additions and 2 deletions
  1. +1
    -1
      react-ui/config/defaultSettings.ts
  2. +3
    -0
      react-ui/package.json
  3. +1
    -1
      react-ui/src/app.tsx
  4. +25
    -0
      react-ui/src/components/KFButton/index.less
  5. +75
    -0
      react-ui/src/components/KFButton/index.tsx
  6. +97
    -0
      react-ui/src/utils/color.ts

+ 1
- 1
react-ui/config/defaultSettings.ts View File

@@ -9,7 +9,7 @@ const Settings: ProLayoutProps & {
} = { } = {
locale: 'zh-CN', locale: 'zh-CN',
navTheme: 'light', navTheme: 'light',
// 拂晓蓝
colorPrimary: '#514cf9',
// layout: 'mix', // layout: 'mix',
contentWidth: 'Fluid', contentWidth: 'Fluid',
fixedHeader: false, fixedHeader: false,


+ 3
- 0
react-ui/package.json View File

@@ -60,14 +60,17 @@
"not ie <= 10" "not ie <= 10"
], ],
"dependencies": { "dependencies": {
"@ant-design/colors": "~7.2.1",
"@ant-design/icons": "^5.0.0", "@ant-design/icons": "^5.0.0",
"@ant-design/pro-components": "^2.4.4", "@ant-design/pro-components": "^2.4.4",
"@ant-design/use-emotion-css": "1.0.4", "@ant-design/use-emotion-css": "1.0.4",
"@antv/g6": "^4.8.24", "@antv/g6": "^4.8.24",
"@antv/hierarchy": "^0.6.12", "@antv/hierarchy": "^0.6.12",
"@ctrl/tinycolor": "~4.1.0",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@umijs/route-utils": "^4.0.1", "@umijs/route-utils": "^4.0.1",
"antd": "~5.21.4", "antd": "~5.21.4",
"antd-style": "~3.7.1",
"caniuse-lite": "~1.0.30001707", "caniuse-lite": "~1.0.30001707",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",


+ 1
- 1
react-ui/src/app.tsx View File

@@ -192,7 +192,7 @@ export const antd: RuntimeAntdConfig = (memo) => {
colorPrimary: themes['primaryColor'], colorPrimary: themes['primaryColor'],
colorPrimaryHover: themes['primaryHoverColor'], colorPrimaryHover: themes['primaryHoverColor'],
colorPrimaryActive: themes['primaryActiveColor'], colorPrimaryActive: themes['primaryActiveColor'],
colorPrimaryBg: 'rgba(81, 76, 249, 0.07)',
// colorPrimaryBg: 'rgba(81, 76, 249, 0.07)',
colorSuccess: themes['successColor'], colorSuccess: themes['successColor'],
colorError: themes['errorColor'], colorError: themes['errorColor'],
colorWarning: themes['warningColor'], colorWarning: themes['warningColor'],


+ 25
- 0
react-ui/src/components/KFButton/index.less View File

@@ -0,0 +1,25 @@
body {
.kf-primary-button.ant-btn-color-primary.ant-btn-variant-link {
background-color: .addAlpha(@primary-color, 0.07) [] !important;
}

.kf-default-button.ant-btn-color-default.ant-btn-variant-link {
background-color: .addAlpha(@text-color-secondary, 0.07) [] !important;
}

.kf-danger-button.ant-btn-color-danger.ant-btn-variant-link {
background-color: .addAlpha(@error-color, 0.07) [] !important;
}

.ant-btn-color-default.ant-btn-variant-link.kf-default-button:not(:disabled):not(
.ant-btn-disabled
):hover {
color: .addAlpha(@text-color-secondary, 0.5) [];
}

.ant-btn-color-default.ant-btn-variant-link.kf-default-button:not(:disabled):not(
.ant-btn-disabled
):active {
color: @text-color-secondary;
}
}

+ 75
- 0
react-ui/src/components/KFButton/index.tsx View File

@@ -0,0 +1,75 @@
import themes from '@/styles/theme.less';
import { addAlpha, derivePrimaryStates } from '@/utils/color';
import { Button, ButtonProps } from 'antd';
import { createStyles } from 'antd-style';
import './index.less';

type KFColor = 'primary' | 'default' | 'danger';

export interface KFButtonProps extends ButtonProps {
kfColor?: KFColor;
}

const useStyles = createStyles(({ token, css }) => ({
primary: css`
color: ${token.colorPrimary} !important;
background-color: ${addAlpha(themes['primaryColor'], 0.07)} !important;

&:hover {
color: ${token.colorPrimaryHover} !important;
}

&:active {
color: ${token.colorPrimaryActive} !important;
}
`,
default: css`
color: ${themes['textColorSecondary']} !important;
background-color: ${addAlpha(themes['textColorSecondary'], 0.07)} !important;

&:hover {
color: ${derivePrimaryStates(themes['textColorSecondary']).colorPrimaryHover} !important;
}

&:active {
color: ${derivePrimaryStates(themes['textColorSecondary']).colorPrimaryActive} !important;
}
`,
danger: css`
color: ${themes['errorColor']} !important;
background-color: ${addAlpha(themes['errorColor'], 0.07)} !important;

&:hover {
color: ${derivePrimaryStates(themes['errorColor']).colorPrimaryHover} !important;
}

&:active {
color: ${derivePrimaryStates(themes['errorColor']).colorPrimaryActive} !important;
}
`,
}));

function KFButton({ kfColor = 'default', className, ...rest }: KFButtonProps) {
const { styles, cx } = useStyles();

let style = '';
switch (kfColor) {
case 'primary':
style = styles.primary;
break;
case 'default':
style = styles.default;
break;
case 'danger':
style = styles.danger;
break;
default:
break;
}

return (
<Button {...rest} className={cx(className, style)} color={kfColor} variant="link"></Button>
);
}

export default KFButton;

+ 97
- 0
react-ui/src/utils/color.ts View File

@@ -0,0 +1,97 @@
/*
* @Author: 赵伟
* @Date: 2025-09-02 09:52:50
* @Description: 兼容 Antd 颜色设置
*/

// 安装依赖:npm i @ant-design/colors
import { generate } from '@ant-design/colors';
import { TinyColor } from '@ctrl/tinycolor';

type Options = {
/** 是否使用暗色算法(需传背景色,默认按 AntD 暗色背景) */
dark?: boolean;
backgroundColor?: string; // 仅 dark 为 true 时生效
};

export function derivePrimaryStates(seed: string, opts: Options = {}) {
const { dark = false, backgroundColor = '#141414' } = opts;
const palette = generate(seed, dark ? { theme: 'dark', backgroundColor } : undefined);

return {
// 基础主色
colorPrimary: palette[5], // 主色(第 6 阶)

// 状态
colorPrimaryHover: palette[4], // hover(第 5 阶)
colorPrimaryActive: palette[6], // active(第 7 阶)
colorPrimaryTextHover: palette[4], // 文本 hover
colorPrimaryTextActive: palette[6], // 文本 active

// 背景
colorPrimaryBg: palette[0], // 浅背景(第 1 阶)
colorPrimaryBgHover: palette[1], // 背景 hover(第 2 阶)

// 边框
colorPrimaryBorder: palette[2], // 普通边框(第 3 阶)
colorPrimaryBorderHover: palette[3], // 边框 hover(第 4 阶)

// 文本
colorPrimaryText: palette[5], // 主文本(等同于 colorPrimary)

// 备用(有时用于选中态阴影/描边)
colorPrimaryShadow: palette[6],
};
}

export function derivePrimaryStates2(color: string) {
const base = new TinyColor(color);
return {
colorPrimaryHover: base.lighten(10).toHexString(),
colorPrimaryActive: base.darken(10).toHexString(),
};
}

/**
* 给颜色值添加透明度.
*
* @param color - 颜色值, #ff0000、#888 或者 rgb(255, 0, 0)
* @param alpha - 透明的,0~1
* @return 颜色值,rgba
*/

export function addAlpha(color: string, alpha: number): string {
const alphaFixed = Math.max(0, Math.min(1, alpha)); // 保证在 [0,1]

// #rrggbb 或 #rgb
if (color.startsWith('#')) {
let r: number, g: number, b: number;

if (color.length === 4) {
// #rgb
r = parseInt(color[1] + color[1], 16);
g = parseInt(color[2] + color[2], 16);
b = parseInt(color[3] + color[3], 16);
} else if (color.length === 7) {
// #rrggbb
r = parseInt(color.slice(1, 3), 16);
g = parseInt(color.slice(3, 5), 16);
b = parseInt(color.slice(5, 7), 16);
} else {
throw new Error('Invalid hex color format');
}

return `rgba(${r}, ${g}, ${b}, ${alphaFixed})`;
}

// rgb(r,g,b)
const rgbMatch = color.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/i);
if (rgbMatch) {
const r = parseInt(rgbMatch[1], 10);
const g = parseInt(rgbMatch[2], 10);
const b = parseInt(rgbMatch[3], 10);
return `rgba(${r}, ${g}, ${b}, ${alphaFixed})`;
}

throw new Error('Unsupported color format');
}

Loading…
Cancel
Save