feat: mobile auto-hide header and tabs for multi-session terminal

- Add useAutoHide hook to TerminalPage for mobile header/tab strip
- Header and tabs auto-hide after 3s, tap to reveal
- Add CSS transitions for smooth show/hide on mobile
- Fullscreen mobile mode hides header and tabs completely
This commit is contained in:
2026-05-28 14:10:06 +02:00
parent 8e5e815ac9
commit 8eb851793d
2 changed files with 55 additions and 28 deletions
+36 -28
View File
@@ -6,6 +6,7 @@ import {
type TerminalSessionInfo,
} from "../components/terminal-session-tabs";
import { useMobileViewport } from "../hooks/use-mobile-viewport";
import { useAutoHide } from "../hooks/use-auto-hide";
import { useTerminalSessions } from "../hooks/use-terminal-sessions";
import type { TerminalSession } from "../api/terminal";
@@ -26,6 +27,7 @@ export const TerminalPage: React.FC = () => {
const isMobile = useMobileViewport();
const [isFullscreen, setIsFullscreen] = useState(false);
const terminalRefs = useRef<Record<string, React.RefObject<TerminalRef>>>({});
const headerAutoHide = useAutoHide({ timeout: 3000, enabled: isMobile });
const {
sessions,
@@ -193,34 +195,40 @@ export const TerminalPage: React.FC = () => {
<section
className={`terminal-page mobile ${isFullscreen ? "fullscreen" : ""}`}
>
{!isFullscreen && (
<div className="terminal-page-header mobile-header">
<button
className="secondary-button"
onClick={() => navigate(-1)}
type="button"
>
Back
</button>
<h1>Terminal</h1>
<button
className="secondary-button"
onClick={() => setIsFullscreen((p) => !p)}
type="button"
>
{isFullscreen ? "Exit" : "Fullscreen"}
</button>
</div>
)}
<TerminalSessionTabs
sessions={sessionInfos}
activeSessionId={activeSessionId ?? ""}
onSelect={handleSelect}
onClose={handleClose}
onCreate={handleCreate}
onRename={handleRename}
isMobile={true}
/>
<div
className={`terminal-page-header mobile-header ${headerAutoHide.isVisible ? "visible" : "hidden"}`}
onClick={() => headerAutoHide.show()}
>
<button
className="secondary-button"
onClick={() => navigate(-1)}
type="button"
>
Back
</button>
<h1>Terminal</h1>
<button
className="secondary-button"
onClick={() => setIsFullscreen((p) => !p)}
type="button"
>
{isFullscreen ? "Exit" : "Fullscreen"}
</button>
</div>
<div
className={`mobile-tabs-container ${headerAutoHide.isVisible ? "visible" : "hidden"}`}
onClick={() => headerAutoHide.show()}
>
<TerminalSessionTabs
sessions={sessionInfos}
activeSessionId={activeSessionId ?? ""}
onSelect={handleSelect}
onClose={handleClose}
onCreate={handleCreate}
onRename={handleRename}
isMobile={true}
/>
</div>
<div className="terminal-page-content">
{error && <div className="terminal-error-banner">{error}</div>}
{sessions.map((session) => (
+19
View File
@@ -2904,6 +2904,25 @@ a.nav-item,
opacity: 1;
}
/* Mobile auto-hide header and tabs */
.terminal-page.mobile .terminal-page-header,
.mobile-tabs-container {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.terminal-page.mobile .terminal-page-header.hidden,
.mobile-tabs-container.hidden {
transform: translateY(-100%);
opacity: 0;
pointer-events: none;
}
.terminal-page.mobile .terminal-page-header.visible,
.mobile-tabs-container.visible {
transform: translateY(0);
opacity: 1;
}
/* Mobile fullscreen */
@media (max-width: 767px) {
.terminal-page.fullscreen {