| import { useState, useEffect, useRef } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Input } from "@/components/ui/input"; | |
| import { motion } from "framer-motion"; | |
| import { useTranslation } from "@/hooks/useTranslation"; | |
| import { useContext } from "react"; | |
| import { LanguageContext } from "@/contexts/LanguageContext"; | |
| import { ArrowLeft } from "lucide-react"; | |
| type Theme = "standard" | "technology" | "sports" | "food" | "custom"; | |
| interface ThemeSelectorProps { | |
| onThemeSelect: (theme: string) => void; | |
| onBack: () => void; | |
| } | |
| export const ThemeSelector = ({ onThemeSelect, onBack }: ThemeSelectorProps) => { | |
| const [selectedTheme, setSelectedTheme] = useState<Theme>("standard"); | |
| const [customTheme, setCustomTheme] = useState(""); | |
| const [isGenerating, setIsGenerating] = useState(false); | |
| const inputRef = useRef<HTMLInputElement>(null); | |
| const t = useTranslation(); | |
| const { language } = useContext(LanguageContext); | |
| useEffect(() => { | |
| const handleKeyPress = (e: KeyboardEvent) => { | |
| if (e.target instanceof HTMLInputElement) return; | |
| switch(e.key.toLowerCase()) { | |
| case 'a': | |
| setSelectedTheme("standard"); | |
| break; | |
| case 'b': | |
| setSelectedTheme("sports"); | |
| break; | |
| case 'c': | |
| setSelectedTheme("food"); | |
| break; | |
| case 'd': | |
| e.preventDefault(); | |
| setSelectedTheme("custom"); | |
| break; | |
| case 'enter': | |
| if (selectedTheme !== "custom" || customTheme.trim()) { | |
| handleSubmit(); | |
| } | |
| break; | |
| case 'backspace': | |
| e.preventDefault(); | |
| onBack(); | |
| break; | |
| } | |
| }; | |
| window.addEventListener('keydown', handleKeyPress); | |
| return () => window.removeEventListener('keydown', handleKeyPress); | |
| }, [selectedTheme, customTheme, language, onBack]); | |
| useEffect(() => { | |
| if (selectedTheme === "custom") { | |
| setTimeout(() => { | |
| inputRef.current?.focus(); | |
| }, 100); | |
| } | |
| }, [selectedTheme]); | |
| const handleSubmit = async () => { | |
| if (selectedTheme === "custom" && !customTheme.trim()) return; | |
| setIsGenerating(true); | |
| try { | |
| await onThemeSelect(selectedTheme === "custom" ? customTheme : selectedTheme); | |
| } finally { | |
| setIsGenerating(false); | |
| } | |
| }; | |
| const handleInputKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { | |
| if (e.key === 'Enter' && customTheme.trim()) { | |
| handleSubmit(); | |
| } | |
| }; | |
| return ( | |
| <motion.div | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| className="space-y-6" | |
| > | |
| <div className="flex items-center justify-between mb-4"> | |
| <Button | |
| variant="ghost" | |
| size="icon" | |
| onClick={onBack} | |
| className="hover:bg-gray-100" | |
| > | |
| <ArrowLeft className="h-4 w-4" /> | |
| </Button> | |
| <h2 className="text-2xl font-bold text-gray-900">{t.themes.title}</h2> | |
| <div className="w-8" /> {/* Spacer for centering */} | |
| </div> | |
| <p className="text-gray-600 text-center">{t.themes.subtitle}</p> | |
| <div className="space-y-4"> | |
| <Button | |
| variant={selectedTheme === "standard" ? "default" : "outline"} | |
| className="w-full justify-between" | |
| onClick={() => setSelectedTheme("standard")} | |
| > | |
| {t.themes.standard} <span className="text-sm opacity-50">{t.themes.pressKey} A</span> | |
| </Button> | |
| <Button | |
| variant={selectedTheme === "sports" ? "default" : "outline"} | |
| className="w-full justify-between" | |
| onClick={() => setSelectedTheme("sports")} | |
| > | |
| {t.themes.sports} <span className="text-sm opacity-50">{t.themes.pressKey} B</span> | |
| </Button> | |
| <Button | |
| variant={selectedTheme === "food" ? "default" : "outline"} | |
| className="w-full justify-between" | |
| onClick={() => setSelectedTheme("food")} | |
| > | |
| {t.themes.food} <span className="text-sm opacity-50">{t.themes.pressKey} C</span> | |
| </Button> | |
| <Button | |
| variant={selectedTheme === "custom" ? "default" : "outline"} | |
| className="w-full justify-between" | |
| onClick={() => setSelectedTheme("custom")} | |
| > | |
| {t.themes.custom} <span className="text-sm opacity-50">{t.themes.pressKey} D</span> | |
| </Button> | |
| {selectedTheme === "custom" && ( | |
| <motion.div | |
| initial={{ opacity: 0, height: 0 }} | |
| animate={{ opacity: 1, height: "auto" }} | |
| exit={{ opacity: 0, height: 0 }} | |
| transition={{ duration: 0.2 }} | |
| > | |
| <Input | |
| ref={inputRef} | |
| type="text" | |
| placeholder={t.themes.customPlaceholder} | |
| value={customTheme} | |
| onChange={(e) => setCustomTheme(e.target.value)} | |
| onKeyPress={handleInputKeyPress} | |
| className="w-full" | |
| /> | |
| </motion.div> | |
| )} | |
| </div> | |
| <Button | |
| onClick={handleSubmit} | |
| className="w-full" | |
| disabled={selectedTheme === "custom" && !customTheme.trim() || isGenerating} | |
| > | |
| {isGenerating ? t.themes.generating : `${t.themes.continue} ⏎`} | |
| </Button> | |
| </motion.div> | |
| ); | |
| }; |