Embed login password eye toggle inside the field.

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-13 23:51:33 +08:00
parent b5da5948a8
commit 6d21d45185
2 changed files with 53 additions and 49 deletions

View file

@ -8941,16 +8941,18 @@ pre {
.login-card__password { .login-card__password {
position: relative; position: relative;
display: block; display: block;
width: 100%;
} }
.login-card__password input { .login-card__password input {
padding-right: 44px; padding-right: 44px !important;
} }
.login-card__eye { .login-card__eye {
position: absolute; position: absolute;
top: 50%; top: 50%;
right: 6px; right: 6px;
z-index: 2;
transform: translateY(-50%); transform: translateY(-50%);
width: 34px; width: 34px;
height: 34px; height: 34px;
@ -8969,6 +8971,12 @@ pre {
color: #93c5fd; color: #93c5fd;
} }
.login-card__eye:focus-visible {
outline: none;
color: #93c5fd;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.35);
}
.login-card__eye svg { .login-card__eye svg {
display: block; display: block;
pointer-events: none; pointer-events: none;

View file

@ -1,4 +1,4 @@
import { Alert, Button, Card, Form, Input, InputGroup, Label, TextField } from "@heroui/react"; import { Alert, Button, Card, Form, Input, Label, TextField } from "@heroui/react";
import { useState, type FormEvent } from "react"; import { useState, type FormEvent } from "react";
import { Navigate, useSearchParams } from "react-router-dom"; import { Navigate, useSearchParams } from "react-router-dom";
import { useAuth } from "../auth/AuthContext"; import { useAuth } from "../auth/AuthContext";
@ -57,53 +57,49 @@ export function LoginPage() {
<Input placeholder={t("auth.username")} /> <Input placeholder={t("auth.username")} />
</TextField> </TextField>
<TextField <div className="login-card__password">
fullWidth <TextField
name="password" fullWidth
value={password} name="password"
onChange={setPassword} type={showPassword ? "text" : "password"}
isDisabled={busy || !ready} value={password}
autoComplete="current-password" onChange={setPassword}
> isDisabled={busy || !ready}
<Label className="login-card__sr">{t("auth.password")}</Label> autoComplete="current-password"
<InputGroup fullWidth> >
<InputGroup.Input <Label className="login-card__sr">{t("auth.password")}</Label>
type={showPassword ? "text" : "password"} <Input placeholder={t("auth.password")} />
placeholder={t("auth.password")} </TextField>
/> <button
<InputGroup.Suffix> type="button"
<Button className="login-card__eye"
isIconOnly aria-label={showPassword ? "Hide password" : "Show password"}
size="sm" tabIndex={-1}
variant="ghost" onClick={() => setShowPassword((v) => !v)}
aria-label={showPassword ? "Hide password" : "Show password"} >
onPress={() => setShowPassword((v) => !v)} {showPassword ? (
> <svg viewBox="0 0 24 24" width="18" height="18" fill="none" aria-hidden="true">
{showPassword ? ( <path
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" aria-hidden="true"> d="M3 3l18 18M10.6 10.6a2.5 2.5 0 0 0 3.5 3.5M9.9 5.1A10 10 0 0 1 12 4.8c5.5 0 9.2 5.3 10.2 6.7a1.2 1.2 0 0 1 0 1.4c-.4.6-1.3 1.8-2.7 3M6.1 6.1C4.2 7.5 2.9 9.3 2 11.1a1.2 1.2 0 0 0 0 1.4C3 13.9 6.7 19.2 12 19.2c1.4 0 2.7-.3 3.9-.8"
<path stroke="currentColor"
d="M3 3l18 18M10.6 10.6a2.5 2.5 0 0 0 3.5 3.5M9.9 5.1A10 10 0 0 1 12 4.8c5.5 0 9.2 5.3 10.2 6.7a1.2 1.2 0 0 1 0 1.4c-.4.6-1.3 1.8-2.7 3M6.1 6.1C4.2 7.5 2.9 9.3 2 11.1a1.2 1.2 0 0 0 0 1.4C3 13.9 6.7 19.2 12 19.2c1.4 0 2.7-.3 3.9-.8" strokeWidth="1.75"
stroke="currentColor" strokeLinecap="round"
strokeWidth="1.75" strokeLinejoin="round"
strokeLinecap="round" />
strokeLinejoin="round" </svg>
/> ) : (
</svg> <svg viewBox="0 0 24 24" width="18" height="18" fill="none" aria-hidden="true">
) : ( <path
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" aria-hidden="true"> d="M2 12.2C3 10.5 6.7 4.8 12 4.8s9 5.7 10 7.4a1.2 1.2 0 0 1 0 1.2C21 15.1 17.3 20.8 12 20.8S3 15.1 2 13.4a1.2 1.2 0 0 1 0-1.2Z"
<path stroke="currentColor"
d="M2 12.2C3 10.5 6.7 4.8 12 4.8s9 5.7 10 7.4a1.2 1.2 0 0 1 0 1.2C21 15.1 17.3 20.8 12 20.8S3 15.1 2 13.4a1.2 1.2 0 0 1 0-1.2Z" strokeWidth="1.75"
stroke="currentColor" strokeLinejoin="round"
strokeWidth="1.75" />
strokeLinejoin="round" <circle cx="12" cy="12.8" r="3" stroke="currentColor" strokeWidth="1.75" />
/> </svg>
<circle cx="12" cy="12.8" r="3" stroke="currentColor" strokeWidth="1.75" /> )}
</svg> </button>
)} </div>
</Button>
</InputGroup.Suffix>
</InputGroup>
</TextField>
{error ? ( {error ? (
<Alert status="danger" className="login-card__error"> <Alert status="danger" className="login-card__error">