Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | import { motion, HTMLMotionProps } from 'framer-motion'; import { cn } from '../../lib/utils'; import { cardHover } from '../../lib/animations'; interface CardProps extends Omit<HTMLMotionProps<'div'>, 'children'> { children: React.ReactNode; hoverable?: boolean; } export function Card({ children, className, hoverable = false, ...props }: CardProps) { return ( <motion.div className={cn( 'rounded-xl border border-gray-200 bg-white p-4 shadow-sm', 'dark:border-gray-700 dark:bg-gray-800', hoverable && 'cursor-pointer transition-shadow duration-200', className )} {...(hoverable && { whileHover: cardHover })} {...props} > {children} </motion.div> ); } interface CardHeaderProps { children: React.ReactNode; className?: string; } export function CardHeader({ children, className }: CardHeaderProps) { return ( <div className={cn('mb-3', className)}> {children} </div> ); } interface CardTitleProps { children: React.ReactNode; className?: string; } export function CardTitle({ children, className }: CardTitleProps) { return ( <h3 className={cn('text-sm font-semibold text-gray-900 dark:text-gray-100', className)}> {children} </h3> ); } interface CardContentProps { children: React.ReactNode; className?: string; } export function CardContent({ children, className }: CardContentProps) { return ( <div className={cn('text-sm text-gray-600 dark:text-gray-300', className)}> {children} </div> ); } |