1
0
Files
nex/frontend/src/themes/glass.ts
lanyuanxiaoyao ddd284c1ca feat: 实现多主题系统,支持6套主题切换和设置页面
重构 ThemeContext 为多主题模型(themeId + followSystem + systemIsDark),
新增设置页面(主题下拉栏 + 跟随系统开关),移除旧 ThemeToggle 按钮,
引入 antd-style 和 clsx 依赖支持 MUI/shadcn/Bootstrap/玻璃主题。
2026-04-17 00:06:08 +08:00

215 lines
5.1 KiB
TypeScript

import { useMemo } from 'react';
import { theme } from 'antd';
import type { ConfigProviderProps } from 'antd';
import { createStyles } from 'antd-style';
import clsx from 'clsx';
const useStyles = createStyles(({ css, cssVar }) => {
const glassBorder = {
boxShadow: [
`${cssVar.boxShadowSecondary}`,
`inset 0 0 5px 2px rgba(255, 255, 255, 0.3)`,
`inset 0 5px 2px rgba(255, 255, 255, 0.2)`,
].join(','),
};
const glassBox = {
...glassBorder,
background: `color-mix(in srgb, ${cssVar.colorBgContainer} 15%, transparent)`,
backdropFilter: 'blur(12px)',
};
return {
glassBorder,
glassBox,
notBackdropFilter: css({
backdropFilter: 'none',
}),
app: css({
textShadow: '0 1px rgba(0,0,0,0.1)',
}),
cardRoot: css({
...glassBox,
backgroundColor: `color-mix(in srgb, ${cssVar.colorBgContainer} 40%, transparent)`,
}),
modalContainer: css({
...glassBox,
backdropFilter: 'none',
}),
buttonRoot: css({
...glassBorder,
}),
buttonRootDefaultColor: css({
background: 'transparent',
color: cssVar.colorText,
'&:hover': {
background: 'rgba(255,255,255,0.2)',
color: `color-mix(in srgb, ${cssVar.colorText} 90%, transparent)`,
},
'&:active': {
background: 'rgba(255,255,255,0.1)',
color: `color-mix(in srgb, ${cssVar.colorText} 80%, transparent)`,
},
}),
dropdownRoot: css({
...glassBox,
borderRadius: cssVar.borderRadiusLG,
ul: {
background: 'transparent',
},
}),
switchRoot: css({ ...glassBorder, border: 'none' }),
segmentedRoot: css({
...glassBorder,
background: 'transparent',
backdropFilter: 'none',
'& .ant-segmented-thumb': {
...glassBox,
},
'& .ant-segmented-item-selected': {
...glassBox,
},
}),
radioButtonRoot: css({
'&.ant-radio-button-wrapper': {
...glassBorder,
background: 'transparent',
borderColor: 'rgba(255, 255, 255, 0.2)',
color: cssVar.colorText,
'&:hover': {
borderColor: 'rgba(255, 255, 255, 0.24)',
color: cssVar.colorText,
},
'&.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)': {
...glassBox,
borderColor: 'rgba(255, 255, 255, 0.28)',
color: cssVar.colorText,
'&::before': {
backgroundColor: 'rgba(255, 255, 255, 0.18)',
},
'&:hover': {
color: cssVar.colorText,
},
},
},
}),
};
});
const useGlassTheme = () => {
const { styles } = useStyles();
return useMemo<ConfigProviderProps>(
() => ({
theme: {
algorithm: theme.defaultAlgorithm,
token: {
borderRadius: 12,
borderRadiusLG: 12,
borderRadiusSM: 12,
borderRadiusXS: 12,
motionDurationSlow: '0.2s',
motionDurationMid: '0.1s',
motionDurationFast: '0.05s',
},
},
app: {
className: styles.app,
},
card: {
classNames: {
root: styles.cardRoot,
},
},
modal: {
classNames: {
container: styles.modalContainer,
},
},
button: {
classNames: ({ props }) => ({
root: clsx(
styles.buttonRoot,
(props.variant !== 'solid' || props.color === 'default' || props.type === 'default') &&
styles.buttonRootDefaultColor,
),
}),
},
alert: {
className: clsx(styles.glassBox, styles.notBackdropFilter),
},
colorPicker: {
classNames: {
root: clsx(styles.glassBox, styles.notBackdropFilter),
},
arrow: false,
},
dropdown: {
classNames: {
root: styles.dropdownRoot,
},
},
select: {
classNames: {
root: clsx(styles.glassBox, styles.notBackdropFilter),
popup: {
root: styles.glassBox,
},
},
},
datePicker: {
classNames: {
root: clsx(styles.glassBox, styles.notBackdropFilter),
popup: {
container: styles.glassBox,
},
},
},
input: {
classNames: {
root: clsx(styles.glassBox, styles.notBackdropFilter),
},
},
inputNumber: {
classNames: {
root: clsx(styles.glassBox, styles.notBackdropFilter),
},
},
popover: {
classNames: {
container: styles.glassBox,
},
},
switch: {
classNames: {
root: styles.switchRoot,
},
},
radio: {
classNames: {
root: styles.radioButtonRoot,
},
},
segmented: {
className: styles.segmentedRoot,
},
progress: {
classNames: {
track: styles.glassBorder,
},
styles: {
track: {
height: 12,
},
rail: {
height: 12,
},
},
},
}),
[],
);
};
export default useGlassTheme;