← back to Stayclaim
src/app/opengraph-image.tsx
85 lines
import { ImageResponse } from 'next/og';
import { headers } from 'next/headers';
import { siteForHost } from '@/lib/site';
// Per-host OG card. Next.js auto-routes this for every page in app/ unless a
// page-specific opengraph-image is provided. Picks up the same surface as the
// rest of layout.tsx via x-pastdoor-host (set in middleware).
//
// Output is 1200x630 (Open Graph standard) and renders a typographic title
// card themed to the surface — green/cream for flagship, red/bone for claim,
// gold/cream for community.
export const runtime = 'edge';
export const contentType = 'image/png';
export const size = { width: 1200, height: 630 };
export const alt = 'pastdoor — every address has a story';
const SURFACE_OG = {
flagship: { bg: '#f3ebd9', accent: '#1f4d40', ink: '#1a1a1a', kicker: 'Open archive' },
claim: { bg: '#e8dcc4', accent: '#c9292e', ink: '#1a1a1a', kicker: 'Filed here' },
community: { bg: '#ede0c4', accent: '#c5a572', ink: '#1a1a1a', kicker: 'Neighborhood screenings' },
} as const;
export default async function OG() {
const h = await headers();
const surface = siteForHost(h.get('x-pastdoor-host') || h.get('host'));
const t = SURFACE_OG[surface.key];
return new ImageResponse(
(
<div
style={{
width: '100%', height: '100%',
display: 'flex', flexDirection: 'column',
background: t.bg,
padding: '80px 96px',
fontFamily: 'serif',
}}
>
{/* GucciStripe at top — shared family signal */}
<div style={{ display: 'flex', height: 6, width: '100%', marginBottom: 60 }}>
<div style={{ flex: 1, background: '#1f4d40' }} />
<div style={{ flex: 1, background: '#c9292e' }} />
<div style={{ flex: 1, background: '#1f4d40' }} />
</div>
{/* Kicker */}
<div
style={{
display: 'flex',
background: t.accent,
color: '#fdf9ee',
padding: '6px 14px',
fontSize: 18,
letterSpacing: 4,
textTransform: 'uppercase',
fontWeight: 700,
alignSelf: 'flex-start',
marginBottom: 32,
}}
>
{t.kicker}
</div>
{/* Brand line */}
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, justifyContent: 'center' }}>
<div style={{ fontSize: 96, color: t.ink, fontWeight: 400, letterSpacing: -3, lineHeight: 1.05, fontStyle: 'italic' }}>
{surface.tagline}
</div>
<div style={{ fontSize: 36, color: t.accent, marginTop: 24, fontWeight: 500 }}>
{surface.brandName}
</div>
</div>
{/* Footer */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', fontSize: 18, color: t.ink, opacity: 0.55 }}>
<span>{surface.domain}</span>
<span>Public record · public domain · public archive</span>
</div>
</div>
),
size
);
}