← back to Stayclaim

src/app/locations-by-year/page.tsx

125 lines

import Link from 'next/link';
import type { Metadata } from 'next';
import { listAllFilmingShoots, yearOf } from '@/lib/db';
import { BreadcrumbArchive } from '@/components/BreadcrumbArchive';

export const metadata: Metadata = {
  title: 'Locations by year',
  description: 'Every public filming permit in the archive, sorted by year. The visual record of what was shot in LA when.',
  alternates: { canonical: '/locations-by-year' },
};

const KIND_LABEL: Record<string, string> = {
  film: 'Feature',
  tv: 'TV',
  commercial: 'Commercial',
  music_video: 'Music video',
  documentary: 'Documentary',
  short: 'Short',
  student: 'Student',
};

export default async function LocationsByYearPage() {
  const shoots = await listAllFilmingShoots();

  // Group by year.
  const byYear: Record<string, typeof shoots> = {};
  for (const s of shoots) {
    const y = s.shoot_date_from ? yearOf(s.shoot_date_from) : 'Undated';
    (byYear[y] ??= []).push(s);
  }
  const years = Object.keys(byYear).sort((a, b) =>
    a === 'Undated' ? 1 : b === 'Undated' ? -1 : Number(b) - Number(a)
  );

  return (
    <>
      <div className="max-w-5xl mx-auto px-6 pt-6">
        <BreadcrumbArchive items={[{ label: 'Archive', href: '/' }, { label: 'Locations by year' }]} />
      </div>

      <header className="max-w-5xl mx-auto px-6 py-12 border-b border-ink/10">
        <p className="text-xs uppercase tracking-[0.15em] text-ink/50 mb-2">Locations by year</p>
        <h1 className="font-display text-5xl md:text-6xl text-ink tracking-[-0.02em] leading-[1.02]">
          Every shoot, sorted by year.
        </h1>
        <p className="mt-4 font-display italic text-xl text-ink/70 max-w-prose">
          Public film permits at addresses in the archive — pulled from FilmLA / data.lacity.org.
        </p>
        <p className="mt-3 font-mono text-[11px] text-ink/45">
          {shoots.length} {shoots.length === 1 ? 'shoot' : 'shoots'} across {years.length} {years.length === 1 ? 'year' : 'years'}
        </p>
        {years.length > 0 && (
          <nav className="mt-6 flex flex-wrap gap-2">
            {years.map(y => (
              <a
                key={y}
                href={`#y-${y}`}
                className="font-mono text-[11px] uppercase tracking-[0.15em] border border-ink/15 px-2 py-1 hover:border-coral hover:text-coral transition"
              >
                {y}
              </a>
            ))}
          </nav>
        )}
      </header>

      <section className="max-w-5xl mx-auto px-6 py-10">
        {shoots.length === 0 ? (
          <p className="text-sm italic text-ink/55">
            No shoots ingested yet. Run <code className="font-mono text-xs">scripts/ingest-la-film-permits.ts</code>.
          </p>
        ) : (
          years.map(year => (
            <div key={year} id={`y-${year}`} className="mb-12 scroll-mt-24">
              <div className="flex items-baseline gap-4 mb-4 pb-2 border-b border-ink/10">
                <h2 className="font-display text-4xl text-ink tracking-[-0.01em]">{year}</h2>
                <span className="font-mono text-[11px] text-ink/45">
                  {byYear[year]!.length} {byYear[year]!.length === 1 ? 'shoot' : 'shoots'}
                </span>
              </div>
              <ol className="divide-y divide-ink/5">
                {byYear[year]!.map(s => (
                  <li key={s.id} className="grid md:grid-cols-[120px_1fr_auto] gap-3 md:gap-6 py-4 items-baseline">
                    <span className="font-mono text-[10px] uppercase tracking-[0.15em] text-ink/55">
                      {KIND_LABEL[s.production_kind] ?? s.production_kind}
                      {s.role ? ` · ${s.role.replace('_', ' ')}` : ''}
                    </span>
                    <div>
                      <div className="flex items-baseline gap-3 flex-wrap">
                        <Link
                          href={`/film/${encodeURIComponent(s.production_slug)}`}
                          className="font-display text-xl text-ink hover:text-coral transition"
                        >
                          {s.production_title}
                          {s.production_year ? <span className="ml-2 text-ink/50">({s.production_year})</span> : null}
                        </Link>
                        <span className="text-ink/30">·</span>
                        <Link
                          href={`/address/${encodeURIComponent(s.listing_slug)}`}
                          className="text-base text-ink/70 hover:text-coral transition"
                        >
                          {s.listing_title}
                        </Link>
                        {s.listing_city && (
                          <span className="text-[11px] text-ink/50">{s.listing_city}</span>
                        )}
                      </div>
                      {s.scene_note && (
                        <p className="mt-1 text-sm text-ink/65 leading-relaxed">{s.scene_note}</p>
                      )}
                    </div>
                    <span className="font-mono text-[10px] text-ink/45 md:text-right">
                      {s.permit_number}
                    </span>
                  </li>
                ))}
              </ol>
            </div>
          ))
        )}
      </section>
    </>
  );
}