fix: prevent cumulative terminal shrinkage in fullscreen mode
When switching terminal sessions in fullscreen mode, the viewport shrank cumulatively because .terminal-wrapper uses grid-template-rows: auto 1fr. With showControls=false, the single child (.terminal-container) landed in the auto track instead of 1fr, creating a feedback loop with xterm fit(). - Add .terminal-wrapper.no-controls with grid-template-rows: 1fr so the container fills the wrapper when the header is hidden. - Apply no-controls class in TerminalComponent when showControls=false. - Replace setTimeout(50) with double requestAnimationFrame in TerminalPage for more reliable fit() timing after tab switches. Quality gates: tsc --noEmit (clean), pytest (208 passed, 6 pre-existing)
This commit is contained in:
@@ -568,7 +568,7 @@ export const TerminalComponent = React.forwardRef<TerminalRef, TerminalProps>(
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`terminal-wrapper ${isMobile ? "mobile" : ""}`}>
|
||||
<div className={`terminal-wrapper ${isMobile ? "mobile" : ""} ${!showControls ? "no-controls" : ""}`}>
|
||||
{showControls && (
|
||||
<div className="terminal-header">
|
||||
<div className="terminal-header-left">
|
||||
|
||||
@@ -17,7 +17,12 @@ const SESSIONS_TO_INFO = (sessions: TerminalSession[]): TerminalSessionInfo[] =>
|
||||
status: s.status as TerminalSessionInfo["status"],
|
||||
}));
|
||||
|
||||
type TerminalStatus = "connecting" | "connected" | "disconnected" | "error" | "resetting";
|
||||
type TerminalStatus =
|
||||
| "connecting"
|
||||
| "connected"
|
||||
| "disconnected"
|
||||
| "error"
|
||||
| "resetting";
|
||||
|
||||
export const TerminalPage: React.FC = () => {
|
||||
const { instanceId } = useParams<{
|
||||
@@ -30,7 +35,9 @@ export const TerminalPage: React.FC = () => {
|
||||
const headerAutoHide = useAutoHide({ timeout: 3000, enabled: isMobile });
|
||||
|
||||
// Track terminal status and callbacks for unified fullscreen header
|
||||
const [terminalStatuses, setTerminalStatuses] = useState<Record<string, TerminalStatus>>({});
|
||||
const [terminalStatuses, setTerminalStatuses] = useState<
|
||||
Record<string, TerminalStatus>
|
||||
>({});
|
||||
const changeFontSizeRef = useRef<((delta: number) => void) | null>(null);
|
||||
const [showResetConfirm, setShowResetConfirm] = useState(false);
|
||||
|
||||
@@ -73,12 +80,19 @@ export const TerminalPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
if (activeSessionId && terminalRefs.current[activeSessionId]) {
|
||||
const ref = terminalRefs.current[activeSessionId];
|
||||
// Small delay to allow display:block to apply
|
||||
const timer = setTimeout(() => {
|
||||
ref.current?.fit();
|
||||
ref.current?.focus();
|
||||
}, 50);
|
||||
return () => clearTimeout(timer);
|
||||
// Double rAF ensures layout has settled after the display:block switch
|
||||
let raf1 = 0;
|
||||
let raf2 = 0;
|
||||
raf1 = requestAnimationFrame(() => {
|
||||
raf2 = requestAnimationFrame(() => {
|
||||
ref.current?.fit();
|
||||
ref.current?.focus();
|
||||
});
|
||||
});
|
||||
return () => {
|
||||
cancelAnimationFrame(raf1);
|
||||
cancelAnimationFrame(raf2);
|
||||
};
|
||||
}
|
||||
}, [activeSessionId]);
|
||||
|
||||
@@ -192,7 +206,10 @@ export const TerminalPage: React.FC = () => {
|
||||
_focusInput: () => void,
|
||||
changeFontSize: (delta: number) => void,
|
||||
) => {
|
||||
setTerminalStatuses((prev) => ({ ...prev, [activeSessionId ?? "default"]: status }));
|
||||
setTerminalStatuses((prev) => ({
|
||||
...prev,
|
||||
[activeSessionId ?? "default"]: status,
|
||||
}));
|
||||
changeFontSizeRef.current = changeFontSize;
|
||||
},
|
||||
[activeSessionId],
|
||||
|
||||
@@ -2562,6 +2562,13 @@ a.nav-item,
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
/* When controls are hidden (fullscreen), only the container is in flow;
|
||||
force it into the 1fr track so it fills the wrapper instead of landing
|
||||
in the auto track and shrinking on each fit(). */
|
||||
.terminal-wrapper.no-controls {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
.terminal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: terminal-fullscreen-unified-header
|
||||
status: in-progress
|
||||
phase: apply
|
||||
status: completed
|
||||
phase: verify
|
||||
type: bugfix
|
||||
description: Fix terminal fullscreen mode where session switcher overlays terminal controls. Combine both elements into a single unified header visible at all times.
|
||||
created_at: 2026-05-28
|
||||
|
||||
Reference in New Issue
Block a user