11"use client" ;
22
3+ import { useState , useEffect , useRef } from "react" ;
34import { Texto } from "./texto" ;
45import { Documento } from "./documento" ;
56import { Audio } from "./audio" ;
@@ -22,6 +23,8 @@ interface AutomaticQuestionsProps {
2223}
2324
2425export default function AutomaticQuestions ( { mode, onModeSelect, onDataChange, onSubmit } : AutomaticQuestionsProps ) {
26+ const [ focusedOptionIndex , setFocusedOptionIndex ] = useState < number > ( 0 ) ;
27+ const buttonRefs = useRef < ( HTMLButtonElement | null ) [ ] > ( [ ] ) ;
2528
2629 const handleDataChange = ( data : { text ?: string ; file ?: File ; num_questions : number ; num_alternatives : number } | null ) => {
2730 if ( data && mode ) {
@@ -34,6 +37,39 @@ export default function AutomaticQuestions({ mode, onModeSelect, onDataChange, o
3437 }
3538 } ;
3639
40+ // Keyboard navigation for mode selection
41+ useEffect ( ( ) => {
42+ if ( mode !== null ) return ; // Only active in selection mode
43+
44+ const handleKeyDown = ( e : KeyboardEvent ) => {
45+ const totalOptions = 3 ; // text, document, audio
46+
47+ if ( e . key === "ArrowDown" || e . key === "ArrowRight" ) {
48+ e . preventDefault ( ) ;
49+ setFocusedOptionIndex ( ( prev ) => ( prev + 1 ) % totalOptions ) ;
50+ } else if ( e . key === "ArrowUp" || e . key === "ArrowLeft" ) {
51+ e . preventDefault ( ) ;
52+ setFocusedOptionIndex ( ( prev ) => ( prev - 1 + totalOptions ) % totalOptions ) ;
53+ } else if ( e . key === "Enter" ) {
54+ e . preventDefault ( ) ;
55+ // Select the focused option
56+ const modes : GenerationMode [ ] = [ "text" , "document" , "audio" ] ;
57+ const selectedMode = modes [ focusedOptionIndex ] ;
58+ onModeSelect ( selectedMode ) ;
59+ }
60+ } ;
61+
62+ document . addEventListener ( "keydown" , handleKeyDown ) ;
63+ return ( ) => document . removeEventListener ( "keydown" , handleKeyDown ) ;
64+ } , [ mode , focusedOptionIndex , onModeSelect ] ) ;
65+
66+ // Focus the button when index changes
67+ useEffect ( ( ) => {
68+ if ( mode === null && buttonRefs . current [ focusedOptionIndex ] ) {
69+ buttonRefs . current [ focusedOptionIndex ] ?. focus ( ) ;
70+ }
71+ } , [ focusedOptionIndex , mode ] ) ;
72+
3773 if ( mode === "text" ) {
3874 return (
3975 < Texto
@@ -75,8 +111,11 @@ export default function AutomaticQuestions({ mode, onModeSelect, onDataChange, o
75111 < div className = "grid grid-cols-1 md:grid-cols-3 gap-6" >
76112 { /* Opção: Texto */ }
77113 < button
114+ ref = { ( el ) => { buttonRefs . current [ 0 ] = el ; } }
78115 onClick = { ( ) => onModeSelect ( "text" ) }
79- className = "group bg-layout-card border-2 rounded-xl p-6 hover:border-blue-500 hover:shadow-lg transition-all duration-200 text-left"
116+ className = { `group bg-layout-card border-2 rounded-xl p-6 hover:border-blue-500 hover:shadow-lg transition-all duration-200 text-left ${
117+ focusedOptionIndex === 0 && mode === null ? "ring-2 ring-blue-500 border-blue-500" : ""
118+ } `}
80119 >
81120 < div className = "w-14 h-14 bg-blue-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-blue-500 transition-colors" >
82121 < svg
@@ -102,8 +141,11 @@ export default function AutomaticQuestions({ mode, onModeSelect, onDataChange, o
102141
103142 { /* Opção: Documento */ }
104143 < button
144+ ref = { ( el ) => { buttonRefs . current [ 1 ] = el ; } }
105145 onClick = { ( ) => onModeSelect ( "document" ) }
106- className = "group bg-layout-card border-2 rounded-xl p-6 hover:border-green-500 hover:shadow-lg transition-all duration-200 text-left"
146+ className = { `group bg-layout-card border-2 rounded-xl p-6 hover:border-green-500 hover:shadow-lg transition-all duration-200 text-left ${
147+ focusedOptionIndex === 1 && mode === null ? "ring-2 ring-green-500 border-green-500" : ""
148+ } `}
107149 >
108150 < div className = "w-14 h-14 bg-green-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-green-500 transition-colors" >
109151 < svg
@@ -122,14 +164,17 @@ export default function AutomaticQuestions({ mode, onModeSelect, onDataChange, o
122164 </ div >
123165 < h3 className = "text-xl font-semibold mb-2" > Documento</ h3 >
124166 < p className = "text-sm " >
125- Faça upload de PDF, DOCX ou TXT para gerar questões
167+ Faça upload de PDF, DOCX, XLSX, PPTX ou TXT para gerar questões
126168 </ p >
127169 </ button >
128170
129171 { /* Opção: Áudio */ }
130172 < button
173+ ref = { ( el ) => { buttonRefs . current [ 2 ] = el ; } }
131174 onClick = { ( ) => onModeSelect ( "audio" ) }
132- className = "group bg-layout-card border-2 rounded-xl p-6 hover:border-purple-500 hover:shadow-lg transition-all duration-200 text-left"
175+ className = { `group bg-layout-card border-2 rounded-xl p-6 hover:border-purple-500 hover:shadow-lg transition-all duration-200 text-left ${
176+ focusedOptionIndex === 2 && mode === null ? "ring-2 ring-purple-500 border-purple-500" : ""
177+ } `}
133178 >
134179 < div className = "w-14 h-14 bg-purple-100 rounded-lg flex items-center justify-center mb-4 group-hover:bg-purple-500 transition-colors" >
135180 < svg
0 commit comments