import { type MutableRefObject, useState, useCallback, useEffect, useRef } from 'react'; import { ChevronLeft, ChevronRight, Keyboard, ArrowDownToLine, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { Terminal } from '@xterm/xterm'; import { sendSocketMessage } from '../../utils/socket'; const SHORTCUTS = [ { id: 'escape', labelKey: 'escape', sequence: '\x1b', hint: 'Esc' }, { id: 'tab', labelKey: 'tab', sequence: '\t', hint: 'Tab' }, { id: 'shift-tab', labelKey: 'shiftTab', sequence: '\x1b[Z', hint: '\u21e7Tab' }, { id: 'arrow-up', labelKey: 'arrowUp', sequence: '\x1b[A', hint: '\u2191' }, { id: 'arrow-down', labelKey: 'arrowDown', sequence: '\x1b[B', hint: '\u2193' }, ] as const; type TerminalShortcutsPanelProps = { wsRef: MutableRefObject; terminalRef: MutableRefObject; isConnected: boolean; }; const preventFocusSteal = (e: React.PointerEvent) => e.preventDefault(); export default function TerminalShortcutsPanel({ wsRef, terminalRef, isConnected, }: TerminalShortcutsPanelProps) { const { t } = useTranslation('settings'); const [isOpen, setIsOpen] = useState(false); const closeTimeoutRef = useRef | null>(null); useEffect(() => { return () => { if (closeTimeoutRef.current) { clearTimeout(closeTimeoutRef.current); } }; }, []); const handleToggle = useCallback(() => { setIsOpen((prev) => !prev); }, []); const handleShortcutAction = useCallback((action: () => void) => { action(); if (document.activeElement instanceof HTMLElement) { document.activeElement.blur(); } if (closeTimeoutRef.current) { clearTimeout(closeTimeoutRef.current); } closeTimeoutRef.current = setTimeout(() => setIsOpen(false), 50); }, []); const sendInput = useCallback( (data: string) => { sendSocketMessage(wsRef.current, { type: 'input', data }); }, [wsRef], ); const scrollToBottom = useCallback(() => { terminalRef.current?.scrollToBottom(); }, [terminalRef]); return ( <> {/* Pull Tab */} {/* Panel */}
{/* Header */}

{t('terminalShortcuts.title')}

{/* Content — conditionally rendered so buttons remount with clean CSS states */} {isOpen && (
{/* Shortcut Keys */}

{t('terminalShortcuts.sectionKeys')}

{SHORTCUTS.map((shortcut) => ( ))}
{/* Navigation */}

{t('terminalShortcuts.sectionNavigation')}

)}
{/* Backdrop */} {isOpen && (
)} ); }