@@ -1,99 +1,83 @@
|
||||
import { Card } from '@astryxdesign/core/Card';
|
||||
import { Card, CardContent, Box, Typography, Avatar, Stack } from '@mui/material';
|
||||
import ArrowUpwardRoundedIcon from '@mui/icons-material/ArrowUpwardRounded';
|
||||
import ArrowDownwardRoundedIcon from '@mui/icons-material/ArrowDownwardRounded';
|
||||
|
||||
// ==============================|| STAT / KPI CARD ||============================== //
|
||||
|
||||
export default function StatCard({ title, value, icon: Icon, color = 'primary', trend, caption, size = 'md' }) {
|
||||
export default function StatCard({ title, value, icon: Icon, color = 'primary', trend, caption, accent = false }) {
|
||||
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={{
|
||||
sx={{
|
||||
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%)`,
|
||||
borderRadius: 3,
|
||||
boxShadow: '0 8px 24px rgba(0,0,0,0.03)',
|
||||
border: '1px solid rgba(0,0,0,0.04)',
|
||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
cursor: 'pointer',
|
||||
boxSizing: 'border-box'
|
||||
'&:hover': { transform: 'translateY(-4px)', boxShadow: '0 16px 32px rgba(0,0,0,0.06)' },
|
||||
background: (theme) => `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${theme.palette[color].lighter}15 100%)`
|
||||
}}
|
||||
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>
|
||||
<Box sx={{ position: 'absolute', right: -15, bottom: -15, opacity: 0.04, transform: 'rotate(-15deg)', pointerEvents: 'none' }}>
|
||||
<Icon sx={{ fontSize: 110 }} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<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={{
|
||||
<CardContent sx={{ p: 2.5, '&:last-child': { pb: 2.5 }, height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-start" sx={{ mb: 1.5, position: 'relative', zIndex: 2 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 600, color: 'text.secondary' }}>
|
||||
{title}
|
||||
</Typography>
|
||||
{Icon && (
|
||||
<Box
|
||||
sx={{
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '2px',
|
||||
backgroundColor: trendUp ? '#E3F6EC' : '#FEEAE9',
|
||||
padding: '2px 6px',
|
||||
borderRadius: '4px'
|
||||
justifyContent: 'center',
|
||||
bgcolor: `${color}.lighter`,
|
||||
color: `${color}.main`,
|
||||
boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.05)'
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: '11px', fontWeight: 700, color: trendUp ? '#00773B' : '#A82216' }}>
|
||||
{trendUp ? '↑' : '↓'} {Math.abs(trend)}%
|
||||
</span>
|
||||
</div>
|
||||
<Icon fontSize="small" />
|
||||
</Box>
|
||||
)}
|
||||
{caption && (
|
||||
<span style={{ fontSize: '0.75rem', color: '#64748b', fontWeight: 600 }}>
|
||||
{caption}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Box sx={{ flexGrow: 1, position: 'relative', zIndex: 2 }}>
|
||||
<Typography variant="h4" sx={{ fontWeight: 800, color: 'grey.900', letterSpacing: '-0.5px', lineHeight: 1 }}>
|
||||
{value}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{(trendUp !== null || caption) && (
|
||||
<Stack direction="row" spacing={1} alignItems="center" sx={{ mt: 2, pt: 1.5, borderTop: '1px dashed rgba(0,0,0,0.06)', position: 'relative', zIndex: 2 }}>
|
||||
{trendUp !== null && (
|
||||
<Stack direction="row" spacing={0.25} alignItems="center" sx={{ bgcolor: trendUp ? 'success.lighter' : 'error.lighter', px: 0.75, py: 0.25, borderRadius: 1 }}>
|
||||
{trendUp ? (
|
||||
<ArrowUpwardRoundedIcon sx={{ fontSize: 14, color: 'success.dark' }} />
|
||||
) : (
|
||||
<ArrowDownwardRoundedIcon sx={{ fontSize: 14, color: 'error.dark' }} />
|
||||
)}
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: trendUp ? 'success.dark' : 'error.dark' }}>
|
||||
{Math.abs(trend)}%
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{caption && (
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary', fontWeight: 600 }}>
|
||||
{caption}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user