68 lines
2.8 KiB
TypeScript
68 lines
2.8 KiB
TypeScript
import Link from "next/link";
|
|
|
|
/*
|
|
* The frame for every screen you can reach without a session: sign in, email
|
|
* verification, and accepting an invitation.
|
|
*
|
|
* These three had drifted into three different layouts. Sign in was a centred
|
|
* 26rem card with the lockup above it; verify and accept-invite were bare
|
|
* left-aligned text on the full 1200px rail, with no masthead, no panel and no
|
|
* brand anywhere on the page. Those two are the first screens a new customer
|
|
* ever sees — arriving from an email, on a domain they have not visited before
|
|
* — and they were the two that did not say whose product this is.
|
|
*
|
|
* There is no AppBar here on purpose: it carries navigation and an account
|
|
* menu, and none of it works without a session.
|
|
*/
|
|
export function AuthShell({
|
|
title,
|
|
lede,
|
|
children,
|
|
footnote,
|
|
}: {
|
|
title: string;
|
|
lede?: React.ReactNode;
|
|
children?: React.ReactNode;
|
|
/** Sits outside the panel: orientation, not part of the task. */
|
|
footnote?: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<main className="mx-auto flex min-h-screen w-full max-w-[26rem] flex-col justify-center px-5 py-12">
|
|
{/* The masthead's lockup, unlinked: there is nowhere to go yet. */}
|
|
<div className="mb-7 flex flex-col items-center gap-2 text-center">
|
|
<span className="flex items-baseline gap-2 text-[1.5rem] font-extrabold tracking-[-0.02em]">
|
|
Vantage
|
|
<span className="font-mono text-[0.78rem] font-normal uppercase tracking-[0.14em] text-ink-3">HQ</span>
|
|
</span>
|
|
<h1 className="text-[1.16rem]">{title}</h1>
|
|
{lede && <p className="text-[0.86rem] text-ink-2">{lede}</p>}
|
|
</div>
|
|
|
|
{children && <div className="grid gap-4 rounded border border-rule bg-panel p-6 shadow-[var(--shadow)]">{children}</div>}
|
|
|
|
{footnote && <div className="mt-5 text-center text-[0.8rem] text-ink-3">{footnote}</div>}
|
|
</main>
|
|
);
|
|
}
|
|
|
|
/*
|
|
* A terminal state — verified, expired, already used, invalid. Always says what
|
|
* happened and what to do next: a dead end that only reports the failure leaves
|
|
* someone holding an email they cannot act on.
|
|
*/
|
|
export function AuthMessage({ title, body, action }: { title: string; body: React.ReactNode; action?: { href: string; label: string } }) {
|
|
return (
|
|
<AuthShell title={title}>
|
|
<p className="text-[0.9rem] text-ink-2">{body}</p>
|
|
{action && (
|
|
<Link
|
|
href={action.href}
|
|
className="inline-flex items-center justify-center gap-2 rounded border border-accent bg-accent px-3.5 py-2 text-[0.86rem] font-semibold text-accent-ink no-underline"
|
|
>
|
|
{action.label}
|
|
</Link>
|
|
)}
|
|
</AuthShell>
|
|
);
|
|
}
|