SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
2.5 KB · 51 lines tsx
Raw Blame History
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