-
Notifications
You must be signed in to change notification settings - Fork 85
Expand file tree
/
Copy pathCard.tsx
More file actions
79 lines (74 loc) · 2.21 KB
/
Copy pathCard.tsx
File metadata and controls
79 lines (74 loc) · 2.21 KB
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
import Image from "next/image";
import Link from "next/link";
export type BadgeTone = "red" | "green" | "orange";
export interface CardProps {
title: string;
description?: string;
subtitle?: string;
meta?: string | string[];
imageSrc: string;
imageAlt?: string;
price?: string | number;
href?: string;
badge?: { label: string; tone?: BadgeTone };
className?: string;
}
const toneToBg: Record<BadgeTone, string> = {
red: "text-[--color-red]",
green: "text-[--color-green]",
orange: "text-[--color-orange]",
};
export default function Card({
title,
description,
subtitle,
meta,
imageSrc,
imageAlt = title,
price,
href,
badge,
className = "",
}: CardProps) {
const displayPrice =
price === undefined ? undefined : typeof price === "number" ? `$${price.toFixed(2)}` : price;
const content = (
<article
className={`group rounded-xl bg-light-100 ring-1 ring-light-300 transition-colors hover:ring-dark-500 ${className}`}
>
<div className="relative aspect-square overflow-hidden rounded-t-xl bg-light-200">
<Image
src={imageSrc}
alt={imageAlt}
fill
sizes="(min-width: 1280px) 360px, (min-width: 1024px) 300px, (min-width: 640px) 45vw, 90vw"
className="object-cover transition-transform duration-300 group-hover:scale-105"
/>
</div>
<div className="p-4">
<div className="mb-1 flex items-baseline justify-between gap-3">
<h3 className="text-heading-3 text-dark-900">{title}</h3>
{displayPrice && <span className="text-body-medium text-dark-900">{displayPrice}</span>}
</div>
{description && <p className="text-body text-dark-700">{description}</p>}
{subtitle && <p className="text-body text-dark-700">{subtitle}</p>}
{meta && (
<p className="mt-1 text-caption text-dark-700">
{Array.isArray(meta) ? meta.join(" • ") : meta}
</p>
)}
</div>
</article>
);
return href ? (
<Link
href={href}
aria-label={title}
className="block rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-[--color-dark-500]"
>
{content}
</Link>
) : (
content
);
}