← back to Stayclaim
src/components/home/FlagshipHome.tsx
236 lines
/**
* WhoLivedThere — flagship home. Editorial, archive-first.
* Hero: featured named historic houses with coordinates from Wikipedia.
* Editorial rails: notable estates, recent newspaper mentions, latest permits.
*/
import Link from 'next/link';
import { unstable_cache } from 'next/cache';
import { pool } from '@/lib/db';
import { sisterSurfaces } from '@/lib/site';
export const dynamic = 'force-dynamic';
async function getFeaturedHouses(): Promise<Array<{ id: string; slug: string; title: string; description: string | null; lat: number; lon: number; source_url: string | null }>> {
const { rows } = await pool.query(`
SELECT DISTINCT ON (l.id) l.id, l.slug, l.title, l.description, l.latitude::float as lat, l.longitude::float as lon, pe.source_url
FROM listing l
LEFT JOIN place_event pe ON pe.listing_id = l.id AND pe.kind = 'named_estate'
WHERE l.source = 'wikipedia_house' AND l.is_public = true AND l.latitude IS NOT NULL
ORDER BY l.id, l.title
LIMIT 12
`);
return rows;
}
const getCounts = unstable_cache(
async () => {
const { rows } = await pool.query<any>(`
SELECT
(SELECT count(*) FROM listing) as listings,
(SELECT count(*) FROM permit) as permits,
(SELECT count(*) FROM parcel) as parcels,
(SELECT count(*) FROM place_event) as events,
(SELECT count(*) FROM news_address_mention) as mentions
`);
return rows[0];
},
['flagship-home-counts'],
{ revalidate: 600 },
);
async function getRecentNewspaperMentions() {
const { rows } = await pool.query(`
SELECT m.raw_address, m.context, n.paper_name, n.issue_date::text as issue_date, n.ia_url
FROM news_address_mention m
JOIN news_issue n ON n.id = m.issue_id
WHERE m.context IS NOT NULL
ORDER BY n.issue_date DESC NULLS LAST
LIMIT 6
`);
return rows;
}
export default async function FlagshipHome() {
const [houses, counts, mentions] = await Promise.all([
getFeaturedHouses(),
getCounts(),
getRecentNewspaperMentions(),
]);
return (
<>
{/* MASTHEAD — magazine-style typography */}
<section className="border-b border-ink/15 bg-sand">
<div className="max-w-7xl mx-auto px-6 py-16 md:py-24">
<div className="flex flex-col md:flex-row items-baseline justify-between gap-6 mb-8">
<p className="text-[10px] uppercase tracking-[0.25em] text-moss font-mono">
◢ The Archive · Vol. I · {new Date().getFullYear()}
</p>
<p className="text-[10px] uppercase tracking-[0.15em] text-ink/40 font-mono tabular-nums">
{Number(counts?.listings ?? 0).toLocaleString()} addresses · {Number(counts?.permits ?? 0).toLocaleString()} permits · {Number(counts?.parcels ?? 0).toLocaleString()} parcels
</p>
</div>
<h1 className="font-display text-[14vw] md:text-[10rem] leading-[0.85] tracking-[-0.04em] text-ink">
Every<br/>
<span className="italic text-moss">address</span><br/>
has a story.
</h1>
<p className="mt-10 font-display italic text-2xl md:text-3xl text-ink/65 max-w-3xl leading-tight">
Look up the full history of any house — who lived there, what was built and when, what the archives say.
</p>
<form action="/search" className="mt-12 flex flex-col sm:flex-row gap-3 max-w-3xl">
<input
type="search"
name="q"
placeholder="600 N Bedford Drive · Pickfair · APN 4328-018-001 · Mary Pickford"
className="flex-1 border-2 border-ink/20 bg-white px-5 py-4 text-base font-sans focus:outline-none focus:border-moss tracking-tight"
/>
<button type="submit" className="bg-ink text-sand px-8 py-4 text-xs uppercase tracking-[0.2em] hover:bg-moss transition font-mono">
Search the archive
</button>
</form>
</div>
</section>
{/* FEATURED ESTATES — editorial gallery */}
{houses.length > 0 && (
<section className="bg-ink text-sand py-20">
<div className="max-w-7xl mx-auto px-6">
<div className="flex items-baseline justify-between mb-12 flex-wrap gap-4">
<div>
<p className="text-[10px] uppercase tracking-[0.25em] text-coral font-mono mb-2">Featured estates</p>
<h2 className="font-display text-5xl md:text-7xl tracking-[-0.02em] leading-[0.95]">
The named houses<br/>
<span className="italic text-coral/80">of Beverly Hills.</span>
</h2>
</div>
<p className="text-sm text-sand/55 max-w-md leading-relaxed font-display italic">
Pickfair. Greystone. Falcon Lair. Each one mapped, with the original Wikipedia article a click away.
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{houses.map(h => (
<Link
key={h.id}
href={`/address/${h.slug}`}
className="block border border-sand/15 bg-ink/50 hover:border-coral hover:bg-ink/80 transition group p-7"
>
<p className="font-mono text-[10px] uppercase tracking-[0.2em] text-coral/80 mb-3">Named estate</p>
<h3 className="font-display text-3xl text-sand tracking-[-0.005em] leading-tight group-hover:text-coral transition">
{h.title}
</h3>
{h.description && (
<p className="mt-3 text-sm text-sand/65 leading-relaxed">{h.description.slice(0, 140)}</p>
)}
<p className="mt-5 font-mono text-[10px] tabular-nums text-sand/40">
{h.lat.toFixed(4)}, {h.lon.toFixed(4)}
</p>
{h.source_url && (
<p className="mt-1 font-mono text-[10px] uppercase tracking-wider text-coral/70">
via Wikipedia ↗
</p>
)}
</Link>
))}
</div>
</div>
</section>
)}
{/* IN THE NEWSPAPER — full-OCR-text mentions */}
{mentions.length > 0 && (
<section className="bg-sand py-20 border-t border-ink/10">
<div className="max-w-7xl mx-auto px-6">
<div className="mb-10">
<p className="text-[10px] uppercase tracking-[0.25em] text-moss font-mono mb-2">In the newspapers</p>
<h2 className="font-display text-5xl md:text-6xl tracking-[-0.02em] leading-[0.95] text-ink">
{Number(counts?.mentions ?? 0).toLocaleString()} address mentions<br/>
<span className="italic text-ink/60">from 1873 onward.</span>
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-8">
{mentions.map((m, i) => (
<a
key={i}
href={/^https?:\/\//i.test(m.ia_url ?? '') ? m.ia_url : '#'}
target="_blank"
rel="noreferrer noopener"
className="border-l-4 border-moss pl-5 hover:border-coral transition group"
>
<p className="font-mono text-[10px] uppercase tracking-[0.15em] text-ink/45">
{m.paper_name} · {m.issue_date}
</p>
<p className="font-display text-2xl text-ink mt-1 group-hover:text-coral transition">
{m.raw_address}
</p>
<p className="mt-2 text-sm italic text-ink/65 leading-relaxed">
“{m.context.slice(0, 200)}{m.context.length > 200 ? '…' : ''}”
</p>
<p className="mt-2 font-mono text-[10px] uppercase tracking-wider text-moss group-hover:text-coral">
view scanned page on Internet Archive ↗
</p>
</a>
))}
</div>
</div>
</section>
)}
{/* INDEX OF SOURCES — minimalist list */}
<section className="bg-ink/95 text-sand py-16 border-t border-sand/10">
<div className="max-w-7xl mx-auto px-6">
<p className="text-[10px] uppercase tracking-[0.25em] text-coral font-mono mb-2">Backed by</p>
<h2 className="font-display text-4xl md:text-5xl tracking-[-0.02em] mb-10">Eleven primary sources.</h2>
<ul className="grid grid-cols-2 md:grid-cols-3 gap-x-10 gap-y-3 font-mono text-xs text-sand/70 uppercase tracking-wider">
<li>LA County Assessor (9.6M parcels)</li>
<li>LADBS Building Permits (1.5M)</li>
<li>LADBS Mechanical / Electrical</li>
<li>LA Bureau of Engineering (626K)</li>
<li>LA Code Enforcement (839K cases)</li>
<li>LAHD Eviction / Foreclosure</li>
<li>Beverly Hills + Pasadena + SM</li>
<li>WeHo Film Permits</li>
<li>LA Active Businesses (619K)</li>
<li>LA Historic-Cultural Monuments</li>
<li>Internet Archive newspapers</li>
<li>Wikipedia + UCLA archives</li>
</ul>
<p className="mt-12 max-w-3xl text-sm text-sand/55 leading-relaxed">
Every fact in the archive carries its own citation. Click any “source ↗” link
on any address page to view the actual government record, scanned newspaper page, or finding aid.
</p>
<Link href="/admin/sources" className="inline-block mt-8 text-xs uppercase tracking-[0.2em] font-mono text-coral hover:underline">
Full source registry →
</Link>
</div>
</section>
{/* SISTER SURFACES */}
<section className="bg-sand py-16 border-t border-ink/15">
<div className="max-w-7xl mx-auto px-6">
<p className="text-[10px] uppercase tracking-[0.25em] text-ink/45 font-mono mb-6">Also part of the archive</p>
<div className="grid md:grid-cols-2 gap-6">
{sisterSurfaces('flagship').map(s => (
<a
key={s.domain}
href={`https://${s.domain}${s.primaryCta.href}`}
className="block border-2 border-ink/15 hover:border-ink p-8 group transition bg-white/50"
>
<p className="font-mono text-[10px] uppercase tracking-[0.25em] text-ink/45">{s.domain}</p>
<h3 className="font-display text-3xl text-ink mt-2 tracking-[-0.01em] group-hover:text-moss transition">
{s.brandName}
</h3>
<p className="font-display italic text-lg text-ink/65 mt-1">{s.tagline}</p>
<p className="mt-4 font-mono text-[11px] uppercase tracking-[0.15em] text-moss">
{s.primaryCta.label} →
</p>
</a>
))}
</div>
</div>
</section>
</>
);
}