fix(web): restore login page design and add runtime config injection (#435)
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #435.
This commit is contained in:
@@ -9,12 +9,14 @@ export interface LoginFormProps {
|
||||
onSubmit: (email: string, password: string) => void | Promise<void>;
|
||||
isLoading?: boolean;
|
||||
error?: string | null;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function LoginForm({
|
||||
onSubmit,
|
||||
isLoading = false,
|
||||
error = null,
|
||||
disabled = false,
|
||||
}: LoginFormProps): ReactElement {
|
||||
const emailRef = useRef<HTMLInputElement>(null);
|
||||
const [email, setEmail] = useState("");
|
||||
@@ -77,7 +79,10 @@ export function LoginForm({
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label htmlFor="login-email" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label
|
||||
htmlFor="login-email"
|
||||
className="mb-2 block text-[0.72rem] font-semibold uppercase tracking-[0.08em] text-[#2f3b52] dark:text-[#c5d0e6]"
|
||||
>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
@@ -91,13 +96,17 @@ export function LoginForm({
|
||||
validateEmail(e.target.value);
|
||||
}
|
||||
}}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || disabled}
|
||||
autoComplete="email"
|
||||
className={[
|
||||
"w-full px-3 py-2 border rounded-md",
|
||||
"focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors",
|
||||
emailError ? "border-blue-400" : "border-gray-300",
|
||||
isLoading ? "opacity-50" : "",
|
||||
"w-full rounded-lg border px-3.5 py-2.5 text-sm",
|
||||
"bg-[#f8faff]/90 text-[#0f141d] placeholder:text-[#5a6a87]",
|
||||
"transition-colors focus:outline-none focus:ring-2 focus:ring-[#56a0ff]/25",
|
||||
"dark:bg-[#0f141d]/80 dark:text-[#eef3ff] dark:placeholder:text-[#8f9db7]",
|
||||
emailError
|
||||
? "border-[#f06a6f] focus:border-[#e5484d]"
|
||||
: "border-[#b8c4de] focus:border-[#2f80ff] dark:border-[#2f3b52] dark:focus:border-[#56a0ff]",
|
||||
isLoading || disabled ? "opacity-50" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
@@ -105,14 +114,21 @@ export function LoginForm({
|
||||
aria-describedby={emailError ? "login-email-error" : undefined}
|
||||
/>
|
||||
{emailError && (
|
||||
<p id="login-email-error" className="mt-1 text-sm text-blue-600" role="alert">
|
||||
<p
|
||||
id="login-email-error"
|
||||
className="mt-1 text-sm text-[#b91c1c] dark:text-[#fda4af]"
|
||||
role="alert"
|
||||
>
|
||||
{emailError}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="login-password" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label
|
||||
htmlFor="login-password"
|
||||
className="mb-2 block text-[0.72rem] font-semibold uppercase tracking-[0.08em] text-[#2f3b52] dark:text-[#c5d0e6]"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
@@ -125,13 +141,17 @@ export function LoginForm({
|
||||
validatePassword(e.target.value);
|
||||
}
|
||||
}}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || disabled}
|
||||
autoComplete="current-password"
|
||||
className={[
|
||||
"w-full px-3 py-2 border rounded-md",
|
||||
"focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors",
|
||||
passwordError ? "border-blue-400" : "border-gray-300",
|
||||
isLoading ? "opacity-50" : "",
|
||||
"w-full rounded-lg border px-3.5 py-2.5 text-sm",
|
||||
"bg-[#f8faff]/90 text-[#0f141d] placeholder:text-[#5a6a87]",
|
||||
"transition-colors focus:outline-none focus:ring-2 focus:ring-[#56a0ff]/25",
|
||||
"dark:bg-[#0f141d]/80 dark:text-[#eef3ff] dark:placeholder:text-[#8f9db7]",
|
||||
passwordError
|
||||
? "border-[#f06a6f] focus:border-[#e5484d]"
|
||||
: "border-[#b8c4de] focus:border-[#2f80ff] dark:border-[#2f3b52] dark:focus:border-[#56a0ff]",
|
||||
isLoading || disabled ? "opacity-50" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
@@ -139,7 +159,11 @@ export function LoginForm({
|
||||
aria-describedby={passwordError ? "login-password-error" : undefined}
|
||||
/>
|
||||
{passwordError && (
|
||||
<p id="login-password-error" className="mt-1 text-sm text-blue-600" role="alert">
|
||||
<p
|
||||
id="login-password-error"
|
||||
className="mt-1 text-sm text-[#b91c1c] dark:text-[#fda4af]"
|
||||
role="alert"
|
||||
>
|
||||
{passwordError}
|
||||
</p>
|
||||
)}
|
||||
@@ -147,13 +171,13 @@ export function LoginForm({
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || disabled}
|
||||
className={[
|
||||
"w-full inline-flex items-center justify-center gap-2",
|
||||
"rounded-md px-4 py-2 text-base font-medium",
|
||||
"bg-blue-600 text-white hover:bg-blue-700",
|
||||
"transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500",
|
||||
isLoading ? "opacity-50 pointer-events-none" : "",
|
||||
"w-full inline-flex items-center justify-center gap-2 rounded-lg px-4 py-3 text-sm font-semibold text-white",
|
||||
"bg-[linear-gradient(135deg,#2f80ff,#8b5cf6)]",
|
||||
"transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-[#56a0ff]/60",
|
||||
"hover:-translate-y-0.5 hover:shadow-[0_10px_30px_rgba(47,128,255,0.38)]",
|
||||
isLoading || disabled ? "opacity-50 pointer-events-none" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
|
||||
Reference in New Issue
Block a user