← 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>
  );
}