← back to Stayclaim
src/components/MediaWall.tsx
89 lines
import { TierBadge } from './TierBadge';
import type { MediaAsset } from '@/lib/db';
import { safeHttpUrl } from '@/lib/url-guards';
const KIND_LABEL: Record<MediaAsset['kind'], string> = {
archival_photo: 'Archival photo',
historic_map: 'Historic map',
postcard: 'Postcard',
drone: 'Aerial photograph',
streetview_thumb: 'Street View',
newspaper_clip: 'Newspaper clipping',
};
export function MediaWall({ assets }: { assets: MediaAsset[] }) {
if (assets.length === 0) return null;
return (
<section className="my-10">
<div className="flex items-baseline justify-between mb-4 flex-wrap gap-2">
<h2 className="font-display text-3xl text-ink tracking-[-0.01em]">Media in the archive</h2>
<span className="text-[10px] uppercase tracking-[0.15em] text-ink/45">
{assets.length} {assets.length === 1 ? 'asset' : 'assets'}
</span>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
{assets.map(a => {
const imgUrl = safeHttpUrl(a.storage_url);
const srcUrl = safeHttpUrl(a.source_url);
return (
<figure key={a.id} className="border border-ink/10 bg-sand">
<div className="relative aspect-[4/3] overflow-hidden bg-ink/10">
{imgUrl && (
/* eslint-disable-next-line @next/next/no-img-element */
<img
src={imgUrl}
alt={a.caption ?? KIND_LABEL[a.kind]}
loading="lazy"
className="w-full h-full object-cover"
/>
)}
{a.year && (
<span className="absolute bottom-2 left-2 bg-ink/85 text-sand font-mono text-[10px] uppercase tracking-[0.15em] px-2 py-1">
{a.year}
</span>
)}
</div>
<figcaption className="p-4">
<p className="text-[10px] uppercase tracking-[0.15em] text-ink/50 mb-1">
{KIND_LABEL[a.kind]}
</p>
{a.caption && (
<p className="text-sm text-ink/80 leading-relaxed">{a.caption}</p>
)}
<div className="mt-3 flex items-center justify-between gap-2">
{a.source_tier === 'A' || a.source_tier === 'B' || a.source_tier === 'C' ? (
srcUrl ? (
<a
href={srcUrl}
target="_blank"
rel="noopener noreferrer"
className="hover:opacity-80 transition"
>
<TierBadge
tier={a.source_tier}
sourceLabel={a.source_label ?? undefined}
/>
</a>
) : (
<TierBadge
tier={a.source_tier}
sourceLabel={a.source_label ?? undefined}
/>
)
) : null}
{a.rights && (
<span className="text-[10px] text-ink/40 truncate" title={a.rights}>
{a.rights}
</span>
)}
</div>
</figcaption>
</figure>
);
})}
</div>
</section>
);
}