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