feat(mobile): rework the sidebar picker, the view switch and the home for phones - #7019
Merged
Conversation
On mobile the sidebar is a Radix Sheet — a modal dialog — and its scroll lock (react-remove-scroll) calls preventDefault() on every wheel and touchmove that lands outside the dialog's own subtree. The picker's popover is portalled to the body, so it is outside: the list clipped at its max height and would not move under a finger. The repo already knew this failure mode for wheel (page-template-select.tsx patches it by hand). Making the popover modal gives it its own lock — only the innermost lock acts, and that one counts the list as scrollable — and it restores the menu semantics this control inherited from the dropdown it replaced. While in there: the Command's max-h-[min(560px,70dvh)] was dead, because CommandList's shared 300px default is smaller, so the picker was always ~373px tall whatever that number said. The list now takes the Command's budget, and the budget clamps to --radix-popover-content-available-height so a picker opened low on a short screen ends where the screen does. Verified against the real Sheet + PopoverContent + Command components in Chrome with a dispatched touch sequence over the list: touchmove is prevented before the change, allowed after, and still prevented once the list reaches its end, so nothing chains to the page behind. Layout at an 806px viewport: Command 560, input 40, strip 33, list 487 and scrollable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AVd1o11cJLXR7HPSTyuyBC
tlgimenes
force-pushed
the
claude/compressed-painting-koala
branch
from
September 4, 2026 19:36
8ada66b to
d726fb6
Compare
…e for two views Three things the mobile shell got wrong, reported from a phone. **Two selectors over one entity.** The sidebar sheet header carried an agent switcher beside the org/project picker. Agents and projects are both virtual MCPs, so those were the same things listed twice under two names. The agent switcher goes; the picker stays and is now the single selector there. That orphaned its whole browser — agents-section.tsx, the agent crumb, and read-cached-task-branch, ~1000 lines nothing else imported — so they go with it, along with the i18n keys only they read. **A popover hung off a control under your thumb.** The picker now opens as a bottom drawer on mobile and stays a popover on the desktop it was drawn for. That also settles the scroll bug from the branch below this one without the `modal` popover: portalled outside the sheet, the popover sat outside that dialog's scroll lock, which cancels every touchmove over it. A drawer is its own modal layer, so the list scrolls. Picking now closes the sheet too, or what you just chose stays hidden behind it. **Chat was a dead end.** On a route with no tabs of its own the view select listed `[Chat]` alone — "Main view" was a label it fell back to, never an option — so tapping Chat left no way back but the browser's back button. The options builder is now a pure function that synthesizes a main-surface row exactly when no tab already leads back, and it is unit-tested. Two surfaces render a toggle instead of a dropdown, per the ask: one tap and a label beats a menu that opens to offer one alternative. Three or more keep the select. Verified on the running app at 390x844 with touch emulation: the toggle round trips main -> chat -> main one tap each; the drawer opens from the bottom with search and both groups; a touchmove over its list is no longer cancelled (defaultPrevented false with the list scrollable). Desktop unchanged — popover, no drawer, Command capped at the 560px it always meant to be, body pointer-events back to `auto` now that it is non-modal again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AVd1o11cJLXR7HPSTyuyBC
It offers to install a CLI on the machine you are sitting at, which is not the phone you are holding — and it took the first screenful of the mobile home to propose it. `hidden md:inline-flex`, so the greeting is what you land on and the column's gap closes with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AVd1o11cJLXR7HPSTyuyBC
tlgimenes
force-pushed
the
claude/mobile-org-picker-drawer
branch
from
September 4, 2026 19:38
db0c3d0 to
73b7164
Compare
tlgimenes
changed the base branch from
claude/compressed-painting-koala
to
main
September 4, 2026 19:40
tlgimenes
enabled auto-merge (squash)
September 4, 2026 19:41
auto-merge was automatically disabled
September 4, 2026 19:42
Pull request was closed
tlgimenes
enabled auto-merge (squash)
September 4, 2026 19:43
decocms Bot
pushed a commit
that referenced
this pull request
Sep 4, 2026
PR: #7019 feat(mobile): rework the sidebar picker, the view switch and the home for phones Bump type: minor - decocms (apps/api/package.json): 4.331.2 -> 4.332.0 - @decocms/native (apps/native/package.json): 4.331.2 -> 4.332.0 Deploy-Scope: web
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported from a phone: the org/project menu would not scroll. Pulling on that turned up three more things the mobile shell got wrong, all fixed here.
1. The picker could not be scrolled by touch
On mobile the sidebar is a Radix
Sheet— a modal dialog — whose scroll lock (react-remove-scroll) callspreventDefault()on every wheel and touchmove landing outside the dialog's own DOM subtree. The picker's popover is portalled todocument.body, so it was outside: the list clipped at its max height and would not move under a finger. The repo already knew this failure mode for wheel and patched it by hand inpage-template-select.tsx.Also, the height cap above it was dead code —
Commanddeclaredmax-h-[min(560px,70dvh)], butCommandList's sharedmax-h-[300px]default is smaller, so the picker was always ~373px tall whatever that number said. The list now takes the Command's budget and clamps to--radix-popover-content-available-height, so a picker opened low on a short screen ends where the screen does.2. Two selectors over one entity
The sheet header carried an agent switcher beside the org/project picker. Agents and projects are both virtual MCPs, so those were the same things listed twice under two names — which is what made the header read as two competing scopes.
The agent switcher goes; the picker is the single selector there. Nothing else in the app opened the agent browser, so this orphaned
agents-section.tsx, the agent crumb inshell-breadcrumb.tsx, andread-cached-task-branch.ts— ~1000 lines knip confirms nothing imports. They go here, with the i18n keys only they read. Desktop is unaffected: it never had an agent crumb.3. A popover hung off a control under your thumb
The picker now opens as a bottom drawer on mobile and stays a popover on the desktop it was drawn for — the drawer presentation borrowed from the agent picker it replaces. That also settles (1) on mobile without a modal popover: a drawer is its own modal layer, so the list scrolls. Picking now closes the sheet too; before, whatever you chose stayed hidden behind it.
4. Chat was a dead end
On a route with no tabs of its own (the org home — the first one people meet) the view select listed
["Chat"]alone. "Main view" was a label it fell back to, never an option, so tapping Chat left no way back but the browser's back button. Confirmed live before the fix: the open dropdown read["Chat", "Chat"](hidden sentinel + the one option).buildMobileViewOptionsis now a pure, unit-tested function that synthesizes a main-surface row exactly when no tab already leads back — where the route declares tabs, opening one already opens the main panel, so a second entry would only duplicate the first.And two surfaces render a toggle button, not a dropdown: one tap and a label beats a menu that opens to offer a single alternative. Three or more keep the select, because past two there is no single "the other one". The button names where it takes you (
Chat/Main view,aria-label="Switch to …").5. The connect pill is desktop-only now
It offers to install a CLI on the machine you are sitting at, which is not the phone you are holding — and it took the first screenful of the mobile home to propose it.
hidden md:inline-flex, so the column's gap closes with it and the greeting is what you land on.Testing
Driven on the running app with device emulation.
Touch-scroll, probed with a real dispatched touch sequence over the list:
touchmoveprevented?modalAt 390×844 with touch: the toggle round trips main → chat → main one tap each, label and
aria-labelflipping with it; the drawer opens from the bottom (data-vaul-drawer-direction="bottom") with search and both groups; sheet header controls are now exactly["Organization and project: …", "Close sidebar", …nav]; the connect pill computesdisplay: none.At 1280×800: popover (no drawer), Command computed
max-height: 560px,body { pointer-events: auto }confirming it is non-modal — no scrollbar-gap shift, and the org shell ish-dvh overflow-hiddenso the body never scrolls anyway.bun run fmt,bun run lint(0 errors),bun run checkacross every workspace,knip(clean), and 317 unit tests in the touched trees pass.Note for whoever runs the suite:
bun test apps/web/srcas one process reports 111 failures — identical onmainat this commit, none introduced here. They are DOM-global collisions between suites batched into one bun process (SSR /window.opener/localStorage), worth a separate look.Follow-ups (not here)
account-popover.tsx) and the inbox popover (sidebar/footer/inbox.tsx) sit in the same mobile sheet and carry the same latent scroll-lock bug — the inbox one has a real scrolling list.dvhtracks the layout viewport, not the visual one), so a tall surface can still extend under the keyboard. A real fix is a separatevisualViewportjob.🤖 Generated with Claude Code
https://claude.ai/code/session_01AVd1o11cJLXR7HPSTyuyBC