Mobile / phone experience pass for the web UI #389

Open
opened 2026-09-01 19:42:09 +00:00 by Cordy · 2 comments
Owner

Split out of the #315 owner-column round (2026-09-01) at Nikola's request — deliberately its own issue so a phone pass cannot accidentally break the settled desktop UI.

What already exists

The UI is not unresponsive today: the file list is a CSS container (container-name:list) with breakpoints at 820px (drop Modified), 560px (drop Size + Owner) and 400px; the sidebar collapses to icons at 700px and disappears into a single-column layout at 820px; several admin surfaces have their own 640–860px media rules; the brand tag hides at 900px. So a phone renders something usable — but nobody has actually designed for it.

Scope of the pass

  • Walk every surface at ~375–430px (files, preview, dialogs, spaces, sharing, transfers, trash, admin) and fix what's cramped, clipped, or unreachable rather than merely stacked.
  • Touch targets: row actions, kebabs and inline confirms are sized for a pointer (30×28 kebabs, 13.5px links); decide minimum hit sizes for touch.
  • Dialogs: several use fixed min/max widths (min(600px, 92vw) is fine; audit the rest) and long forms (share, members, retention picker) need a scroll/keyboard story.
  • The top bar (search, bell, avatar) and breadcrumbs at narrow widths.
  • Admin on a phone: probably read-mostly — decide what is honestly out of scope and state it, rather than half-supporting everything.
  • No separate mobile markup: extend the existing container-query/media approach; the desktop UI must be pixel-unchanged above the breakpoints.

Definition of done

A phone user can browse, preview, upload, share, restore from trash and read notifications comfortably; anything deliberately desktop-only (e.g. deep admin) degrades to a readable, honest layout instead of a broken one; the desktop UI is untouched at ≥820px.

Split out of the #315 owner-column round (2026-09-01) at Nikola's request — deliberately its own issue so a phone pass cannot accidentally break the settled desktop UI. ## What already exists The UI is not unresponsive today: the file list is a CSS container (`container-name:list`) with breakpoints at 820px (drop Modified), 560px (drop Size + Owner) and 400px; the sidebar collapses to icons at 700px and disappears into a single-column layout at 820px; several admin surfaces have their own 640–860px media rules; the brand tag hides at 900px. So a phone renders something usable — but nobody has actually *designed* for it. ## Scope of the pass - Walk every surface at ~375–430px (files, preview, dialogs, spaces, sharing, transfers, trash, admin) and fix what's cramped, clipped, or unreachable rather than merely stacked. - Touch targets: row actions, kebabs and inline confirms are sized for a pointer (30×28 kebabs, 13.5px links); decide minimum hit sizes for touch. - Dialogs: several use fixed min/max widths (`min(600px, 92vw)` is fine; audit the rest) and long forms (share, members, retention picker) need a scroll/keyboard story. - The top bar (search, bell, avatar) and breadcrumbs at narrow widths. - Admin on a phone: probably read-mostly — decide what is honestly out of scope and state it, rather than half-supporting everything. - No separate mobile markup: extend the existing container-query/media approach; the desktop UI must be pixel-unchanged above the breakpoints. ## Definition of done A phone user can browse, preview, upload, share, restore from trash and read notifications comfortably; anything deliberately desktop-only (e.g. deep admin) degrades to a readable, honest layout instead of a broken one; the desktop UI is untouched at ≥820px.
Author
Owner

Recon + plan (2026-09-13). Mockup rev 1 delivered to Nikola (mobile-389-mockup.html, 9 variants, every surface at 390px). Note the surface list has grown since this issue was written: the pass now also covers the #484–509 toolbar/tiles/selection/pagination work and the #486 New menu + editor page.

The headline finding: at ≤820px the sidebar is display:none with no replacement (@media(max-width:820px){#app{grid-template-columns:1fr} #app > aside{display:none}}). A phone user cannot reach Recents, Favourites, Spaces, Shares, Transfers, Trash or Admin at all. Everything else is degradation; this is absence.

Full defect inventory from the recon

  • Touch targets: row actions 28×28, gear 34×34, checkboxes ~20px, tab/menu rows unpadded — all under any touch minimum.
  • Popover menus: rowmenu has no width bound (long de/fr labels can exceed 390px); bell/avatar menus are 278px right-anchored popovers; sort menu 230px. All clip or crowd at phone width.
  • Preview panel: side-panel maths go negative below ~700px (LIST_MIN 360 + PV_MIN 280 > viewport); the divider is already hidden at 700px but the panel itself has no phone story.
  • 100vh in five places (app shell, aside, pvpanel, divider) — iOS URL-bar collapse territory; zero safe-area-inset usage anywhere.
  • Toolbar (Upload/New/sort/view/gear) and the selection bar overflow the fixed 48px slot from v0.6.177 at 390px.
  • Dialogs: widths are fine (min(30rem, 92vw) base) but there is no max-height/scroll/keyboard story, and sub-16px inputs trigger iOS focus zoom.
  • What already helps: viewport meta present; container queries drop Modified/Size/Owner at 820/560; chips go glyph-only at 400; permanent row actions (#509) mean no hover-only affordances; admin kvboxes already stack at 640.

Decisions taken (Nikola, 2026-09-13)

  1. Navigation below 820px: bottom tab bar — Personal, Recents, Favourites, Spaces, More; the More sheet carries Shares/Transfers/Federated/Deleted files/Administration with existing visibility rules, counts and dots. Applies to the 481–819px tablet band too (reachability fix), with phone-only styling at ≤480px.
  2. Rows: star + kebab only, 44px targets; the kebab opens a bottom sheet with the full menu inventory in today's order. Selection mode: count header replaces the toolbar in place; a bottom action bar (Download/Copy to/Move to/Favourite/Delete) replaces the tab bar.
  3. Admin: functional with three exceptions — every topic stacks and stays fully usable; audit Trace, key rotation/drain, and the peering key exchange show an honest "best done on a desktop" card while remaining readable. Admin becomes a drill-in topic list on phones; #admin/<topic> deep links keep working.

Other design calls in the mockup (rev 1)

  • Preview on phone = full-screen takeover of the existing #pvpanel (fixed inset:0, 100dvh), Edit/star/close in the header, Download/Open in a bottom bar, browser-back closes (editor-page pushState pattern), sibling navigation gains swipe.
  • All .menu/.fbpop popovers become bottom sheets at ≤480px via ONE shared mechanism, not per-menu forks.
  • Dialogs become bottom-anchored cards: max-height 90dvh, scrolling body, pinned action row, 16px inputs, safe-area clearance. Folder picker becomes a full-height sheet.
  • Tiles: fixed 2-column at phone width; tile-size option hides there.
  • Search: topbar magnifier expands to a full-width row with Cancel; brand collapses to the mark.
  • Second line on rows becomes the subtitle (size · date, or path in search/recents) — the data the container queries currently just drop.

The contract

  • ≥820px: byte-identical desktop UI (hard invariant; verified by desktop screenshot diff each wave).
  • New tiers: ≤819px gets the tab bar; ≤480px gets the full phone treatment.
  • Touch spec: 44×44 min hit, 52px rows, 46px menu rows, 16px inputs.
  • 100vh→100dvh everywhere full-height; env(safe-area-inset-*) on all bottom-fixed chrome; body scroll locked under sheets.
  • Deliberately desktop-only (degrade readable, never broken): drag-and-drop move, preview resize divider, the three admin ceremonies, density setting.
  • Named out of scope: long-press selection (v2), PWA/offline, pull-to-refresh.

Pitfalls carried into the build

  • The 48px fixed toolbar/selbar slot must become height-flexible only below 820px, or the v0.6.177 no-jump guarantee breaks on desktop.
  • #fileactions-scoped ID-specificity CSS (the #485 lesson) applies to every toolbar override; sheet CSS must not leak into .menu desktop styling — the sheet mode is a body-class gate, not a .menu rewrite.
  • The tab bar and admin drill-in touch setView/openAdmin routing — the highest-regression-risk JS in the pass; each wave ships alone and gets the desktop diff.
  • i18n ×4 for all new labels (More, Cancel, the desktop-card copy); German lengths sized-for in the sheets.

Build order (each wave its own release, dogfood-verified at 390×844 + desktop-diffed): A shell (tab bar, More/bell/avatar sheets, search row, dvh/safe-area plumbing) → B list & actions (row recipe, kebab/New/sort/gear sheets, selection action bar, tiles) → C layers (preview takeover, dialog cards, folder picker) → D admin drill-in + desktop cards + editor bar. Build starts on mockup approval.

Recon + plan (2026-09-13). Mockup rev 1 delivered to Nikola (`mobile-389-mockup.html`, 9 variants, every surface at 390px). Note the surface list has grown since this issue was written: the pass now also covers the #484–509 toolbar/tiles/selection/pagination work and the #486 New menu + editor page. **The headline finding**: at ≤820px the sidebar is `display:none` with **no replacement** (`@media(max-width:820px){#app{grid-template-columns:1fr} #app > aside{display:none}}`). A phone user cannot reach Recents, Favourites, Spaces, Shares, Transfers, Trash or Admin at all. Everything else is degradation; this is absence. **Full defect inventory from the recon** - Touch targets: row actions 28×28, gear 34×34, checkboxes ~20px, tab/menu rows unpadded — all under any touch minimum. - Popover menus: rowmenu has no width bound (long de/fr labels can exceed 390px); bell/avatar menus are 278px right-anchored popovers; sort menu 230px. All clip or crowd at phone width. - Preview panel: side-panel maths go negative below ~700px (LIST_MIN 360 + PV_MIN 280 > viewport); the divider is already hidden at 700px but the panel itself has no phone story. - `100vh` in five places (app shell, aside, pvpanel, divider) — iOS URL-bar collapse territory; zero `safe-area-inset` usage anywhere. - Toolbar (Upload/New/sort/view/gear) and the selection bar overflow the fixed 48px slot from v0.6.177 at 390px. - Dialogs: widths are fine (`min(30rem, 92vw)` base) but there is no max-height/scroll/keyboard story, and sub-16px inputs trigger iOS focus zoom. - What already helps: viewport meta present; container queries drop Modified/Size/Owner at 820/560; chips go glyph-only at 400; permanent row actions (#509) mean no hover-only affordances; admin kvboxes already stack at 640. **Decisions taken (Nikola, 2026-09-13)** 1. **Navigation below 820px: bottom tab bar** — Personal, Recents, Favourites, Spaces, More; the More sheet carries Shares/Transfers/Federated/Deleted files/Administration with existing visibility rules, counts and dots. Applies to the 481–819px tablet band too (reachability fix), with phone-only styling at ≤480px. 2. **Rows: star + kebab only**, 44px targets; the kebab opens a bottom sheet with the full menu inventory in today's order. Selection mode: count header replaces the toolbar in place; a bottom action bar (Download/Copy to/Move to/Favourite/Delete) replaces the tab bar. 3. **Admin: functional with three exceptions** — every topic stacks and stays fully usable; audit Trace, key rotation/drain, and the peering key exchange show an honest "best done on a desktop" card while remaining readable. Admin becomes a drill-in topic list on phones; `#admin/<topic>` deep links keep working. **Other design calls in the mockup (rev 1)** - Preview on phone = full-screen takeover of the existing #pvpanel (fixed inset:0, 100dvh), Edit/star/close in the header, Download/Open in a bottom bar, browser-back closes (editor-page pushState pattern), sibling navigation gains swipe. - All `.menu`/`.fbpop` popovers become bottom sheets at ≤480px via ONE shared mechanism, not per-menu forks. - Dialogs become bottom-anchored cards: max-height 90dvh, scrolling body, pinned action row, 16px inputs, safe-area clearance. Folder picker becomes a full-height sheet. - Tiles: fixed 2-column at phone width; tile-size option hides there. - Search: topbar magnifier expands to a full-width row with Cancel; brand collapses to the mark. - Second line on rows becomes the subtitle (size · date, or path in search/recents) — the data the container queries currently just drop. **The contract** - ≥820px: byte-identical desktop UI (hard invariant; verified by desktop screenshot diff each wave). - New tiers: ≤819px gets the tab bar; ≤480px gets the full phone treatment. - Touch spec: 44×44 min hit, 52px rows, 46px menu rows, 16px inputs. - 100vh→100dvh everywhere full-height; env(safe-area-inset-*) on all bottom-fixed chrome; body scroll locked under sheets. - Deliberately desktop-only (degrade readable, never broken): drag-and-drop move, preview resize divider, the three admin ceremonies, density setting. - Named out of scope: long-press selection (v2), PWA/offline, pull-to-refresh. **Pitfalls carried into the build** - The 48px fixed toolbar/selbar slot must become height-flexible only below 820px, or the v0.6.177 no-jump guarantee breaks on desktop. - `#fileactions`-scoped ID-specificity CSS (the #485 lesson) applies to every toolbar override; sheet CSS must not leak into `.menu` desktop styling — the sheet mode is a body-class gate, not a `.menu` rewrite. - The tab bar and admin drill-in touch `setView`/`openAdmin` routing — the highest-regression-risk JS in the pass; each wave ships alone and gets the desktop diff. - i18n ×4 for all new labels (More, Cancel, the desktop-card copy); German lengths sized-for in the sheets. **Build order** (each wave its own release, dogfood-verified at 390×844 + desktop-diffed): A shell (tab bar, More/bell/avatar sheets, search row, dvh/safe-area plumbing) → B list & actions (row recipe, kebab/New/sort/gear sheets, selection action bar, tiles) → C layers (preview takeover, dialog cards, folder picker) → D admin drill-in + desktop cards + editor bar. Build starts on mockup approval.
Author
Owner

Mobile pass shipped — v0.6.180 → v0.6.183, all four waves live on both dogfoods

Implemented exactly per the approved mockup and the three recorded decisions (bottom tab bar; star + kebab rows with bottom-sheet menus; functional admin with 3 desktop-only ceremonies).

Wave A — shell (v0.6.180, PR #520): bottom tab bar (Personal, Recents, Favourites, Spaces, More) ≤819px — the sidebar was display:none below 820px with no replacement. More sheet carries Shares/Transfers/Federated/Deleted files/Administration under their existing visibility rules with the Transfers dot. At ≤480px every .menu/.fbpop popover becomes a bottom sheet (grabber, scrim via body:has, 46px rows, safe-area padding) and search collapses to a magnifier that expands to a full-width 16px-input row.

Wave B — list & actions (v0.6.181, PR #521): phone rows carry size · date in the subtitle, actions reduce to star + kebab at 44px, kebab and space sheets open with an identity header, selection swaps the tab bar for a bottom action bar (the real #sel-* buttons DOM-moved, width-gated, reversible on resize), 2-column tiles, compact toolbar.

Wave C — layers (v0.6.182, PR #522): preview is a full takeover ≤480 (over the top bar, tab bar hidden while open) with the system back gesture closing it via one pushed history entry, and horizontal swipe stepping siblings like ArrowUp/Down. Dialogs become bottom cards (90dvh, sticky actions, 16px inputs); the audit picker becomes a sheet.

Wave D — admin + editor (v0.6.183, PR #523): Administration was unreachable below 820px (the rail lives in the hidden sidebar) — phones now get a topic-list drill-in proxying the real rail buttons, with a back affordance, and the tab bar stays visible in admin (tab taps close admin first, so dirty-revert runs). The three ceremonies — audit leak tracing, key rotation/drain, peering key exchange — carry an advisory desk card in en/de-CH/fr/it; nothing is gated. Editor bar ≤480: 44px, icon-only back, no path/app tag; the read-only chip never degrades.

Desktop invariant, enforced by construction: each wave's one-shot ran a fence gate over all six &lt;style&gt; blocks asserting the only phone selectors outside @media (max-width:…) blocks are the three display:none base lines (#searchtoggle, #searchcancel, #tabbar / .n2ph, .shhead, #selbot / #admtopics, #admback, .deskcard), plus node --check on every inline script block. All injected JS is width-gated or CSS-hidden at ≥820px.

Out of scope as agreed: long-press selection, PWA/manifest, pull-to-refresh; desktop-only: drag-drop move, preview divider, density setting.

Remaining before close: the real-phone pass — Safari iOS + Android Chrome on files/files-bao: tab bar + More sheet, sheets/scrim, search expand, row kebab header, selection bottom bar, preview takeover + back gesture + swipe, a dialog (rename), admin drill-in + a save bar, and opening a document in the editor. I can't log in to the dogfoods, so everything above is verified structurally; the visual pass is yours.

## Mobile pass shipped — v0.6.180 → v0.6.183, all four waves live on both dogfoods Implemented exactly per the approved mockup and the three recorded decisions (bottom tab bar; star + kebab rows with bottom-sheet menus; functional admin with 3 desktop-only ceremonies). **Wave A — shell (v0.6.180, PR #520):** bottom tab bar (Personal, Recents, Favourites, Spaces, More) ≤819px — the sidebar was `display:none` below 820px with no replacement. More sheet carries Shares/Transfers/Federated/Deleted files/Administration under their existing visibility rules with the Transfers dot. At ≤480px every `.menu`/`.fbpop` popover becomes a bottom sheet (grabber, scrim via `body:has`, 46px rows, safe-area padding) and search collapses to a magnifier that expands to a full-width 16px-input row. **Wave B — list &amp; actions (v0.6.181, PR #521):** phone rows carry `size · date` in the subtitle, actions reduce to star + kebab at 44px, kebab **and** space sheets open with an identity header, selection swaps the tab bar for a bottom action bar (the real `#sel-*` buttons DOM-moved, width-gated, reversible on resize), 2-column tiles, compact toolbar. **Wave C — layers (v0.6.182, PR #522):** preview is a full takeover ≤480 (over the top bar, tab bar hidden while open) with the system back gesture closing it via one pushed history entry, and horizontal swipe stepping siblings like ArrowUp/Down. Dialogs become bottom cards (90dvh, sticky actions, 16px inputs); the audit picker becomes a sheet. **Wave D — admin + editor (v0.6.183, PR #523):** Administration was unreachable below 820px (the rail lives in the hidden sidebar) — phones now get a topic-list drill-in proxying the real rail buttons, with a back affordance, and the tab bar stays visible in admin (tab taps close admin first, so dirty-revert runs). The three ceremonies — audit leak tracing, key rotation/drain, peering key exchange — carry an advisory desk card in en/de-CH/fr/it; nothing is gated. Editor bar ≤480: 44px, icon-only back, no path/app tag; the read-only chip never degrades. **Desktop invariant, enforced by construction:** each wave's one-shot ran a fence gate over **all six** `&lt;style&gt;` blocks asserting the only phone selectors outside `@media (max-width:…)` blocks are the three `display:none` base lines (`#searchtoggle, #searchcancel, #tabbar` / `.n2ph, .shhead, #selbot` / `#admtopics, #admback, .deskcard`), plus `node --check` on every inline script block. All injected JS is width-gated or CSS-hidden at ≥820px. **Out of scope as agreed:** long-press selection, PWA/manifest, pull-to-refresh; desktop-only: drag-drop move, preview divider, density setting. **Remaining before close: the real-phone pass** — Safari iOS + Android Chrome on files/files-bao: tab bar + More sheet, sheets/scrim, search expand, row kebab header, selection bottom bar, preview takeover + back gesture + swipe, a dialog (rename), admin drill-in + a save bar, and opening a document in the editor. I can't log in to the dogfoods, so everything above is verified structurally; the visual pass is yours.
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#389
No description provided.