Route-group layouts do the guarding. A customer session on /staff/* is redirected to its own home rather than shown a refusal -- there is nothing to tell them about. This is UX only: admin enforces the same boundary with RequireStaff/RequireCustomer and answers 404 rather than 403 for another account's data, which is the layer that actually matters. Signup carries the honeypot the backend expects and reports "check your email" rather than claiming an account exists, matching a backend that creates nothing until the link is opened. Buttons match site/'s .btn--solid and .btn--line, neutral border included. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
28 lines
798 B
TypeScript
28 lines
798 B
TypeScript
export function Field({
|
|
label,
|
|
hint,
|
|
error,
|
|
...input
|
|
}: React.InputHTMLAttributes<HTMLInputElement> & {
|
|
label: string;
|
|
hint?: React.ReactNode;
|
|
error?: string;
|
|
}) {
|
|
return (
|
|
<label className="grid max-w-md gap-1.5">
|
|
<span className="font-mono text-[0.72rem] uppercase tracking-[0.1em] text-ink-3">
|
|
{label}
|
|
</span>
|
|
<input
|
|
{...input}
|
|
className="rounded border border-rule bg-panel-2 px-2.5 py-2 font-mono text-ink"
|
|
/>
|
|
{error ? (
|
|
<span className="text-[0.82rem] text-expired">{error}</span>
|
|
) : hint ? (
|
|
<span className="text-[0.82rem] text-ink-3">{hint}</span>
|
|
) : null}
|
|
</label>
|
|
);
|
|
}
|