File size: 1,963 Bytes
b190b45 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
import React, { HTMLAttributes, ReactNode } from 'react';
interface CardProps extends HTMLAttributes<HTMLDivElement> {
children: ReactNode;
hover?: boolean;
}
interface CardHeaderProps {
children: ReactNode;
className?: string;
}
interface CardBodyProps {
children: ReactNode;
className?: string;
}
interface CardFooterProps {
children: ReactNode;
className?: string;
}
export const Card: React.FC<CardProps> = ({
children,
hover = true,
className = '',
...props
}) => {
const classes = ['card', hover ? '' : 'no-hover', className].filter(Boolean).join(' ');
return (
<div className={classes} {...props}>
{children}
</div>
);
};
export const CardHeader: React.FC<CardHeaderProps> = ({ children, className = '' }) => {
return <div className={`card-header ${className}`}>{children}</div>;
};
export const CardBody: React.FC<CardBodyProps> = ({ children, className = '' }) => {
return <div className={`card-body ${className}`}>{children}</div>;
};
export const CardFooter: React.FC<CardFooterProps> = ({ children, className = '' }) => {
return <div className={`card-footer ${className}`}>{children}</div>;
};
// Stat Card Component
interface StatCardProps {
icon?: ReactNode;
value: string | number;
label: string;
change?: {
value: string;
positive: boolean;
};
className?: string;
}
export const StatCard: React.FC<StatCardProps> = ({
icon,
value,
label,
change,
className = ''
}) => {
return (
<div className={`stat-card ${className}`}>
{icon && <div className="stat-icon">{icon}</div>}
<div className="stat-value">{value}</div>
<div className="stat-label">{label}</div>
{change && (
<div className={`stat-change ${change.positive ? 'positive' : 'negative'}`}>
{change.value}
</div>
)}
</div>
);
};
export default Card;
|