import { useState, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Terminal, X } from 'lucide-react'; import { useSettings } from '@/contexts/SettingsContext'; import { useAchievements } from '@/contexts/AchievementsContext'; const commands: Record = { '/home': '/', '/about': '/about', '/me': '/about', '/projects': '/projects', '/proj': '/projects', '/resources': '/resources', '/res': '/resources', '/links': '/links', '/faq': '/faq', '/games': '/games', '/arcade': '/games', '/tetris': '/games/tetris', '/pacman': '/games/pacman', '/snake': '/games/snake', '/breakout': '/games/breakout', '/music': '/music', '/m': '/music', '/ai': '/ai', '/chat': '/ai', '/achievements': '/achievements', '/ach': '/achievements', }; const helpText = `Available commands: /home - Navigate to Home /about, /me - Navigate to About Me /projects, /proj - Navigate to Projects /resources, /res - Navigate to Resources /links - Navigate to Links /faq - Navigate to FAQ /games, /arcade - Browse Arcade games /tetris - Play Tetris /pacman - Play Pac-Man /snake - Play Snake /breakout - Play Breakout /music, /m - Navigate to Music Player /ai, /chat - Navigate to AI Chat /help, /h - Show this help message /clear, /c - Clear terminal output ...there may be other commands.`; const TerminalCommand = () => { const [isOpen, setIsOpen] = useState(false); const [input, setInput] = useState(''); const [output, setOutput] = useState(['Type /help for available commands']); const inputRef = useRef(null); const outputRef = useRef(null); const navigate = useNavigate(); const { playSound } = useSettings(); const { unlockAchievement } = useAchievements(); useEffect(() => { if (isOpen && inputRef.current) { inputRef.current.focus(); } }, [isOpen]); useEffect(() => { if (outputRef.current) { outputRef.current.scrollTop = outputRef.current.scrollHeight; } }, [output]); // Keyboard shortcut to toggle terminal useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { // Don't trigger if already in an input field const isInputFocused = document.activeElement?.tagName === 'INPUT' || document.activeElement?.tagName === 'TEXTAREA'; if (e.key === '`' || (e.ctrlKey && e.key === '/')) { e.preventDefault(); setIsOpen(prev => !prev); playSound('beep'); } // Open terminal when pressing "/" (only if not in input) if (e.key === '/' && !isOpen && !isInputFocused) { e.preventDefault(); setIsOpen(true); playSound('beep'); // Pre-fill with "/" so user can continue typing command setTimeout(() => setInput('/'), 50); } if (e.key === 'Escape' && isOpen) { setIsOpen(false); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [isOpen, playSound]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const trimmedInput = input.trim().toLowerCase(); if (!trimmedInput) return; playSound('click'); setOutput(prev => [...prev, `> ${input}`]); // Unlock terminal user achievement unlockAchievement('terminal_user'); if (trimmedInput === '/help' || trimmedInput === '/h') { setOutput(prev => [...prev, helpText]); } else if (trimmedInput === '/hint') { unlockAchievement('hint_seeker'); setOutput(prev => [...prev, 'Hidden feature detected in system...', 'Hint: Old-school gamers know a certain cheat code.', 'Think NES, 1986, Contra... 30 lives anyone?', 'The sequence uses arrow keys and two letters.' ]); } else if (trimmedInput === '/clear' || trimmedInput === '/c') { setOutput(['Terminal cleared. Type /help for commands.']); } else if (commands[trimmedInput]) { setOutput(prev => [...prev, `Navigating to ${trimmedInput.slice(1)}...`]); playSound('beep'); setTimeout(() => { navigate(commands[trimmedInput]); setIsOpen(false); }, 300); } else { setOutput(prev => [...prev, `Command not found: ${trimmedInput}`, 'Type /help for available commands']); } setInput(''); }; return ( <> {/* Terminal Toggle Button - aligned with music player */} { setIsOpen(true); playSound('beep'); }} className="fixed bottom-4 right-4 z-[60] p-3 border-2 border-primary bg-background text-primary hover:bg-primary hover:text-background transition-all duration-300 box-glow" title="Open Terminal (` or Ctrl+/)" > {/* Terminal Window */} {isOpen && ( {/* Terminal Header */}
terminal@my-site.lol
{/* Terminal Output */}
{output.map((line, i) => (
{line}
))}
{/* Terminal Input */}
{'>'} setInput(e.target.value)} className="flex-1 bg-transparent border-none outline-none font-mono text-primary placeholder-primary/40" placeholder="Enter command..." autoComplete="off" spellCheck={false} /> _
)}
); }; export default TerminalCommand;