|
| 1 | +import * as React from "react" |
| 2 | +import type { IconType } from "react-icons" |
| 3 | +import { cn } from "@/lib/utils" |
| 4 | +import { CardHoverBackground } from "../card-icon/hover-background" |
| 5 | +import { Glass } from "../glass" |
| 6 | +import { Button } from "./button" |
| 7 | + |
| 8 | +function Card({ |
| 9 | + className, |
| 10 | + size = "default", |
| 11 | + hoverBackground = false, |
| 12 | + children, |
| 13 | + ...props |
| 14 | +}: React.ComponentProps<typeof Glass> & { size?: "default" | "sm"; hoverBackground?: boolean }) { |
| 15 | + return ( |
| 16 | + <Glass |
| 17 | + data-slot="card" |
| 18 | + data-size={size} |
| 19 | + className={cn( |
| 20 | + "group/card relative flex h-66 w-78 flex-col gap-4 overflow-hidden rounded-[1.25rem] bg-background-blur text-card-foreground text-sm ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", |
| 21 | + className |
| 22 | + )} |
| 23 | + {...props} |
| 24 | + > |
| 25 | + {hoverBackground && <CardHoverBackground />} |
| 26 | + {children} |
| 27 | + </Glass> |
| 28 | + ) |
| 29 | +} |
| 30 | + |
| 31 | +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { |
| 32 | + return ( |
| 33 | + <div |
| 34 | + data-slot="card-header" |
| 35 | + className={cn( |
| 36 | + "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3", |
| 37 | + className |
| 38 | + )} |
| 39 | + {...props} |
| 40 | + /> |
| 41 | + ) |
| 42 | +} |
| 43 | + |
| 44 | +function CardTitle({ gradient = true, className, ...props }: React.ComponentProps<"h3"> & { gradient?: boolean }) { |
| 45 | + return ( |
| 46 | + <h3 |
| 47 | + data-slot="card-title" |
| 48 | + className={cn( |
| 49 | + `${gradient ? "bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent" : ""} font-medium leading-snug group-data-[size=sm]/card:text-base`, |
| 50 | + className |
| 51 | + )} |
| 52 | + {...props} |
| 53 | + /> |
| 54 | + ) |
| 55 | +} |
| 56 | + |
| 57 | +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { |
| 58 | + return <div data-slot="card-description" className={cn("text-muted-foreground", className)} {...props} /> |
| 59 | +} |
| 60 | + |
| 61 | +function CardAction({ |
| 62 | + className, |
| 63 | + icon: Icon, |
| 64 | + iconSize = "normal", |
| 65 | + gradient = true, |
| 66 | + ...props |
| 67 | +}: React.ComponentProps<"div"> & { icon: IconType; iconSize?: "small" | "normal" | "large"; gradient?: boolean }) { |
| 68 | + const gradientId = React.useId() |
| 69 | + |
| 70 | + return ( |
| 71 | + <div |
| 72 | + data-slot="card-action" |
| 73 | + className={cn("col-start-2 row-span-2 row-start-1 self-auto justify-self-end", className)} |
| 74 | + {...props} |
| 75 | + > |
| 76 | + {gradient && ( |
| 77 | + <svg width="0" height="0" className="absolute" aria-hidden="true" focusable="false"> |
| 78 | + <linearGradient id={gradientId} x1="0%" y1="100%" x2="0%" y2="0%"> |
| 79 | + <stop offset="0%" className="text-blue-secondary" stopColor="currentColor" /> |
| 80 | + <stop offset="100%" className="text-blue-primary" stopColor="currentColor" /> |
| 81 | + </linearGradient> |
| 82 | + </svg> |
| 83 | + )} |
| 84 | + |
| 85 | + <Icon |
| 86 | + size={iconSize === "small" ? "1.125rem" : iconSize === "normal" ? "2rem" : "3.5rem"} |
| 87 | + fill={gradient ? `url(#${gradientId})` : "currentColor"} |
| 88 | + stroke={gradient ? `url(#${gradientId})` : "currentColor"} |
| 89 | + /> |
| 90 | + </div> |
| 91 | + ) |
| 92 | +} |
| 93 | + |
| 94 | +function CardContent({ className, ...props }: React.ComponentProps<"div">) { |
| 95 | + return <div data-slot="card-content" className={cn("group-data-[size=sm]/card:px-3", className)} {...props} /> |
| 96 | +} |
| 97 | + |
| 98 | +function CardBottomButton({ className, ...props }: React.ComponentProps<typeof Button>) { |
| 99 | + return <Button data-slot="card-footer" className={cn("self-end", className)} {...props} /> |
| 100 | +} |
| 101 | + |
| 102 | +export { Card, CardHeader, CardBottomButton, CardTitle, CardAction, CardDescription, CardContent } |
0 commit comments