Mobile: the native apps on a phone — one tap, one pane, pinch, and a self-updating PWA - #749
Merged
Merged
Conversation
…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>
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.
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
touchstartbehind the browser's history swipe (mobile Safari, Chrome for Android), on home too. Pointer Events are unaffected, so the edge-Back gesture keeps working..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.phpputsOPENSTATION_VERSIONin theself.__OS_SW_CONFIGpreamble, so a release is a byte change in the served worker even when nothing undersrc/pwa/changed (the bundle itself is content-hashed on purpose).src/pwa/sw-register.tscallsregistration.update()whenever the page comes back to the foreground (visibilitychange,pageshow), at most once every five minutes and never while hidden. The existingcontrollerchangehandler reloads once. New section indocs/pwa.md.Apps
src/content-graph/pinch.ts, the wheel's anchoring). The canvas takestouch-action: none; a finger lifting off a pinch is not a tap on the node it rested on.<os-select>of the same pages under 640px (both bindtab; the strip stays in the DOM to drive the panes) and drops the pane inset from 32px to 12px.<os-select>on a phone (src/posts-window/status-control.ts, same data attribute, sameos-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.<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 andnpm run buildare green.Unverified on device
The history-swipe guard relies on cancelling
touchstartat 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