spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1import { ImageResponse } from 'next/og';2import type { NextRequest } from 'next/server';3import { t } from '@/i18n';4import { api, safe } from '@/lib/api';5import { splitCompareSlugs } from '@/lib/compare-state';6import { OG_INK2, OG_INK3, OG_RULE, OG_SIZE_H, OG_SIZE_W, OgFrame, OgWordmark } from '../../og-shared';78export const revalidate = 3600;910/**11 * Social image for /compare/a/b/c — `GET /compare/og?slugs=canada,united-states,france`.12 * (A file-convention `opengraph-image` cannot live under a catch-all segment, so the page's metadata points here.)13 */14export async function GET(req: NextRequest) {15 const raw = req.nextUrl.searchParams.get('slugs') ?? '';16 const list = await safe(api.countries());17 const bySlug = new Map((list?.items ?? []).flatMap((c) => [[c.slug ?? '', c] as const, [c.id.toLowerCase(), c] as const]));18 const wanted = splitCompareSlugs(raw.split('/'));19 const countries = wanted.map((s) => bySlug.get(s)).filter((c): c is NonNullable<typeof c> => !!c);20 const names = countries.length ? countries.map((c) => c.name ?? c.id) : wanted.map((s) => s.replace(/-/g, ' '));21 const flagSize = countries.length > 5 ? 84 : countries.length > 3 ? 108 : 132;22 const nameSize = names.join('').length > 40 ? 40 : 56;23 return new ImageResponse(24 (25 <OgFrame>26 <OgWordmark size={28} />27 <div style={{ display: 'flex', alignItems: 'center', gap: 20, marginTop: 44, flexWrap: 'wrap' }}>28 {countries.map((c) => (29 <div key={c.id} style={{ fontSize: flagSize, lineHeight: 1, display: 'flex' }}>30 {c.flag ?? ''}31 </div>32 ))}33 </div>34 <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'baseline', marginTop: 28, fontSize: nameSize, fontWeight: 600, letterSpacing: -1, lineHeight: 1.1 }}>35 {names.map((n, i) => (36 <div key={n} style={{ display: 'flex', alignItems: 'baseline' }}>37 {i > 0 ? <span style={{ color: OG_INK3, fontSize: nameSize * 0.6, fontWeight: 400, margin: '0 14px' }}>{t('compare.vs')}</span> : null}38 <span>{n}</span>39 </div>40 ))}41 </div>42 <div style={{ display: 'flex', marginTop: 'auto', paddingTop: 20, borderTop: `1px solid ${OG_RULE}`, fontSize: 24, color: OG_INK2 }}>43 {t('compare.title')} · {t('home.compare.sub')}44 </div>45 <div style={{ position: 'absolute', right: 64, bottom: 24, fontSize: 20, color: OG_INK3 }}>{t('og.site')}</div>46 </OgFrame>47 ),48 { width: OG_SIZE_W, height: OG_SIZE_H },49 );50}51