spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1import type { Metadata } from 'next';2import { redirect } from 'next/navigation';3import { t } from '@/i18n';4import { isAdminAuthed, isAdminConfigured } from '@/lib/admin-auth';5import { routes } from '@/lib/site';6import { loginAction } from '../actions';78export const metadata: Metadata = { title: t('admin.login.title'), robots: { index: false, follow: false } };9export const dynamic = 'force-dynamic';1011export default async function AdminLoginPage({ searchParams }: { searchParams: Promise<{ error?: string; next?: string }> }) {12 const sp = await searchParams;13 if (await isAdminAuthed()) redirect(routes.admin());14 const configured = isAdminConfigured();15 return (16 <div className="mx-auto max-w-sm py-16">17 <div className="eyebrow">{t('admin.title')}</div>18 <h1 className="display mt-1 text-3xl text-ink">{t('admin.login.title')}</h1>19 <p className="mt-2 text-sm text-ink-2">{t('admin.login.sub')}</p>20 {!configured ? (21 <p className="mt-4 rounded-sm border border-warn/40 px-3 py-2 text-sm text-warn">{t('admin.login.notConfigured')}</p>22 ) : (23 <form action={loginAction} className="mt-6 space-y-3">24 <input type="hidden" name="next" value={sp.next ?? routes.admin()} />25 <label className="block text-sm">26 <span className="mb-1 block text-xs font-medium text-ink-2">{t('admin.login.token')}</span>27 <input name="token" type="password" autoComplete="current-password" required autoFocus className="h-11 w-full rounded-sm border border-rule bg-surface px-3 font-mono text-sm outline-none focus:border-accent" />28 </label>29 {sp.error ? <p className="text-sm text-down">{t('admin.login.error')}</p> : null}30 <button type="submit" className="inline-flex h-11 w-full items-center justify-center rounded-sm bg-ink px-4 text-sm font-medium text-paper hover:bg-accent hover:text-accent-ink">31 {t('admin.login.submit')}32 </button>33 </form>34 )}35 </div>36 );37}38