diff --git a/apps/web/src/pages/terminal.tsx b/apps/web/src/pages/terminal.tsx index 7e7b80b..ab0abdd 100644 --- a/apps/web/src/pages/terminal.tsx +++ b/apps/web/src/pages/terminal.tsx @@ -6,10 +6,14 @@ import { type TerminalSessionInfo, } from "../components/terminal-session-tabs"; import { Icon } from "../components/icon"; +import { SpecialKeysStrip } from "../components/special-keys-strip"; +import { SpecialKeysPanel } from "../components/special-keys-panel"; import { useMobileViewport } from "../hooks/use-mobile-viewport"; import { useAutoHide } from "../hooks/use-auto-hide"; +import { useVirtualKeyboard } from "../hooks/use-virtual-keyboard"; import { useTerminalSessions } from "../hooks/use-terminal-sessions"; import type { TerminalSession } from "../api/terminal"; +import type { ModifierKey } from "../hooks/use-special-keys"; const SESSIONS_TO_INFO = (sessions: TerminalSession[]): TerminalSessionInfo[] => sessions.map((s) => ({ @@ -40,7 +44,12 @@ export const TerminalPage: React.FC = () => { Record >({}); const changeFontSizeRef = useRef<((delta: number) => void) | null>(null); + const sendDataRef = useRef<((data: string) => void) | null>(null); + const focusInputRef = useRef<(() => void) | null>(null); const [showResetConfirm, setShowResetConfirm] = useState(false); + const [showSpecialKeysPanel, setShowSpecialKeysPanel] = useState(false); + const [activeModifier, setActiveModifier] = useState(null); + const { isOpen: isKeyboardOpen, height: keyboardHeight } = useVirtualKeyboard(); const { sessions, @@ -206,15 +215,17 @@ export const TerminalPage: React.FC = () => { const handleTerminalReady = useCallback( ( - _sendData: (data: string) => void, + sendData: (data: string) => void, status: TerminalStatus, - _focusInput: () => void, + focusInput: () => void, changeFontSize: (delta: number) => void, ) => { setTerminalStatuses((prev) => ({ ...prev, [activeSessionId ?? "default"]: status, })); + sendDataRef.current = sendData; + focusInputRef.current = focusInput; changeFontSizeRef.current = changeFontSize; }, [activeSessionId], @@ -224,6 +235,10 @@ export const TerminalPage: React.FC = () => { changeFontSizeRef.current?.(delta); }, []); + const handleSendKey = useCallback((data: string) => { + sendDataRef.current?.(data); + }, []); + const handleReset = useCallback(() => { if (activeSessionId && terminalRefs.current[activeSessionId]) { terminalRefs.current[activeSessionId].current?.reset(); @@ -318,6 +333,7 @@ export const TerminalPage: React.FC = () => { {/* Terminal content — always fills full viewport */}
headerAutoHide.toggle()} > {error &&
{error}
} @@ -332,6 +348,8 @@ export const TerminalPage: React.FC = () => { onClose={() => handleClose(session.id)} isMobile={true} showControls={false} + activeModifier={activeModifier} + onModifierChange={setActiveModifier} onTerminalReady={handleTerminalReady} />
@@ -342,6 +360,24 @@ export const TerminalPage: React.FC = () => { )} + + setShowSpecialKeysPanel(true)} + onKeepFocus={() => focusInputRef.current?.()} + activeModifier={activeModifier} + onModifierChange={setActiveModifier} + /> + + setShowSpecialKeysPanel(false)} + onKeepFocus={() => focusInputRef.current?.()} + activeModifier={activeModifier} + onModifierChange={setActiveModifier} + /> ); }