feat(maestro): tighten mobile session UX
ci / rust (push) Failing after 1m42s

On phones (single tab, one pane at a time):
- drop the pane border/padding/focus-ring so the session fills the screen
- collapse the redundant tab bar; float a ☰ to keep the sidebar drawer reachable
- disable pull-to-refresh (overscroll-behavior) so terminal scroll wins

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-24 15:53:26 +00:00
co-authored by Claude Opus 4.8
parent 57d417f7a0
commit 9286eb09ba
2 changed files with 56 additions and 2 deletions
+15
View File
@@ -344,6 +344,9 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
renderTabs();
canvas.replaceChildren();
const tab = activeTab(layout);
// Mobile single-tab: the tab bar carries no information (one tab, one pane),
// so CSS collapses it and we float a ☰ instead (rendered in renderMobile).
el.classList.toggle("mv-mobile-solo", isMobile && layout.tabs.length === 1);
if (!tab.root) {
pool.setVisible([]);
@@ -380,6 +383,18 @@ export function createMultiView(opts: MultiViewOptions): MultiView {
const wrap = document.createElement("div");
wrap.className = "mv-mobile";
// With a single tab the tab bar (and its ☰) is hidden — float a ☰ so the
// sidebar drawer stays reachable.
if (layout.tabs.length === 1) {
const fab = document.createElement("button");
fab.type = "button";
fab.className = "mv-mobile-fab";
fab.title = "Sessions";
fab.textContent = "☰";
fab.addEventListener("click", () => opts.onToggleSidebar?.());
wrap.appendChild(fab);
}
if (ls.length > 1) {
const bar = document.createElement("div");
bar.className = "mv-panebar";
+41 -2
View File
@@ -183,6 +183,8 @@ html,
body {
height: 100%;
margin: 0;
/* No pull-to-refresh / scroll chaining — terminal scroll wins on touch. */
overscroll-behavior: none;
}
body {
@@ -1914,6 +1916,11 @@ textarea {
display: flex;
flex-direction: column;
}
/* Mobile, single tab: the tab bar is pure chrome — collapse it (a floating ☰
inside the pane keeps the sidebar drawer reachable). */
.mv-mobile-solo > .mv-tabs {
display: none;
}
/* tab bar */
.mv-tabs {
@@ -2233,14 +2240,46 @@ textarea {
.mv-mobile {
position: absolute;
inset: var(--sp-2);
/* Flush to the edges — a single full-screen pane needs no canvas inset. */
inset: 0;
display: flex;
flex-direction: column;
gap: var(--sp-2);
gap: 0;
}
/* One pane fills the screen: no border, radius, or focus ring to box it in. */
.mv-mobile > .mv-pane,
.mv-mobile > .mv-pane.is-focused {
border: none;
border-radius: 0;
box-shadow: none;
}
/* Floating ☰ that replaces the collapsed tab bar, tucked into the header bar. */
.mv-mobile-fab {
position: absolute;
top: 0;
left: 0;
z-index: var(--z-sticky);
display: inline-grid;
place-items: center;
width: 34px;
height: var(--bar-h);
border: none;
background: transparent;
color: var(--ink);
font-size: var(--fs-15);
cursor: pointer;
}
/* Make room for the ☰: shift the title (single pane) or pad the pill strip. */
.mv-mobile-fab + .mv-pane .attach-title {
margin-left: 30px;
}
.mv-mobile-fab + .mv-panebar {
padding-left: 38px;
}
.mv-panebar {
display: flex;
gap: 4px;
padding: var(--sp-1) var(--sp-2);
overflow-x: auto;
scrollbar-width: none;
flex: none;