BetterFrame/server/src/web-templates/auth-pages.tsx
2026-05-10 01:09:13 +02:00

165 lines
5.1 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Auth page templates: setup, login, TOTP, recovery.
*/
import { js } from "jsx-htmx";
import { MinimalLayout } from "./layout.js";
// ---- Setup ------------------------------------------------------------------
export function SetupPage(props: { error?: string; username?: string }) {
return (
<MinimalLayout
title="Initial Setup"
flash={props.error ? { type: "error", message: props.error } : undefined}
>
<p style="color:#666; margin-bottom:1.25rem">
Create your admin account to get started.
</p>
<form method="post" action="/setup">
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
name="username"
type="text"
class="form-input"
required
minlength="3"
maxlength="64"
pattern="[a-zA-Z0-9_-]+"
value={props.username ?? ""}
autocomplete="username"
/>
<div class="form-hint">364 characters. Letters, digits, underscore, hyphen.</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
class="form-input"
required
minlength="12"
autocomplete="new-password"
/>
<div class="form-hint">At least 12 characters.</div>
</div>
<button type="submit" class="btn btn-primary btn-block">Create Admin Account</button>
</form>
</MinimalLayout>
);
}
// ---- Login ------------------------------------------------------------------
export function LoginPage(props: { error?: string; username?: string; welcome?: boolean }) {
return (
<MinimalLayout
title="Sign In"
flash={
props.error
? { type: "error", message: props.error }
: props.welcome
? { type: "success", message: "Admin account created. Sign in to continue." }
: undefined
}
>
<form method="post" action="/auth/login">
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
name="username"
type="text"
class="form-input"
required
value={props.username ?? ""}
autocomplete="username"
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
class="form-input"
required
autocomplete="current-password"
/>
</div>
<button type="submit" class="btn btn-primary btn-block">Sign In</button>
</form>
</MinimalLayout>
);
}
// ---- TOTP -------------------------------------------------------------------
export function TotpPage(props: { error?: string }) {
return (
<MinimalLayout
title="Two-Factor Authentication"
flash={props.error ? { type: "error", message: props.error } : undefined}
>
<p style="color:#666; margin-bottom:1rem">
Enter the 6-digit code from your authenticator app.
</p>
<form method="post" action="/auth/totp">
<div class="form-group">
<label for="code">Code</label>
<input
id="code"
name="code"
type="text"
class="form-input"
required
maxlength="6"
pattern="[0-9]{6}"
autocomplete="one-time-code"
inputmode="numeric"
style="text-align:center; font-size:1.5rem; letter-spacing:0.3rem"
/>
</div>
<button type="submit" class="btn btn-primary btn-block">Verify</button>
</form>
<p style="text-align:center; margin-top:1rem">
<a href="/auth/recovery">Use a recovery code</a>
</p>
</MinimalLayout>
);
}
// ---- Recovery ---------------------------------------------------------------
export function RecoveryPage(props: { error?: string }) {
return (
<MinimalLayout
title="Recovery Code"
flash={props.error ? { type: "error", message: props.error } : undefined}
>
<p style="color:#666; margin-bottom:1rem">
Enter one of your recovery codes. Each code can only be used once.
</p>
<form method="post" action="/auth/recovery">
<div class="form-group">
<label for="code">Recovery Code</label>
<input
id="code"
name="code"
type="text"
class="form-input"
required
maxlength="10"
style="text-align:center; font-size:1.1rem; letter-spacing:0.15rem; text-transform:uppercase"
/>
</div>
<button type="submit" class="btn btn-primary btn-block">Verify</button>
</form>
<p style="text-align:center; margin-top:1rem">
<a href="/auth/totp">Back to authenticator code</a>
</p>
</MinimalLayout>
);
}