milestone 23 s3: convert auth/LoginPage.tsx to stylex
This commit is contained in:
+59
-10
@@ -1,8 +1,57 @@
|
||||
import { useEffect, useState, type FormEvent } from "react";
|
||||
import { useRouter, useSearch } from "@tanstack/react-router";
|
||||
import * as stylex from "@stylexjs/stylex";
|
||||
import { ApiError } from "@/lib/api";
|
||||
import { useAuth } from "@/auth/store";
|
||||
import { inputClass, largePrimaryButtonClass } from "@/ui/classes";
|
||||
import { styles as shared } from "@/ui/styles";
|
||||
import { colors } from "@/ui/tokens.stylex";
|
||||
|
||||
const styles = stylex.create({
|
||||
/** Login renders outside AppShell, so it paints the page ground itself. */
|
||||
page: {
|
||||
display: "flex",
|
||||
minHeight: "100dvh",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: colors.surface,
|
||||
color: colors.text,
|
||||
padding: "1rem",
|
||||
},
|
||||
card: {
|
||||
width: "100%",
|
||||
maxWidth: "24rem",
|
||||
},
|
||||
heading: {
|
||||
fontSize: "1.5rem",
|
||||
lineHeight: "2rem",
|
||||
fontWeight: 600,
|
||||
},
|
||||
probing: {
|
||||
marginTop: "1rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
form: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "1rem",
|
||||
marginTop: "1.5rem",
|
||||
},
|
||||
fieldLabel: {
|
||||
display: "block",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
fontWeight: 500,
|
||||
},
|
||||
submit: {
|
||||
width: "100%",
|
||||
},
|
||||
error: {
|
||||
marginTop: "1rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.danger,
|
||||
},
|
||||
});
|
||||
|
||||
export function safeRedirect(raw: string | undefined): string {
|
||||
if (raw === undefined) return "/";
|
||||
@@ -76,15 +125,15 @@ export default function LoginPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex min-h-dvh items-center justify-center bg-zinc-50 p-4 text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
|
||||
<section className="w-full max-w-sm">
|
||||
<h1 className="text-2xl font-semibold">nxdns</h1>
|
||||
<main {...stylex.props(styles.page)}>
|
||||
<section {...stylex.props(styles.card)}>
|
||||
<h1 {...stylex.props(styles.heading)}>nxdns</h1>
|
||||
{authRequired !== true ? (
|
||||
<p className="mt-4 text-zinc-500">Checking whether a password is required…</p>
|
||||
<p {...stylex.props(styles.probing)}>Checking whether a password is required…</p>
|
||||
) : (
|
||||
<form onSubmit={onSubmit} className="mt-6 space-y-4">
|
||||
<form onSubmit={onSubmit} {...stylex.props(styles.form)}>
|
||||
<div>
|
||||
<label htmlFor="password" className="block text-sm font-medium">
|
||||
<label htmlFor="password" {...stylex.props(styles.fieldLabel)}>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
@@ -95,20 +144,20 @@ export default function LoginPage() {
|
||||
required
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
className={inputClass}
|
||||
{...stylex.props(shared.input, shared.focusRing)}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={busy || lockedOut}
|
||||
className={`w-full ${largePrimaryButtonClass}`}
|
||||
{...stylex.props(shared.largePrimaryButton, styles.submit, shared.focusRing)}
|
||||
>
|
||||
{busy ? "Logging in…" : "Log in"}
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
{error !== null && (
|
||||
<p role="alert" className="mt-4 text-sm text-red-600 dark:text-red-400">
|
||||
<p role="alert" {...stylex.props(styles.error)}>
|
||||
{errorMessage(error, remaining)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user