← back to Stayclaim
src/components/NodeCard.tsx
56 lines
import Link from 'next/link';
import Image from 'next/image';
/**
* NodeCard — card for Address / Person / Neighborhood / Architect nodes.
* Discriminated by `kind`. Any surfaced fact must carry its source implicitly
* (card hero + byline); detail-level tiering lives on the destination page.
*/
export type NodeCardKind = 'address' | 'person' | 'neighborhood' | 'architect';
export function NodeCard({
kind,
href,
title,
subtitle,
imageUrl,
eyebrow,
}: {
kind: NodeCardKind;
href: string;
title: string;
subtitle?: string;
imageUrl?: string;
eyebrow?: string;
}) {
const kindLabel: Record<NodeCardKind, string> = {
address: 'Address',
person: 'Person',
neighborhood: 'Neighborhood',
architect: 'Architect',
};
return (
<Link
href={href}
className="group flex flex-col border border-ink/10 bg-sand hover:border-ink/40 transition overflow-hidden"
>
{imageUrl && (
<div className="relative aspect-[4/3] bg-ink/5">
<Image src={imageUrl} alt="" fill sizes="(max-width:768px) 100vw, 400px" className="object-cover" />
</div>
)}
<div className="p-4 flex-1 flex flex-col">
<p className="text-[10px] uppercase tracking-[0.15em] text-ink/50 mb-1">
{eyebrow ?? kindLabel[kind]}
</p>
<h3 className="font-display text-xl text-ink leading-tight group-hover:text-coral transition">
{title}
</h3>
{subtitle && <p className="mt-1 text-sm text-ink/60">{subtitle}</p>}
</div>
</Link>
);
}