fix mobile terminal drawer sizing (#799)

This commit is contained in:
ekko
2026-05-16 21:01:00 +08:00
committed by GitHub
parent f7556e6204
commit 048a0ad87e
3 changed files with 144 additions and 7 deletions
@@ -86,9 +86,10 @@ function handleClose() {
.drawer-panel {
position: fixed;
top: 0;
right: -900px;
width: 900px;
height: 100vh;
right: min(-1180px, -88vw);
width: min(1180px, 88vw);
height: calc(100 * var(--vh));
max-height: calc(100 * var(--vh));
background: $bg-card;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
display: flex;
@@ -180,5 +181,3 @@ function handleClose() {
overflow: auto;
}
</style>
@@ -103,6 +103,9 @@ let activeFitAddon: FitAddon | null = null;
let resizeObserver: ResizeObserver | null = null;
let reconnectAttempts = 0;
const MAX_RECONNECT_ATTEMPTS = 3;
let touchScrollLastY: number | null = null;
let touchScrollRemainder = 0;
const TOUCH_SCROLL_LINE_PX = 18;
// ─── Computed ──────────────────────────────────────────────────
@@ -356,6 +359,35 @@ function sendResize() {
} catch {}
}
function handleTerminalTouchStart(event: TouchEvent) {
if (event.touches.length !== 1) {
touchScrollLastY = null;
touchScrollRemainder = 0;
return;
}
touchScrollLastY = event.touches[0].clientY;
touchScrollRemainder = 0;
}
function handleTerminalTouchMove(event: TouchEvent) {
if (!activeTerm || event.touches.length !== 1 || touchScrollLastY === null) return;
const nextY = event.touches[0].clientY;
touchScrollRemainder += touchScrollLastY - nextY;
touchScrollLastY = nextY;
const lines = Math.trunc(touchScrollRemainder / TOUCH_SCROLL_LINE_PX);
if (lines === 0) return;
activeTerm.scrollLines(lines);
touchScrollRemainder -= lines * TOUCH_SCROLL_LINE_PX;
event.preventDefault();
}
function handleTerminalTouchEnd() {
touchScrollLastY = null;
touchScrollRemainder = 0;
}
// ─── Theme ───────────────────────────────────────────────────────
function applyTheme(themeName: string) {
@@ -517,7 +549,15 @@ onUnmounted(() => {
</div>
</header>
<div class="terminal-container">
<div ref="terminalRef" class="terminal-xterm" :style="{ backgroundColor: terminalBg }" />
<div
ref="terminalRef"
class="terminal-xterm"
:style="{ backgroundColor: terminalBg }"
@touchstart="handleTerminalTouchStart"
@touchmove="handleTerminalTouchMove"
@touchend="handleTerminalTouchEnd"
@touchcancel="handleTerminalTouchEnd"
/>
</div>
</div>
</div>
@@ -798,4 +838,35 @@ onUnmounted(() => {
display: none !important;
}
}
@media (max-width: $breakpoint-mobile) {
.terminal-panel-drawer {
height: calc(100 * var(--vh));
max-height: calc(100 * var(--vh));
}
.terminal-main {
min-height: 0;
}
.terminal-container {
margin-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
}
.terminal-xterm {
:deep(.xterm-viewport),
:deep(.xterm-scrollable-element) {
touch-action: pan-y;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
scrollbar-width: thin !important;
}
:deep(.xterm-viewport::-webkit-scrollbar),
:deep(.xterm-scrollable-element::-webkit-scrollbar) {
display: block !important;
width: 6px !important;
}
}
}
</style>
@@ -245,6 +245,9 @@ let activeTerm: Terminal | null = null;
let activeFitAddon: FitAddon | null = null;
let resizeObserver: ResizeObserver | null = null;
let mobileQuery: MediaQueryList | null = null;
let touchScrollLastY: number | null = null;
let touchScrollRemainder = 0;
const TOUCH_SCROLL_LINE_PX = 18;
// ─── Computed ──────────────────────────────────────────────────
@@ -495,6 +498,35 @@ function sendResize() {
} catch {}
}
function handleTerminalTouchStart(event: TouchEvent) {
if (event.touches.length !== 1) {
touchScrollLastY = null;
touchScrollRemainder = 0;
return;
}
touchScrollLastY = event.touches[0].clientY;
touchScrollRemainder = 0;
}
function handleTerminalTouchMove(event: TouchEvent) {
if (!activeTerm || event.touches.length !== 1 || touchScrollLastY === null) return;
const nextY = event.touches[0].clientY;
touchScrollRemainder += touchScrollLastY - nextY;
touchScrollLastY = nextY;
const lines = Math.trunc(touchScrollRemainder / TOUCH_SCROLL_LINE_PX);
if (lines === 0) return;
activeTerm.scrollLines(lines);
touchScrollRemainder -= lines * TOUCH_SCROLL_LINE_PX;
event.preventDefault();
}
function handleTerminalTouchEnd() {
touchScrollLastY = null;
touchScrollRemainder = 0;
}
// ─── Theme ───────────────────────────────────────────────────────
function applyTheme(themeName: string) {
@@ -689,7 +721,15 @@ onUnmounted(() => {
</div>
</header>
<div class="terminal-container">
<div ref="terminalRef" class="terminal-xterm" :style="{ backgroundColor: terminalBg }" />
<div
ref="terminalRef"
class="terminal-xterm"
:style="{ backgroundColor: terminalBg }"
@touchstart="handleTerminalTouchStart"
@touchmove="handleTerminalTouchMove"
@touchend="handleTerminalTouchEnd"
@touchcancel="handleTerminalTouchEnd"
/>
</div>
</div>
</div>
@@ -980,6 +1020,19 @@ onUnmounted(() => {
// ─── Mobile ─────────────────────────────────────────────────────
@media (max-width: $breakpoint-mobile) {
.terminal-panel {
height: calc(100 * var(--vh));
max-height: calc(100 * var(--vh));
}
.terminal-main {
min-height: 0;
}
.terminal-container {
margin-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
}
.session-close-btn {
display: flex;
}
@@ -1011,6 +1064,20 @@ onUnmounted(() => {
left: 0;
right: 0;
bottom: 0;
:deep(.xterm-viewport),
:deep(.xterm-scrollable-element) {
touch-action: pan-y;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
scrollbar-width: thin !important;
}
:deep(.xterm-viewport::-webkit-scrollbar),
:deep(.xterm-scrollable-element::-webkit-scrollbar) {
display: block !important;
width: 6px !important;
}
}
}
</style>