website refactor
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
import { ArrowDownRight, ArrowUpRight, LucideIcon } from 'lucide-react';
|
||||
import { Box } from './Box';
|
||||
import { Card } from './Card';
|
||||
import { Text } from './Text';
|
||||
import { Icon } from './Icon';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { Stack } from './Stack';
|
||||
import { Text } from './Text';
|
||||
|
||||
interface StatCardProps {
|
||||
label: string;
|
||||
@@ -15,6 +19,9 @@ interface StatCardProps {
|
||||
value: number;
|
||||
isPositive: boolean;
|
||||
};
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export function StatCard({
|
||||
@@ -25,7 +32,12 @@ export function StatCard({
|
||||
variant = 'blue',
|
||||
className = '',
|
||||
trend,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
delay = 0,
|
||||
}: StatCardProps) {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
|
||||
const variantClasses = {
|
||||
blue: 'bg-gradient-to-br from-blue-900/20 to-blue-700/10 border-blue-500/30',
|
||||
purple: 'bg-gradient-to-br from-purple-900/20 to-purple-700/10 border-purple-500/30',
|
||||
@@ -34,39 +46,77 @@ export function StatCard({
|
||||
};
|
||||
|
||||
const iconColorClasses = {
|
||||
blue: '#60a5fa',
|
||||
blue: 'text-primary-blue',
|
||||
purple: 'text-purple-400',
|
||||
green: 'text-performance-green',
|
||||
orange: 'text-warning-amber'
|
||||
};
|
||||
|
||||
const iconHexColors = {
|
||||
blue: '#3b82f6',
|
||||
purple: '#a78bfa',
|
||||
green: '#34d399',
|
||||
orange: '#fb923c'
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className={`${variantClasses[variant]} ${className}`}>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<Text size="sm" color="text-gray-400" className="mb-1" block>
|
||||
{label}
|
||||
</Text>
|
||||
<Text size="3xl" weight="bold" color="text-white" block>
|
||||
{value}
|
||||
const cardContent = (
|
||||
<Card className={`${variantClasses[variant]} ${className} h-full`} p={5}>
|
||||
<Stack gap={3}>
|
||||
<Stack direction="row" align="start" justify="between">
|
||||
{icon && (
|
||||
<Box
|
||||
width="11"
|
||||
height="11"
|
||||
rounded="xl"
|
||||
display="flex"
|
||||
center
|
||||
bg="bg-iron-gray/50"
|
||||
border={true}
|
||||
borderColor="border-charcoal-outline"
|
||||
>
|
||||
<Icon icon={icon} size={5} className={iconColorClasses[variant]} />
|
||||
</Box>
|
||||
)}
|
||||
{trend && (
|
||||
<Stack
|
||||
direction="row"
|
||||
align="center"
|
||||
gap={1}
|
||||
color={trend.isPositive ? 'text-performance-green' : 'text-error-red'}
|
||||
>
|
||||
<Icon icon={trend.isPositive ? ArrowUpRight : ArrowDownRight} size={4} />
|
||||
<Text size="sm" weight="medium">{Math.abs(trend.value)}%</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<Box>
|
||||
<Text size="2xl" weight="bold" color="text-white" block mb={1}>
|
||||
{prefix}{typeof value === 'number' ? value.toLocaleString() : value}{suffix}
|
||||
</Text>
|
||||
<Text size="sm" color="text-gray-400" block>{label}</Text>
|
||||
{subValue && (
|
||||
<Text size="xs" color="text-gray-500" className="mt-1" block>
|
||||
<Text size="xs" color="text-gray-500" block mt={1}>
|
||||
{subValue}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-2">
|
||||
{icon && (
|
||||
<Icon icon={icon} size={8} color={iconColorClasses[variant]} />
|
||||
)}
|
||||
{trend && (
|
||||
<Text size="sm" color={trend.isPositive ? 'text-performance-green' : 'text-error-red'}>
|
||||
{trend.isPositive ? '↑' : '↓'}{Math.abs(trend.value)}%
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldReduceMotion) {
|
||||
return <Box fullHeight>{cardContent}</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
as={motion.div}
|
||||
fullHeight
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay }}
|
||||
>
|
||||
{cardContent}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user