SPB Git forge
3commits 1branches 0releases
417.0 KBsize
maindefault branch
10 days agolast push
TypeScript 66.5% Python 30.9% JavaScript 1.4% CSS 0.7%
2.2 KB · 48 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import { redirect } from 'next/navigation';3import { LogoMark } from '@/components/brand/logo';4import { Container } from '@/components/ui/section';5import { isAdmin, safeNextPath } from '@/lib/admin-auth';67export const metadata: Metadata = { title: 'Sign in', robots: { index: false, follow: false } };89export default async function AdminLoginPage({ searchParams }: { searchParams: Promise<{ error?: string; next?: string }> }) {10  const sp = await searchParams;11  const next = safeNextPath(sp.next);12  if (await isAdmin()) redirect(next);13  const error = sp.error === 'invalid' ? 'That token is not valid.' : sp.error === 'unconfigured' ? 'SI_ADMIN_TOKEN is not configured on the server — the admin is disabled.' : null;14  return (15    <Container className="flex min-h-[60vh] items-center justify-center py-12">16      <form method="post" action="/api/admin/login" className="w-full max-w-sm rounded-lg border border-rule bg-plane/60 p-6">17        <div className="flex items-center gap-2">18          <LogoMark size={22} className="text-ink" />19          <p className="eyebrow">SatelliteIndex admin</p>20        </div>21        <h1 className="mt-3 text-xl font-semibold tracking-tight">Sign in</h1>22        <p className="mt-1 text-sm text-ink-2">Paste the operator token. It is verified on the server and never stored in the browser — only a hashed session cookie is set.</p>23        <label htmlFor="token" className="eyebrow mt-5 block">24          Admin token25        </label>26        <input27          id="token"28          name="token"29          type="password"30          autoComplete="current-password"31          required32          autoFocus33          className="mono mt-1.5 block h-11 w-full rounded-md border border-rule bg-plane-2 px-3 text-sm text-ink outline-none focus:border-accent"34        />35        <input type="hidden" name="next" value={next} />36        {error && (37          <p role="alert" className="mt-3 text-sm text-danger">38            {error}39          </p>40        )}41        <button type="submit" className="mt-4 inline-flex h-11 w-full items-center justify-center rounded-md bg-accent text-sm font-semibold text-accent-ink hover:brightness-110">42          Continue43        </button>44      </form>45    </Container>46  );47}48