File
Blob: src/client/components/ui/card.tsx
| 1 | import type { ComponentProps, ReactNode } from "react"; |
| 2 | |
| 3 | type CardVariant = "default" | "accent"; |
| 4 | |
| 5 | type CardProps = { |
| 6 | variant?: CardVariant; |
| 7 | interactive?: boolean; |
| 8 | children: ReactNode; |
| 9 | className?: string; |
| 10 | } & Omit<ComponentProps<"div">, "children" | "className">; |
| 11 | |
| 12 | const base = "rounded-2xl p-5 sm:p-6"; |
| 13 | |
| 14 | const variantStyles: Record<CardVariant, string> = { |
| 15 | default: |
| 16 | "border border-zinc-300 dark:border-zinc-800/60 bg-white shadow-sm dark:bg-zinc-900/50 dark:shadow-none", |
| 17 | accent: |
| 18 | "border border-accent-500/20 bg-gradient-to-br from-white to-zinc-50 dark:from-zinc-900/80 dark:to-zinc-900/40", |
| 19 | }; |
| 20 | |
| 21 | const interactiveStyles = "hover:-translate-y-0.5 transition-transform cursor-pointer"; |
| 22 | |
| 23 | export function Card({ |
| 24 | variant = "default", |
| 25 | interactive = false, |
| 26 | className = "", |
| 27 | children, |
| 28 | ...rest |
| 29 | }: CardProps) { |
| 30 | const classes = |
| 31 | `${base} ${variantStyles[variant]} ${interactive ? interactiveStyles : ""} ${className}`.trim(); |
| 32 | |
| 33 | return ( |
| 34 | <div className={classes} {...rest}> |
| 35 | {children} |
| 36 | </div> |
| 37 | ); |
| 38 | } |