Login page Authenticate and input icon

This commit is contained in:
sriram
2026-08-25 11:06:54 +05:30
parent 814347e2d2
commit e1247ce1b2
5 changed files with 84 additions and 13 deletions

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/useAuth';
import { ShieldCheck, Lock, User, ArrowRight, Sparkles } from 'lucide-react';
import { ShieldCheck, Lock, User, ArrowRight, Sparkles, Eye, EyeOff } from 'lucide-react';
/*
* There is exactly one interactive account: `admin`.
@@ -19,6 +19,7 @@ export function LoginPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
@@ -96,14 +97,36 @@ export function LoginPage() {
<label className="block text-xs font-medium text-slate-600 mb-1.5">Password</label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-400" />
{/* pr-11, unlike the username field's pr-4, keeps a long
password from running underneath the toggle button. */}
<input
type="password"
type={showPassword ? 'text' : 'password'}
required
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter password"
className="w-full rounded-xl border border-ink-900/15 bg-white py-2.5 pl-9 pr-4 text-sm text-ink-950 placeholder-slate-400 focus:border-amber-500 focus:outline-none focus:ring-2 focus:ring-amber-500/25"
className="w-full rounded-xl border border-ink-900/15 bg-white py-2.5 pl-9 pr-11 text-sm text-ink-950 placeholder-slate-400 focus:border-amber-500 focus:outline-none focus:ring-2 focus:ring-amber-500/25"
/>
{/*
type="button" is load-bearing: a <button> inside a <form>
defaults to type="submit", so peeking at the password would
fire a half-typed login attempt instead of revealing it.
The icon shows the ACTION, not the state - an open eye means
"reveal", which is the convention every browser and password
manager uses. aria-pressed carries the state for screen
readers, which the glyph alone cannot.
*/}
<button
type="button"
onClick={() => setShowPassword((shown) => !shown)}
aria-label={showPassword ? 'Hide password' : 'Show password'}
aria-pressed={showPassword}
title={showPassword ? 'Hide password' : 'Show password'}
className="absolute right-2 top-1/2 -translate-y-1/2 rounded-lg p-1.5 text-slate-400 hover:text-slate-600 hover:bg-ink-900/5 focus:outline-none focus:ring-2 focus:ring-amber-500/25 transition-colors cursor-pointer"
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</div>
</div>