Skip to content

Commit 6ba828c

Browse files
committed
adiciona algumas nveçãoes por teclado
1 parent 0955a7a commit 6ba828c

File tree

6 files changed

+176
-31
lines changed

6 files changed

+176
-31
lines changed

frontend/src/app/(home)/create/questions/automatico/automatico.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// /create/question/automatico/automatico.tsx
21
"use client";
32

43
import { useState } from "react";
Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,49 @@
11
"use client";
22

3-
import { CiAlarmOn, CiBasketball, CiBookmarkPlus, CiShare1, CiUser, CiViewList } from "react-icons/ci";
3+
import { CiBookmarkPlus, CiUser, CiViewList } from "react-icons/ci";
4+
import { BsArrowUp, BsArrowDown, BsArrowLeft, BsArrowRight } from "react-icons/bs";
45
import HomeCard from "./card";
56
import Acessibilidade from "./acessibilidade";
67
import { useUser } from "@/hook/useUser";
78
import { useEffect } from "react";
8-
// import ThemeList from "./themeList";
9-
9+
import { useRouter } from "next/navigation";
1010

1111
export default function Home() {
12-
const { user, getMe } = useUser();
13-
useEffect(() => {
14-
getMe();
15-
}, []);
12+
const { user, getMe } = useUser();
13+
const router = useRouter();
14+
15+
useEffect(() => {
16+
getMe();
17+
}, []);
18+
19+
useEffect(() => {
20+
const handleKeyDown = (e: KeyboardEvent) => {
21+
switch (e.key) {
22+
case "ArrowUp":
23+
e.preventDefault();
24+
router.push("/create"); // Navega para Criar Quiz
25+
break;
26+
case "ArrowDown":
27+
e.preventDefault();
28+
router.push("/play"); // Navega para Ver Quizzes
29+
break;
30+
case "ArrowRight":
31+
e.preventDefault();
32+
router.push("/profile"); // Navega para Perfil
33+
break;
34+
}
35+
};
36+
37+
document.addEventListener("keydown", handleKeyDown);
38+
39+
return () => {
40+
document.removeEventListener("keydown", handleKeyDown);
41+
};
42+
}, [router]);
1643

1744
return (
1845
<div className="flex h-full mt-6 space-x-24">
1946
<div className="flex-1 h-full flex flex-col gap-9">
20-
{/* <div className="flex-1 h-full flex flex-col gap-9 max-w-2/3"> */}
2147
<h1 className="font-bold text-4xl capitalize">
2248
Olá, {user?.name || "Visitante"}!
2349
</h1>
@@ -30,7 +56,7 @@ const { user, getMe } = useUser();
3056
href= "/create"
3157
ariaLabel= "Criar Quiz - Crie seus próprios quizzes personalizados."
3258
color= "create"
33-
cornerIcon={<CiShare1 />}
59+
cornerIcon={<BsArrowUp />}
3460
/>
3561
<HomeCard
3662
key= {3}
@@ -39,6 +65,7 @@ const { user, getMe } = useUser();
3965
description= "Veja sua lista de quizzes."
4066
href= "/play"
4167
color= "play"
68+
cornerIcon={<BsArrowDown />}
4269
/>
4370
<HomeCard
4471
key= {4}
@@ -47,12 +74,12 @@ const { user, getMe } = useUser();
4774
description= "Acesse e edite seu perfil."
4875
href= "/profile"
4976
color= "ranking"
77+
cornerIcon={<BsArrowRight />}
5078
/>
5179
</div>
5280
<Acessibilidade />
5381
</div>
5482

55-
{/* <ThemeList /> */}
5683
</div>
5784
);
58-
}
85+
}

frontend/src/app/login/page.tsx

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useRef, useEffect } from "react";
44
import { Input } from "@/components/ui/input";
55
import { useAuth } from "@/hook/useAuth";
66
import { Button } from "@/components/ui/button";
7+
import { BsArrowDown, BsArrowUp, BsArrowReturnLeft } from "react-icons/bs";
78

89
export default function Login() {
910
const { login, loading, error } = useAuth();
1011
const [email, setEmail] = useState("");
1112
const [password, setPassword] = useState("");
13+
14+
const emailRef = useRef<HTMLInputElement>(null);
15+
const passwordRef = useRef<HTMLInputElement>(null);
16+
const buttonRef = useRef<HTMLButtonElement>(null);
1217

1318
const handleSubmit = async (e: React.FormEvent) => {
1419
e.preventDefault();
@@ -19,6 +24,39 @@ export default function Login() {
1924
}
2025
};
2126

27+
useEffect(() => {
28+
const handleKeyDown = (e: KeyboardEvent) => {
29+
// Seta para cima - foca no email
30+
if (e.key === "ArrowUp") {
31+
e.preventDefault();
32+
emailRef.current?.focus();
33+
}
34+
// Seta para baixo - foca na senha
35+
else if (e.key === "ArrowDown") {
36+
e.preventDefault();
37+
if (document.activeElement === emailRef.current) {
38+
passwordRef.current?.focus();
39+
} else {
40+
emailRef.current?.focus();
41+
}
42+
}
43+
else if ((e.key === "ArrowReturnLeft" || e.key === "Enter") &&
44+
document.activeElement !== emailRef.current &&
45+
document.activeElement !== passwordRef.current) {
46+
e.preventDefault();
47+
if (!loading) {
48+
buttonRef.current?.click();
49+
}
50+
}
51+
};
52+
53+
document.addEventListener("keydown", handleKeyDown);
54+
55+
return () => {
56+
document.removeEventListener("keydown", handleKeyDown);
57+
};
58+
}, [loading]);
59+
2260
return (
2361
<div className="flex flex-col items-center justify-center">
2462
{loading && <p>Carregando...</p>}
@@ -31,30 +69,36 @@ export default function Login() {
3169
<div className="grid grid-cols-1 gap-2">
3270
<label>Email</label>
3371
<Input
72+
ref={emailRef}
3473
type="email"
3574
value={email}
3675
onChange={(e) => setEmail(e.target.value)}
76+
suffix={<BsArrowUp />}
3777
required
3878
/>
3979
</div>
4080
<div className="grid grid-cols-1 gap-2">
4181
<label>Senha</label>
4282
<Input
83+
ref={passwordRef}
4384
type="password"
85+
suffix={<BsArrowDown />}
4486
value={password}
4587
onChange={(e) => setPassword(e.target.value)}
4688
required
4789
/>
4890
</div>
4991
<Button
92+
ref={buttonRef}
5093
type="submit"
5194
disabled={loading}
5295
className="mt-4 hover:bg-qorange-500"
96+
suffix={<BsArrowReturnLeft />}
5397
>
5498
{loading ? "Entrando..." : "Entrar"}
5599
</Button>
56100
<div>Novo no QuizLab? <a href="/quiz-lab/registro" className="text-qyellow-default cursor-pointer underline">Cadastre-se</a></div>
57101
</form>
58102
</div>
59103
);
60-
}
104+
}

frontend/src/app/registro/page.tsx

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useEffect, useState, useRef } from "react";
44
import { Input } from "@/components/ui/input";
55
import { useAuth } from "@/hook/useAuth";
66
import { Button } from "@/components/ui/button";
7+
import { BsArrowDown, BsArrowLeft, BsArrowReturnLeft, BsArrowUp } from "react-icons/bs";
78

89
export default function Registro() {
910
const { register, loading, error, clearError } = useAuth();
1011
const [name, setName] = useState("");
1112
const [email, setEmail] = useState("");
1213
const [password, setPassword] = useState("");
1314

15+
const nameRef = useRef<HTMLInputElement>(null);
16+
const emailRef = useRef<HTMLInputElement>(null);
17+
const passwordRef = useRef<HTMLInputElement>(null);
18+
const buttonRef = useRef<HTMLButtonElement>(null);
19+
1420
const handleSubmit = async (e: React.FormEvent) => {
1521
e.preventDefault();
1622
clearError();
@@ -23,6 +29,51 @@ export default function Registro() {
2329
}
2430
};
2531

32+
useEffect(() => {
33+
const handleKeyDown = (e: KeyboardEvent) => {
34+
// Seta para cima - foca no nome
35+
if (e.key === "ArrowUp") {
36+
e.preventDefault();
37+
nameRef.current?.focus();
38+
}
39+
// Seta para direita - navega entre campos
40+
else if (e.key === "ArrowRight") {
41+
e.preventDefault();
42+
if (document.activeElement === nameRef.current) {
43+
emailRef.current?.focus();
44+
} else if (document.activeElement === emailRef.current) {
45+
passwordRef.current?.focus();
46+
} else {
47+
nameRef.current?.focus();
48+
}
49+
}
50+
// Seta para baixo - navega entre campos
51+
else if (e.key === "ArrowDown") {
52+
e.preventDefault();
53+
if (document.activeElement === nameRef.current) {
54+
emailRef.current?.focus();
55+
} else if (document.activeElement === emailRef.current) {
56+
passwordRef.current?.focus();
57+
} else {
58+
nameRef.current?.focus();
59+
}
60+
}
61+
// Enter - submete o formulário
62+
else if (e.key === "Enter") {
63+
e.preventDefault();
64+
if (!loading) {
65+
buttonRef.current?.click();
66+
}
67+
}
68+
};
69+
70+
document.addEventListener("keydown", handleKeyDown);
71+
72+
return () => {
73+
document.removeEventListener("keydown", handleKeyDown);
74+
};
75+
}, [loading]);
76+
2677
return (
2778
<div className="flex flex-col items-center justify-center">
2879
<h1 className="text-6xl font-black">Cadastrar-se</h1>
@@ -45,6 +96,8 @@ export default function Registro() {
4596
value={name}
4697
onChange={(e) => setName(e.target.value)}
4798
disabled={loading}
99+
ref={nameRef}
100+
suffix={<BsArrowUp />}
48101
required
49102
/>
50103
</div>
@@ -54,9 +107,11 @@ export default function Registro() {
54107
<Input
55108
id="email"
56109
type="email"
110+
ref={emailRef}
57111
value={email}
58112
onChange={(e) => setEmail(e.target.value)}
59113
disabled={loading}
114+
suffix={<BsArrowDown />}
60115
required
61116
/>
62117
</div>
@@ -67,18 +122,24 @@ export default function Registro() {
67122
id="password"
68123
type="password"
69124
value={password}
125+
ref={passwordRef}
70126
onChange={(e) => setPassword(e.target.value)}
71127
disabled={loading}
128+
suffix={<BsArrowLeft />}
72129
required
73130
/>
74131
</div>
132+
75133
<Button
76-
type="submit"
77-
disabled={loading}
78-
className="mt-4 hover:bg-qorange-500"
79-
>
134+
ref={buttonRef}
135+
type="submit"
136+
disabled={loading}
137+
className="mt-4 hover:bg-qorange-500"
138+
suffix={<BsArrowReturnLeft />}
139+
>
80140
{loading ? "Registrando..." : "Registrar"}
81141
</Button>
142+
82143
<div>Já tem uma conta? <a className="text-qyellow-default cursor-pointer underline" href="/quiz-lab/login">Faça login!</a></div>
83144
</form>
84145
</div>

frontend/src/components/ui/button.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { forwardRef } from "react";
4-
import type { ButtonHTMLAttributes } from "react";
4+
import type { ButtonHTMLAttributes, ReactNode } from "react";
55
import { cn } from "@/lib/utils";
66

77
const baseStyles =
@@ -25,10 +25,11 @@ export type ButtonSize = keyof typeof sizeStyles;
2525
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
2626
variant?: ButtonVariant;
2727
size?: ButtonSize;
28+
suffix?: ReactNode;
2829
}
2930

3031
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
31-
({ variant = "solid", size = "md", className, disabled, ...props }, ref) => {
32+
({ variant = "solid", size = "md", className, disabled, suffix, children, ...props }, ref) => {
3233
return (
3334
<button
3435
ref={ref}
@@ -41,7 +42,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
4142
)}
4243
disabled={disabled}
4344
{...props}
44-
/>
45+
>
46+
{children}
47+
{suffix && <span className="ml-2">{suffix}</span>}
48+
</button>
4549
);
4650
}
4751
);

0 commit comments

Comments
 (0)