From 9e88acaa36cbaf3fd3b5ab69663188fcbfe1c917 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 23:15:15 +0200 Subject: [PATCH 1/4] fix: remove 0-dimension check blocking terminal fit and add debug logging - Remove chicken-and-egg check that prevented fit() when cols/rows were 0 - Add console logging for container dimensions and fit results - Add retry limit (50 attempts) for initial fit to prevent infinite loops --- apps/web/src/components/terminal.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index 6403cc6..a8ca77c 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -229,8 +229,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 { @@ -240,8 +238,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 { @@ -249,7 +248,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 })); } }; @@ -259,14 +258,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); From 84b7b64ec0cdce6b5e12683fce948e3676221ac9 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 23:20:51 +0200 Subject: [PATCH 2/4] fix: change mobile terminal wrapper from grid to flexbox Grid layout was not properly sizing the content area, causing 0 height. Flexbox with flex: 1 on content area ensures proper filling. --- apps/web/src/styles.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index d0633fe..a912705 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; From fbd41e3eb49511b7525cfd1df216c42ee076f067 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 23:25:42 +0200 Subject: [PATCH 3/4] fix: mobile terminal container height - use flexbox throughout - Change .mobile-terminal-content to display: flex with flex-direction: column - Change .terminal-wrapper.mobile to use flex: 1 instead of position: absolute - Change .terminal-container to use flex: 1 instead of height: 100% - Ensures proper height calculation in flex layout chain --- apps/web/src/styles.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index a912705..7651e13 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -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; From 8fb4b6737285c3e4429958285251928aedc42f83 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 23:35:05 +0200 Subject: [PATCH 4/4] fix: enable terminal scrolling on mobile - Add overflow-y: auto and -webkit-overflow-scrolling: touch to xterm-viewport - Change touch-action from 'none' to 'pan-y' on mobile terminal wrapper and container - This allows vertical scrolling through terminal output history while preventing zoom --- apps/web/src/styles.css | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 7651e13..715251f 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -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; } }