diff --git a/apps/web/src/components/features/terminal/terminal.tsx b/apps/web/src/components/features/terminal/terminal.tsx index 6ffd0c5..f518fb7 100644 --- a/apps/web/src/components/features/terminal/terminal.tsx +++ b/apps/web/src/components/features/terminal/terminal.tsx @@ -387,11 +387,38 @@ export const TerminalComponent = React.forwardRef( scrollPending = 0; }; - const isAlternateScreen = () => { - const term = termRef.current; - if (!term) return false; - return term.buffer.active === term.buffer.alternate; - }; + const isAlternateScreen = () => { + const term = termRef.current; + if (!term) return false; + return term.buffer.active === term.buffer.alternate; + }; + + // Debug overlay for mobile scroll diagnostics + let debugOverlay: HTMLDivElement | null = null; + const showDebug = (msg: string) => { + if (!debugOverlay) { + debugOverlay = document.createElement("div"); + debugOverlay.style.position = "fixed"; + debugOverlay.style.bottom = "120px"; + debugOverlay.style.left = "8px"; + debugOverlay.style.right = "8px"; + debugOverlay.style.zIndex = "9999"; + debugOverlay.style.background = "rgba(0,0,0,0.8)"; + debugOverlay.style.color = "#0f0"; + debugOverlay.style.fontFamily = "monospace"; + debugOverlay.style.fontSize = "11px"; + debugOverlay.style.padding = "8px"; + debugOverlay.style.borderRadius = "6px"; + debugOverlay.style.pointerEvents = "none"; + debugOverlay.style.whiteSpace = "pre-wrap"; + debugOverlay.style.maxHeight = "120px"; + debugOverlay.style.overflow = "auto"; + document.body.appendChild(debugOverlay); + } + const line = `${new Date().toLocaleTimeString()} ${msg}`; + debugOverlay.textContent = + line + "\n" + debugOverlay.textContent?.split("\n").slice(0, 8).join("\n"); + }; const onTouchStart = (e: TouchEvent) => { if (e.touches.length === 1) { @@ -406,6 +433,10 @@ export const TerminalComponent = React.forwardRef( const touch = e.touches[0]; const deltaY = startY - touch.clientY; const deltaX = Math.abs(startX - touch.clientX); + const alternate = isAlternateScreen(); + showDebug( + `move dy=${deltaY.toFixed(0)} dx=${deltaX.toFixed(0)} alt=${alternate} scrolling=${isScrolling}`, + ); // Decide early whether this is a vertical scroll gesture. if (!isScrolling) { @@ -418,10 +449,11 @@ export const TerminalComponent = React.forwardRef( // Take over the gesture so the page/toolbar never scrolls. e.preventDefault(); - if (isAlternateScreen()) { + if (alternate) { // Alternate screen (tmux/vim): accumulate the swipe and // send SGR 1006 mouse-wheel events in steps. scrollPending += deltaY; + showDebug(`alt pending=${scrollPending.toFixed(0)}`); flushScroll(); } else if (termRef.current) { // Normal buffer: let xterm.js scroll its own viewport by @@ -431,6 +463,7 @@ export const TerminalComponent = React.forwardRef( ? (termRef.current.options.fontSize as number) * 1.2 : 10; const lines = Math.round(deltaY / lineHeight); + showDebug(`normal lines=${lines}`); if (lines !== 0) { termRef.current.scrollLines(lines); }