From 3c3789575723b09be9232cbe898eae20b95ee7a6 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sat, 3 Oct 2026 01:36:18 +0800 Subject: [PATCH] fix(mobile): a pane on its way shows that it is coming Opening a pane over a slow link left an empty screen until its replay arrived. After a quarter second without it, three dots say it is coming. --- mobile/src/main.ts | 12 +++++++++++- mobile/src/style.css | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/mobile/src/main.ts b/mobile/src/main.ts index f5d21381..08718286 100644 --- a/mobile/src/main.ts +++ b/mobile/src/main.ts @@ -2737,13 +2737,21 @@ function terminalScreen(host: Host, place: Place, pane: PaneView, title: string, typing.setAttribute("autocorrect", "off"); typing.setAttribute("autocomplete", "off"); + // Until the pane's screen first arrives, a sign that it is on its way, + // not an empty pane; held back a moment so a quick link never flashes it. + const loading = h("div", { class: "term-loading", hidden: true }, h("span"), h("span"), h("span")); + const loadingSoon = window.setTimeout(() => (loading.hidden = false), 250); + const loaded = () => { + clearTimeout(loadingSoon); + loading.remove(); + }; // Back in the history, the way down to what is happening now is one tap. const latest = h("button", { class: "to-latest", ariaLabel: "Jump to the latest output", hidden: true }, ico("down")); const view = h( "div", { class: "screen term-screen" }, bar, - h("div", { class: "term-wrap" }, screenEl, typing, copyView, findBar, latest, banner), + h("div", { class: "term-wrap" }, screenEl, loading, typing, copyView, findBar, latest, banner), h("div", { class: "term-dock" }, h("div", { class: "key-slot" }, pages, answers, suggest), dots, chips, compose), ); @@ -2896,6 +2904,7 @@ function terminalScreen(host: Host, place: Place, pane: PaneView, title: string, // A pane its server no longer has — restarted since, and not started // again — is not coming back by retrying: said so, with a way on. const gone = () => { + loaded(); ended = true; live = false; retry.cancel(); @@ -3808,6 +3817,7 @@ function terminalScreen(host: Host, place: Place, pane: PaneView, title: string, const replay = () => { if (replayed) return; replayed = true; + loaded(); term.reset(); }; live = false; diff --git a/mobile/src/style.css b/mobile/src/style.css index 660d3a1c..2d130029 100644 --- a/mobile/src/style.css +++ b/mobile/src/style.css @@ -2705,3 +2705,47 @@ html[data-nav="pop"]::view-transition-new(root) { .row { -webkit-touch-callout: none; } + +/* Three dots while a pane's screen is on its way (main.ts `loading`). */ +.term-loading { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + pointer-events: none; +} + +.term-loading[hidden] { + display: none; +} + +.term-loading span { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--ink-3); + animation: loading-dot 1s ease-in-out infinite; +} + +.term-loading span:nth-child(2) { + animation-delay: 0.15s; +} + +.term-loading span:nth-child(3) { + animation-delay: 0.3s; +} + +@keyframes loading-dot { + 0%, + 80%, + 100% { + opacity: 0.3; + transform: scale(0.8); + } + 40% { + opacity: 1; + transform: none; + } +}