feat(GlassCard): 新增通用毛玻璃卡片组件
- 支持多种变体: default, elevated, subtle, transparent - 支持悬停效果、发光效果、角落装饰 - 黑金配色主题,可全局复用 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
179
src/components/GlassCard/index.js
Normal file
179
src/components/GlassCard/index.js
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/**
|
||||||
|
* GlassCard - 通用毛玻璃卡片组件
|
||||||
|
*
|
||||||
|
* 复用自 Company 页面的 Glassmorphism 风格
|
||||||
|
* 可在全局使用
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { memo, forwardRef } from 'react';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
// 主题配置
|
||||||
|
const GLASS_THEME = {
|
||||||
|
colors: {
|
||||||
|
gold: {
|
||||||
|
400: '#D4AF37',
|
||||||
|
500: '#B8960C',
|
||||||
|
},
|
||||||
|
bg: {
|
||||||
|
deep: '#0A0A14',
|
||||||
|
primary: '#0F0F1A',
|
||||||
|
elevated: '#1A1A2E',
|
||||||
|
surface: '#252540',
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
subtle: 'rgba(212, 175, 55, 0.1)',
|
||||||
|
default: 'rgba(212, 175, 55, 0.2)',
|
||||||
|
emphasis: 'rgba(212, 175, 55, 0.4)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
blur: {
|
||||||
|
sm: 'blur(8px)',
|
||||||
|
md: 'blur(16px)',
|
||||||
|
lg: 'blur(24px)',
|
||||||
|
},
|
||||||
|
glow: {
|
||||||
|
sm: '0 0 8px rgba(212, 175, 55, 0.3)',
|
||||||
|
md: '0 0 16px rgba(212, 175, 55, 0.4)',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 变体样式
|
||||||
|
const VARIANTS = {
|
||||||
|
default: {
|
||||||
|
bg: `linear-gradient(135deg, ${GLASS_THEME.colors.bg.elevated} 0%, ${GLASS_THEME.colors.bg.primary} 100%)`,
|
||||||
|
border: `1px solid ${GLASS_THEME.colors.line.default}`,
|
||||||
|
backdropFilter: GLASS_THEME.blur.md,
|
||||||
|
},
|
||||||
|
elevated: {
|
||||||
|
bg: `linear-gradient(145deg, ${GLASS_THEME.colors.bg.surface} 0%, ${GLASS_THEME.colors.bg.elevated} 100%)`,
|
||||||
|
border: `1px solid ${GLASS_THEME.colors.line.emphasis}`,
|
||||||
|
backdropFilter: GLASS_THEME.blur.lg,
|
||||||
|
},
|
||||||
|
subtle: {
|
||||||
|
bg: 'rgba(212, 175, 55, 0.05)',
|
||||||
|
border: `1px solid ${GLASS_THEME.colors.line.subtle}`,
|
||||||
|
backdropFilter: GLASS_THEME.blur.sm,
|
||||||
|
},
|
||||||
|
transparent: {
|
||||||
|
bg: 'rgba(15, 15, 26, 0.8)',
|
||||||
|
border: `1px solid ${GLASS_THEME.colors.line.default}`,
|
||||||
|
backdropFilter: GLASS_THEME.blur.lg,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ROUNDED_MAP = {
|
||||||
|
sm: '8px',
|
||||||
|
md: '12px',
|
||||||
|
lg: '16px',
|
||||||
|
xl: '20px',
|
||||||
|
'2xl': '24px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const PADDING_MAP = {
|
||||||
|
none: 0,
|
||||||
|
sm: 3,
|
||||||
|
md: 4,
|
||||||
|
lg: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 角落装饰
|
||||||
|
const CornerDecor = memo(({ position }) => {
|
||||||
|
const baseStyle = {
|
||||||
|
position: 'absolute',
|
||||||
|
width: '12px',
|
||||||
|
height: '12px',
|
||||||
|
borderColor: GLASS_THEME.colors.gold[400],
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderWidth: 0,
|
||||||
|
opacity: 0.6,
|
||||||
|
};
|
||||||
|
|
||||||
|
const positions = {
|
||||||
|
tl: { top: '8px', left: '8px', borderTopWidth: '2px', borderLeftWidth: '2px' },
|
||||||
|
tr: { top: '8px', right: '8px', borderTopWidth: '2px', borderRightWidth: '2px' },
|
||||||
|
bl: { bottom: '8px', left: '8px', borderBottomWidth: '2px', borderLeftWidth: '2px' },
|
||||||
|
br: { bottom: '8px', right: '8px', borderBottomWidth: '2px', borderRightWidth: '2px' },
|
||||||
|
};
|
||||||
|
|
||||||
|
return <Box sx={{ ...baseStyle, ...positions[position] }} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
CornerDecor.displayName = 'CornerDecor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GlassCard 组件
|
||||||
|
*
|
||||||
|
* @param {string} variant - 变体: 'default' | 'elevated' | 'subtle' | 'transparent'
|
||||||
|
* @param {boolean} hoverable - 是否启用悬停效果
|
||||||
|
* @param {boolean} glowing - 是否启用发光效果
|
||||||
|
* @param {boolean} cornerDecor - 是否显示角落装饰
|
||||||
|
* @param {string} rounded - 圆角: 'sm' | 'md' | 'lg' | 'xl' | '2xl'
|
||||||
|
* @param {string} padding - 内边距: 'none' | 'sm' | 'md' | 'lg'
|
||||||
|
*/
|
||||||
|
const GlassCard = forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
children,
|
||||||
|
variant = 'default',
|
||||||
|
hoverable = true,
|
||||||
|
glowing = false,
|
||||||
|
cornerDecor = false,
|
||||||
|
rounded = 'lg',
|
||||||
|
padding = 'md',
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const variantStyle = VARIANTS[variant] || VARIANTS.default;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
ref={ref}
|
||||||
|
position="relative"
|
||||||
|
bg={variantStyle.bg}
|
||||||
|
border={variantStyle.border}
|
||||||
|
borderRadius={ROUNDED_MAP[rounded]}
|
||||||
|
backdropFilter={variantStyle.backdropFilter}
|
||||||
|
p={PADDING_MAP[padding]}
|
||||||
|
transition="all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)"
|
||||||
|
overflow="hidden"
|
||||||
|
_hover={
|
||||||
|
hoverable
|
||||||
|
? {
|
||||||
|
borderColor: GLASS_THEME.colors.line.emphasis,
|
||||||
|
boxShadow: glowing ? GLASS_THEME.glow.md : GLASS_THEME.glow.sm,
|
||||||
|
transform: 'translateY(-2px)',
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
...(glowing && {
|
||||||
|
boxShadow: GLASS_THEME.glow.sm,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{/* 角落装饰 */}
|
||||||
|
{cornerDecor && (
|
||||||
|
<>
|
||||||
|
<CornerDecor position="tl" />
|
||||||
|
<CornerDecor position="tr" />
|
||||||
|
<CornerDecor position="bl" />
|
||||||
|
<CornerDecor position="br" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 内容 */}
|
||||||
|
<Box position="relative" zIndex={1}>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
GlassCard.displayName = 'GlassCard';
|
||||||
|
|
||||||
|
export default memo(GlassCard);
|
||||||
|
export { GLASS_THEME };
|
||||||
Reference in New Issue
Block a user