100 lines
4.0 KiB
JavaScript
100 lines
4.0 KiB
JavaScript
import { Card } from '@astryxdesign/core/Card';
|
|
|
|
// ==============================|| STAT / KPI CARD ||============================== //
|
|
|
|
export default function StatCard({ title, value, icon: Icon, color = 'primary', trend, caption, size = 'md' }) {
|
|
const trendUp = typeof trend === 'number' ? trend >= 0 : null;
|
|
const isCompact = size === 'sm';
|
|
|
|
// Map theme colors to CSS values
|
|
const colorMap = {
|
|
primary: { main: '#C01227', light: 'rgba(192, 18, 39, 0.04)', border: 'rgba(192, 18, 39, 0.1)' },
|
|
secondary: { main: '#475569', light: 'rgba(71, 85, 105, 0.04)', border: 'rgba(71, 85, 105, 0.1)' },
|
|
success: { main: '#10b981', light: 'rgba(16, 185, 129, 0.04)', border: 'rgba(16, 185, 129, 0.1)' },
|
|
warning: { main: '#f59e0b', light: 'rgba(245, 158, 11, 0.04)', border: 'rgba(245, 158, 11, 0.1)' },
|
|
error: { main: '#ef4444', light: 'rgba(239, 68, 68, 0.04)', border: 'rgba(239, 68, 68, 0.1)' },
|
|
info: { main: '#3b82f6', light: 'rgba(59, 130, 246, 0.04)', border: 'rgba(59, 130, 246, 0.1)' }
|
|
};
|
|
|
|
const themeColor = colorMap[color] || colorMap.primary;
|
|
|
|
return (
|
|
<Card
|
|
style={{
|
|
height: '100%',
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
borderRadius: isCompact ? '12px' : '16px',
|
|
padding: isCompact ? '16px' : '24px',
|
|
border: `1px solid ${themeColor.border}`,
|
|
boxShadow: '0 4px 20px rgba(0,0,0,0.02)',
|
|
background: `linear-gradient(135deg, #ffffff 0%, ${themeColor.light} 100%)`,
|
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
cursor: 'pointer',
|
|
boxSizing: 'border-box'
|
|
}}
|
|
className="stat-card"
|
|
>
|
|
{Icon && (
|
|
<div style={{ position: 'absolute', right: '-12px', bottom: '-12px', opacity: 0.04, transform: 'rotate(-15deg)', pointerEvents: 'none', color: themeColor.main }}>
|
|
<Icon size={isCompact ? 64 : 96} />
|
|
</div>
|
|
)}
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: isCompact ? '10px' : '16px', position: 'relative', zIndex: 2 }}>
|
|
<span style={{ fontWeight: 700, fontSize: '0.75rem', color: '#64748b', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
|
|
{title}
|
|
</span>
|
|
{Icon && (
|
|
<div
|
|
style={{
|
|
width: isCompact ? '28px' : '36px',
|
|
height: isCompact ? '28px' : '36px',
|
|
borderRadius: '8px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
backgroundColor: 'rgba(192, 18, 39, 0.08)',
|
|
color: '#C01227'
|
|
}}
|
|
>
|
|
<Icon size={isCompact ? 14 : 18} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div style={{ flexGrow: 1, position: 'relative', zIndex: 2, marginBottom: (trendUp !== null || caption) ? (isCompact ? '10px' : '16px') : '0' }}>
|
|
<span style={{ fontWeight: 800, fontSize: isCompact ? '1.5rem' : '2rem', color: '#1e293b', lineHeight: 1, display: 'block' }}>
|
|
{value}
|
|
</span>
|
|
</div>
|
|
|
|
{(trendUp !== null || caption) && (
|
|
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '8px', paddingTop: isCompact ? '8px' : '12px', borderTop: '1px dashed #e2e8f0', position: 'relative', zIndex: 2 }}>
|
|
{trendUp !== null && (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '2px',
|
|
backgroundColor: trendUp ? '#E3F6EC' : '#FEEAE9',
|
|
padding: '2px 6px',
|
|
borderRadius: '4px'
|
|
}}
|
|
>
|
|
<span style={{ fontSize: '11px', fontWeight: 700, color: trendUp ? '#00773B' : '#A82216' }}>
|
|
{trendUp ? '↑' : '↓'} {Math.abs(trend)}%
|
|
</span>
|
|
</div>
|
|
)}
|
|
{caption && (
|
|
<span style={{ fontSize: '0.75rem', color: '#64748b', fontWeight: 600 }}>
|
|
{caption}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</Card>
|
|
);
|
|
}
|