fix: mobile terminal black screen - grid cell had 0 height
- Root cause: .mobile-terminal-wrapper used height: 100vh inside flex parent - Fix: Use flex: 1 instead so grid properly allocates 1fr height to content - Add .shell.mobile-terminal-shell CSS to ensure full viewport coverage - Remove debug logging
This commit is contained in:
@@ -74,7 +74,6 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
wsRef.current = ws;
|
wsRef.current = ws;
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
console.log("[Terminal] WebSocket connected");
|
|
||||||
setStatus("connected");
|
setStatus("connected");
|
||||||
setError(null);
|
setError(null);
|
||||||
reconnectAttemptsRef.current = 0;
|
reconnectAttemptsRef.current = 0;
|
||||||
@@ -107,16 +106,13 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
if (!termRef.current) return;
|
if (!termRef.current) return;
|
||||||
|
|
||||||
if (event.data instanceof Blob) {
|
if (event.data instanceof Blob) {
|
||||||
console.log("[Terminal] Received blob data:", event.data.size, "bytes");
|
|
||||||
event.data.arrayBuffer().then((buffer) => {
|
event.data.arrayBuffer().then((buffer) => {
|
||||||
const data = new Uint8Array(buffer);
|
const data = new Uint8Array(buffer);
|
||||||
console.log("[Terminal] Writing", data.length, "bytes to terminal");
|
|
||||||
termRef.current?.write(data);
|
termRef.current?.write(data);
|
||||||
});
|
});
|
||||||
} else if (typeof event.data === "string") {
|
} else if (typeof event.data === "string") {
|
||||||
try {
|
try {
|
||||||
const msg = JSON.parse(event.data);
|
const msg = JSON.parse(event.data);
|
||||||
console.log("[Terminal] Received JSON message:", msg);
|
|
||||||
if (msg.type === "status") {
|
if (msg.type === "status") {
|
||||||
if (msg.status === "connected") {
|
if (msg.status === "connected") {
|
||||||
setStatus("connected");
|
setStatus("connected");
|
||||||
@@ -188,12 +184,7 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
}, [instanceId]);
|
}, [instanceId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!terminalRef.current) {
|
if (!terminalRef.current) return;
|
||||||
console.error("[Terminal] terminalRef is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("[Terminal] Initializing terminal for instance", instanceId, "isMobile:", isMobile);
|
|
||||||
|
|
||||||
// Initialize terminal
|
// Initialize terminal
|
||||||
const currentFontSize = calculateFontSize();
|
const currentFontSize = calculateFontSize();
|
||||||
@@ -237,25 +228,18 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
|
|
||||||
// Define fitTerminal before connectWebSocket so it's available in onmessage
|
// Define fitTerminal before connectWebSocket so it's available in onmessage
|
||||||
const fitTerminal = () => {
|
const fitTerminal = () => {
|
||||||
if (!fitAddonRef.current || !termRef.current) {
|
if (!fitAddonRef.current || !termRef.current) return;
|
||||||
console.log("[Terminal] fitTerminal: missing refs");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Ensure terminal is opened and has valid dimensions
|
// Ensure terminal is opened and has valid dimensions
|
||||||
if (termRef.current.cols === 0 || termRef.current.rows === 0) {
|
if (termRef.current.cols === 0 || termRef.current.rows === 0) return;
|
||||||
console.log("[Terminal] fitTerminal: zero dimensions", termRef.current.cols, termRef.current.rows);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const oldCols = termRef.current.cols;
|
const oldCols = termRef.current.cols;
|
||||||
const oldRows = termRef.current.rows;
|
const oldRows = termRef.current.rows;
|
||||||
try {
|
try {
|
||||||
fitAddonRef.current.fit();
|
fitAddonRef.current.fit();
|
||||||
} catch (err) {
|
} catch {
|
||||||
console.error("[Terminal] fit error:", err);
|
// Ignore fit errors during initialization
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { cols, rows } = termRef.current;
|
const { cols, rows } = termRef.current;
|
||||||
console.log("[Terminal] fitTerminal:", oldCols, "x", oldRows, "->", cols, "x", rows);
|
|
||||||
// Force refresh if dimensions changed and are valid
|
// Force refresh if dimensions changed and are valid
|
||||||
if ((cols !== oldCols || rows !== oldRows) && cols > 0 && rows > 0) {
|
if ((cols !== oldCols || rows !== oldRows) && cols > 0 && rows > 0) {
|
||||||
try {
|
try {
|
||||||
@@ -271,24 +255,17 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Open xterm first (must happen before fit)
|
// Open xterm first (must happen before fit)
|
||||||
console.log("[Terminal] Opening xterm in container", container.clientWidth, "x", container.clientHeight);
|
|
||||||
term.open(container);
|
term.open(container);
|
||||||
ws = connectWebSocket();
|
ws = connectWebSocket();
|
||||||
|
|
||||||
// Initial fit after layout settles (terminal must be opened first)
|
// Initial fit after layout settles (terminal must be opened first)
|
||||||
const doInitialFit = () => {
|
const doInitialFit = () => {
|
||||||
if (!container.isConnected) {
|
if (!container.isConnected) return;
|
||||||
console.log("[Terminal] Container not connected yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Ensure container has dimensions before fitting
|
// Ensure container has dimensions before fitting
|
||||||
console.log("[Terminal] Container dimensions:", container.clientWidth, "x", container.clientHeight);
|
|
||||||
if (container.clientWidth > 0 && container.clientHeight > 0) {
|
if (container.clientWidth > 0 && container.clientHeight > 0) {
|
||||||
console.log("[Terminal] Calling initial fit");
|
|
||||||
fitTerminal();
|
fitTerminal();
|
||||||
} else {
|
} else {
|
||||||
// Container not ready yet, try again
|
// Container not ready yet, try again
|
||||||
console.log("[Terminal] Container has no dimensions, retrying...");
|
|
||||||
requestAnimationFrame(doInitialFit);
|
requestAnimationFrame(doInitialFit);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-5
@@ -3112,17 +3112,27 @@ a.nav-item,
|
|||||||
Mobile Terminal Styles
|
Mobile Terminal Styles
|
||||||
============================================ */
|
============================================ */
|
||||||
|
|
||||||
.mobile-terminal-wrapper {
|
/* Mobile terminal shell - fills viewport */
|
||||||
|
.shell.mobile-terminal-shell {
|
||||||
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shell.mobile-terminal-shell > * {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-terminal-wrapper {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr auto;
|
grid-template-rows: auto 1fr auto;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"header"
|
"header"
|
||||||
"content"
|
"content"
|
||||||
"keys";
|
"keys";
|
||||||
height: 100vh;
|
flex: 1;
|
||||||
height: 100dvh; /* Dynamic viewport height for mobile */
|
min-height: 0;
|
||||||
max-height: 100vh;
|
|
||||||
max-height: 100dvh;
|
|
||||||
background: #1e1e1e;
|
background: #1e1e1e;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user