← back to Stayclaim
src/app/page.tsx
102 lines
import { searchListings, getRecentPermits, yearOf } from '@/lib/db';
import { MapHero } from '@/components/MapHero';
import { Rail } from '@/components/Rail';
import { NodeCard } from '@/components/NodeCard';
import { FilmsGridServer } from '@/components/FilmsGridServer';
import { HeroCollage } from '@/components/HeroCollage';
import { StarsCtaRow } from '@/components/StarsCtaRow';
import { currentSurface } from '@/lib/site';
// Storytelling-tone copy — facts framed as scenes / chapters / pages, not as data.
const FILMS_HEADING: Record<'flagship' | 'claim' | 'community', { kicker: string; heading: string }> = {
flagship: { kicker: 'Open archive', heading: 'Stories caught on film, near here' },
claim: { kicker: 'Filmed here', heading: 'Scenes the cameras came for' },
community: { kicker: 'Pages from the block', heading: 'What the neighborhood has lived through' },
};
export default async function HomePage() {
const [listings, permitEvents, surface] = await Promise.all([
searchListings({ limit: 24 }),
getRecentPermits(6),
currentSurface(),
]);
const filmCopy = FILMS_HEADING[surface.key] ?? FILMS_HEADING.flagship;
const pins = listings
.map(l => {
const lat = Number(l.latitude);
const lng = Number(l.longitude);
return { l, lat, lng };
})
.filter(({ lat, lng }) => Number.isFinite(lat) && Number.isFinite(lng))
.map(({ l, lat, lng }, i) => ({
slug: l.slug,
title: l.title,
lat,
lng,
featured: i === 0,
}));
const recentlyResearched = listings.slice(0, 3);
const recentPermits = permitEvents.slice(0, 3);
const recentlyClaimed = listings.filter(l => l.claimed_by).slice(0, 3);
return (
<>
<HeroCollage />
<StarsCtaRow surface={surface.key} />
<MapHero pins={pins} />
<Rail label="Recently researched">
{recentlyResearched.map(l => (
<NodeCard
key={l.id}
kind="address"
href={`/address/${l.slug}`}
title={l.title}
subtitle={l.city ? `${l.city}, ${l.state}` : undefined}
imageUrl={l.hero_image ?? undefined}
eyebrow={l.property_type ?? 'Address'}
/>
))}
</Rail>
<Rail label="This week in permits">
{recentPermits.map(p => (
<NodeCard
key={`permit-${p.id}`}
kind="address"
href={`/address/${p.listing_slug}`}
title={p.listing_title}
subtitle={(() => { const s = p.summary ?? ''; return s.length > 80 ? `${s.slice(0, 80)}…` : s; })()}
imageUrl={p.listing_hero ?? undefined}
eyebrow={`Permit · ${yearOf(p.valid_from)}`}
/>
))}
</Rail>
{recentlyClaimed.length > 0 && (
<Rail label="Recently claimed by owners">
{recentlyClaimed.map(l => (
<NodeCard
key={`claim-${l.id}`}
kind="address"
href={`/address/${l.slug}`}
title={l.title}
subtitle="Claimed"
imageUrl={l.hero_image ?? undefined}
eyebrow="Owner-curated"
/>
))}
</Rail>
)}
<FilmsGridServer
heading={filmCopy.heading}
kicker={filmCopy.kicker}
limit={60}
/>
</>
);
}