diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index 6c5ede1..63a5de5 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -21,7 +21,7 @@ interface TerminalProps { } const FONT_SIZE_KEY = "terminal-font-size"; -const MIN_FONT_SIZE = 16; +const MIN_FONT_SIZE = 10; const MAX_FONT_SIZE = 24; const RECONNECT_ATTEMPTS = 3; const RECONNECT_DELAY_BASE = 1000; @@ -163,11 +163,17 @@ export const TerminalComponent: React.FC = ({ term.loadAddon(new WebLinksAddon()); term.open(terminalRef.current); - fitAddon.fit(); // Connect WebSocket const ws = connectWebSocket(); + // Fit after layout settles - use rAF to ensure DOM is ready + requestAnimationFrame(() => { + requestAnimationFrame(() => { + fitAddon.fit(); + }); + }); + // Handle terminal input term.onData((data) => { if (ws.readyState !== WebSocket.OPEN) return; @@ -242,7 +248,8 @@ export const TerminalComponent: React.FC = ({ ws.close(); term.dispose(); }; - }, [instanceId, connectWebSocket, calculateFontSize]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [instanceId, connectWebSocket]); // Update parent about status changes useEffect(() => { @@ -266,9 +273,17 @@ export const TerminalComponent: React.FC = ({ const newSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, fontSize + delta)); setFontSize(newSize); localStorage.setItem(FONT_SIZE_KEY, newSize.toString()); - if (termRef.current) { + if (termRef.current && fitAddonRef.current) { termRef.current.options.fontSize = newSize; - fitAddonRef.current?.fit(); + requestAnimationFrame(() => { + if (termRef.current && fitAddonRef.current) { + try { + fitAddonRef.current.fit(); + } catch { + // Ignore fit errors during re-initialization + } + } + }); } }; @@ -345,26 +360,22 @@ export const TerminalComponent: React.FC = ({ )}
- {isMobile && ( - <> - - - - )} + + {onClose && (