feat(login): implementar alternância de visibilidade de senha

- Implementa funcionalidade de mostrar/esconder senha na página de login
- Integra ícones Eye e EyeOff para o controle de visibilidade
- Adiciona animação 'fade-up' à página de login
- Define novas classes de estilo para o campo de senha e botão de toggle
- Configura a regra '@typescript-eslint/semi' no ESLint
- Adiciona keyframes e animação 'fade-up' ao Tailwind CSS
master
Artur Oliveira 2025-12-16 09:30:35 -03:00
parent 91ec90f810
commit 81499374b6
3 changed files with 29 additions and 3 deletions

View File

@ -25,6 +25,7 @@ export default defineConfig([
'react/jsx-indent': ['error', 4], 'react/jsx-indent': ['error', 4],
'react/jsx-indent-props': ['error', 4], 'react/jsx-indent-props': ['error', 4],
'semi': ['error', 'always'], 'semi': ['error', 'always'],
'@typescript-eslint/semi': ['error', 'always'],
}, },
}, },
]) ])

View File

@ -1,12 +1,14 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Layout } from "../components/Layout"; import { Layout } from "../components/Layout";
import type { LoginProps } from "../types/Login"; import type { LoginProps } from "../types/Login";
import { Eye, EyeOff } from "lucide-icons-react";
export const Login = () => { export const Login = () => {
const [form, setForm] = useState<LoginProps>({ const [form, setForm] = useState<LoginProps>({
email: "", email: "",
password: "" password: ""
}); });
const [showPassword, setShowPassword] = useState<boolean>(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setForm({ setForm({
@ -15,6 +17,10 @@ export const Login = () => {
}); });
}; };
const handleShowPassword = () => {
setShowPassword(!showPassword);
};
useEffect(() => { useEffect(() => {
console.log(form); console.log(form);
}, [form]); }, [form]);
@ -35,10 +41,10 @@ export const Login = () => {
className={Styles.input} className={Styles.input}
onChange={handleChange}/> onChange={handleChange}/>
</div> </div>
<div> <div className={Styles.inputWrapper}>
<label htmlFor="password" className={Styles.label}>Password:</label> <label htmlFor="password" className={Styles.label}>Password:</label>
<input <input
type="password" type={showPassword ? "text" : "password"}
id="password" id="password"
name="password" name="password"
placeholder="********" placeholder="********"
@ -46,6 +52,14 @@ export const Login = () => {
className={Styles.input} className={Styles.input}
onChange={handleChange} onChange={handleChange}
/> />
<button
type="button"
aria-label={showPassword ? "Hide password" : "Show password"}
className={Styles.iconButton}
onClick={handleShowPassword}
>
{showPassword ? <Eye size={18} /> : <EyeOff size={18} />}
</button>
</div> </div>
<button type="submit" className={Styles.button}>Login</button> <button type="submit" className={Styles.button}>Login</button>
</form> </form>
@ -55,10 +69,12 @@ export const Login = () => {
}; };
const Styles = { const Styles = {
layout: "h-screen flex flex-col gap-4 justify-center", layout: "h-screen flex flex-col gap-4 justify-center animate-fade-up",
logo: "w-36 h-36 mx-auto mb-4", logo: "w-36 h-36 mx-auto mb-4",
card: "w-96 p-8 shadow-lg rounded-lg border border-cardBorder bg-card", card: "w-96 p-8 shadow-lg rounded-lg border border-cardBorder bg-card",
label: "block mb-2 text-md font-medium text-text", label: "block mb-2 text-md font-medium text-text",
inputWrapper: "relative",
input: "bg-gray-50 border border-cardBorder text-text text-md rounded-lg outline-none block w-full p-2.5", input: "bg-gray-50 border border-cardBorder text-text text-md rounded-lg outline-none block w-full p-2.5",
iconButton: "absolute right-3 top-1/2 text-text p-1 focus:outline-none",
button: "w-full bg-accent p-2 rounded-md mt-4 text-white font-bold text-lg hover:bg-hover transition duration-150", button: "w-full bg-accent p-2 rounded-md mt-4 text-white font-bold text-lg hover:bg-hover transition duration-150",
}; };

View File

@ -15,6 +15,15 @@ export default {
hover: '#D04A0F', hover: '#D04A0F',
accent: '#E95A1B', accent: '#E95A1B',
}, },
keyframes: {
'fade-up': {
'0%': { opacity: '0', transform: 'translateY(8px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
},
animation: {
'fade-up': 'fade-up 300ms ease-out forwards',
},
}, },
}, },
plugins: [], plugins: [],