diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index 1d1f714..53cf2c7 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -246,8 +246,6 @@ export const TerminalComponent: React.FC = ({ // Define fitTerminal before connectWebSocket so it's available in onmessage const fitTerminal = () => { if (!fitAddonRef.current || !termRef.current) return; - // Ensure terminal is opened and has valid dimensions - if (termRef.current.cols === 0 || termRef.current.rows === 0) return; const oldCols = termRef.current.cols; const oldRows = termRef.current.rows; try { @@ -257,8 +255,9 @@ export const TerminalComponent: React.FC = ({ return; } const { cols, rows } = termRef.current; - // Force refresh if dimensions changed and are valid - if ((cols !== oldCols || rows !== oldRows) && cols > 0 && rows > 0) { + console.log(`[Terminal] fit() result: ${cols}x${rows} (was ${oldCols}x${oldRows})`); + // Force refresh if dimensions are valid + if (cols > 0 && rows > 0) { try { termRef.current.refresh(0, rows - 1); } catch { @@ -266,7 +265,7 @@ export const TerminalComponent: React.FC = ({ } } const currentWs = wsRef.current; - if (currentWs?.readyState === WebSocket.OPEN) { + if (currentWs?.readyState === WebSocket.OPEN && cols > 0 && rows > 0) { currentWs.send(JSON.stringify({ type: "resize", cols, rows })); } }; @@ -276,14 +275,20 @@ export const TerminalComponent: React.FC = ({ ws = connectWebSocket(); // Initial fit after layout settles (terminal must be opened first) + let fitAttempts = 0; const doInitialFit = () => { if (!container.isConnected) return; + fitAttempts++; // Ensure container has dimensions before fitting if (container.clientWidth > 0 && container.clientHeight > 0) { + console.log(`[Terminal] Container ready: ${container.clientWidth}x${container.clientHeight} (attempt ${fitAttempts})`); fitTerminal(); - } else { - // Container not ready yet, try again + } else if (fitAttempts < 50) { + // Container not ready yet, try again (max 50 attempts ~ 1s) + console.log(`[Terminal] Container not ready: ${container.clientWidth}x${container.clientHeight} (attempt ${fitAttempts})`); requestAnimationFrame(doInitialFit); + } else { + console.warn(`[Terminal] Container never got dimensions after ${fitAttempts} attempts`); } }; requestAnimationFrame(doInitialFit); diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index d0633fe..715251f 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -3122,8 +3122,8 @@ a.nav-item, } .mobile-terminal-wrapper { - display: grid; - grid-template-rows: auto 1fr auto; + display: flex; + flex-direction: column; height: 100%; min-height: 0; background: #1e1e1e; @@ -3239,26 +3239,26 @@ a.nav-item, overflow: hidden; position: relative; background: #1e1e1e; + display: flex; + flex-direction: column; } /* Terminal wrapper - fills content area */ .terminal-wrapper.mobile { border: none; border-radius: 0; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + flex: 1; + min-height: 0; width: 100%; - height: 100%; overflow: hidden; + display: flex; + flex-direction: column; } .terminal-wrapper.mobile .terminal-container { width: 100%; - height: 100%; - max-height: 100%; + flex: 1; + min-height: 0; padding: 0; overflow: hidden; position: relative; @@ -3270,6 +3270,13 @@ a.nav-item, height: 100%; } +/* Enable scrolling in mobile terminal */ +.terminal-wrapper.mobile .terminal-container .xterm-viewport { + overflow-y: auto !important; + -webkit-overflow-scrolling: touch !important; + height: 100% !important; +} + /* Special Keys Strip */ .special-keys-strip { flex-shrink: 0; @@ -3499,16 +3506,17 @@ a.nav-item, /* Disable zoom on mobile terminal */ @media (max-width: 767px) { .mobile-terminal-wrapper { - touch-action: none; + touch-action: pan-y; -webkit-text-size-adjust: none; } - .mobile-terminal-wrapper * { + .mobile-terminal-wrapper button, + .mobile-terminal-wrapper .special-key-button { touch-action: manipulation; } .terminal-container { - touch-action: none; + touch-action: pan-y; padding: 0; } }