Skip to content

Mobile: the native apps on a phone — one tap, one pane, pinch, and a self-updating PWA - #749

Merged
AllTerrainDeveloper merged 5 commits into
trunkfrom
mobile/native-apps
Sep 3, 2026
Merged

Mobile: the native apps on a phone — one tap, one pane, pinch, and a self-updating PWA#749
AllTerrainDeveloper merged 5 commits into
trunkfrom
mobile/native-apps

Conversation

@AllTerrainDeveloper

@AllTerrainDeveloper AllTerrainDeveloper commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Why

The phone layer (#739, #746, #747) puts every window full-screen, but the apps inside still assumed a desk: double-click to open, two-pane splits, pinned columns, 32px insets, a Corkboard that only zoomed with a wheel. And two gaps in the layer itself made the shell feel stuck: closing the last app left an empty "Open apps" sheet over a hidden home, and an installed app on an iPhone never learned about a new release without being deleted and reinstalled.

What

Phone layer

  • The switcher closes itself when its last card is closed; home shows. Opening it from an empty home still shows the empty message.
  • Both edges carry a zone that cancels the touchstart behind the browser's history swipe (mobile Safari, Chrome for Android), on home too. Pointer Events are unaffected, so the edge-Back gesture keeps working.
  • The home grid is always a scroller by one pixel (.os-mobile-home__content), so a screen that fits gets the platform's own rubber band. No JS tracking.

Installed app — how a release reaches it

  • includes/pwa.php puts OPENSTATION_VERSION in the self.__OS_SW_CONFIG preamble, so a release is a byte change in the served worker even when nothing under src/pwa/ changed (the bundle itself is content-hashed on purpose).
  • src/pwa/sw-register.ts calls registration.update() whenever the page comes back to the foreground (visibilitychange, pageshow), at most once every five minutes and never while hidden. The existing controllerchange handler reloads once. New section in docs/pwa.md.

Apps

  • Corkboard pinches: two fingers zoom about their midpoint and pan with it (src/content-graph/pinch.ts, the wheel's anchoring). The canvas takes touch-action: none; a finger lifting off a pinch is not a tap on the node it rested on.
  • WP Explorer opens on one tap on a phone (mode stamp) or under a coarse primary pointer: rows, tiles, folder tiles, dossier relation tiles. Modifier clicks still only select; an item with no editor still opens its pane.
  • Code Blue page-scrolls as one surface under 640px instead of pinning toolbar, tiles and chart around a 120px issue list.
  • Preferences swaps the sidebar for an <os-select> of the same pages under 640px (both bind tab; the strip stays in the DOM to drive the panes) and drops the pane inset from 32px to 12px.
  • Posts, Pages, Users offer the status filter as an <os-select> on a phone (src/posts-window/status-control.ts, same data attribute, same os-pick), wrap the toolbar, and show title + date (users: name, role, actions). Trimming runs after the hidden-column preference and the columns filter, so nothing is hidden on the desk.
  • Plugins shows name, status, actions on a phone with no sticky column; the search takes its own row.
  • Comments shows one pane at a time under 720px: the list, then the conversation on a tap, with a Back control in its head; the five tabs become an <os-select> with the counts in the labels. The @media (max-width: 720px) rule that hid the rail outright is replaced by a container query.

Tests

New: sw-register-resume, content-graph-pinch, posts-window-status-control; extended: mobile-layer, mobile-gestures, os-settings.test.ts, list-table.test.ts, openStationPwaAdminAssetCache.php. npm run typecheck, lint, test:js (455 files), lint:php, the PHPUnit class and npm run build are green.

Unverified on device

The history-swipe guard relies on cancelling touchstart at the edge zones, which is the documented way to suppress Safari's gesture but has not been tried on a real iPhone here. Please test it first.

🤖 Generated with Claude Code

Open WordPress Playground Preview

AllTerrainDeveloper and others added 5 commits September 3, 2026 17:08
…self-updating PWA

The phone layer put every window full-screen; the apps inside still
assumed a desk. This pass makes each of them usable under a thumb, and
fixes the two phone-layer gaps that made the shell feel stuck.

Phone layer
- The switcher steps aside when its last card is closed, so home shows
  instead of an empty sheet the user had to dismiss by hand.
- Both edges carry a zone that cancels the touchstart behind the
  browser's history swipe (Safari, Chrome for Android), on home too.
- The home grid is always a scroller by one pixel, so a screen that fits
  gets the platform's own rubber band.

Installed app
- The plugin version rides in the service worker preamble, so a release
  is a byte change even when nothing under src/pwa changed.
- The shell asks the registration for an update whenever the page comes
  back to the foreground (visibilitychange, pageshow), at most once per
  five minutes; the existing controllerchange handler reloads once.

Apps
- Corkboard pinches: two fingers zoom about their midpoint and pan with
  it (pinch.ts, the wheel's anchoring); the canvas takes touch-action
  none, and a finger lifting off a pinch is not a tap on a node.
- WP Explorer opens on one tap on a phone or under a coarse pointer —
  rows, tiles, folder tiles, dossier relation tiles.
- Code Blue page-scrolls as one surface under 640px.
- Preferences swaps the sidebar for an os-select of the same pages,
  bound to the same state, and tightens the pane inset.
- Posts, Pages and Users offer the status filter as an os-select on a
  phone (status-control.ts), wrap the toolbar, and show title and date
  (users: name, role, actions) after the hidden-column preference and
  the columns filter have run.
- Plugins shows name, status and actions on a phone with no sticky
  column; the search takes its own row.
- Comments shows one pane at a time under 720px — the list, then the
  conversation on a tap, with a Back control — and its five tabs become
  an os-select with the counts in the labels. The media query that hid
  the rail outright is gone.

Docs: docs/mobile.md, docs/pwa.md. Tests for every piece above.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… names the editor window

The narrow layouts for Comments, Preferences, Posts/Pages/Users, Plugins
and Code Blue were container queries alone (600–720px). The phone mode
is not a width: a wide browser previewing it, or a phone turned
sideways, runs the phone layer with a window wider than any of those
thresholds, and none of the folds applied — the tab strip stayed, the
Comments rail stayed hidden with its Back control going nowhere, the
Preferences inset stayed at 32px. Each fold is now also keyed on
html[data-os-mode="mobile"], the same rules under both.

WP Explorer's edit action opened the editor on a bare URL, and an
iframe never reports its own title, so the window — and the phone's
top bar — read the URL for as long as it lived. The action now passes
the item's own title (and the section's icon), for posts and users.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A finger has no right button, and iOS never turns a held finger into a
contextmenu event. A touch or pen held still for half a second on a
row, a tile or the empty canvas now opens the same context menu a
right-click does, where the finger is; the release is swallowed so it
is not also a tap. A drift past 10px (a scroll) or an early lift
cancels. The press state hangs off the element rather than the
handler closure, so a repaint mid-press cannot leave a timer nobody
can cancel.

The browser's own callout and text selection are off on those
surfaces under a coarse pointer and in the phone mode; on a desk the
labels stay selectable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A long menu on a phone (WP Explorer's item menu runs past twenty rows)
opened off the bottom edge with no way to reach the rest: the viewport
clamp in menu-position.ts can only slide a box that fits, so it parked
the menu at the top edge with its tail cut off. The open menu now caps
itself to the viewport (dvh, with vh as the floor) and scrolls inside,
which also gives the clamp a box it can place. Submenu flyouts are
separate elements, so the overflow clips nothing of theirs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Side by side in a 360px pane the sentence wrapped to three lines beside
a button squeezed to its minimum. Under a narrow container, and in the
phone mode, the sentence and the button stack, the order the copy
already puts them in.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@AllTerrainDeveloper
AllTerrainDeveloper merged commit c511842 into trunk Sep 3, 2026
5 checks passed
@AllTerrainDeveloper
AllTerrainDeveloper deleted the mobile/native-apps branch September 3, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant