Mobile: fit the installed app to a phone — display stamp, no zoom, anchored tab bar - #747
Merged
Conversation
…chored tab bar The phone layer never knew whether it ran in a tab or as an installed app, nothing stopped the page from zooming, and the tab bar's bottom edge was wherever Safari ended the shell's viewport-sized fixed box. - `data-os-display="standalone|browser"` on <html>, written by the head stamp and the mode controller; `wp.os.mode.getDisplay()` / `isStandalone()`. - No page zoom: `maximum-scale=1,user-scalable=no` in the viewport meta, `touch-action: pan-x pan-y` on the root, a zoom guard cancelling the pinch while stamped mobile or standalone, and every kit field at 16px on the phone through `--os-ui-field-font-size` (+ compact, + radius). - The tab bar is fixed to the viewport's bottom edge; the shell body keeps its footprint clear. The admin-bar height token is 0 on a phone. - Opaque status bar (`black`, filterable via `openstation_pwa_status_bar_style`); manifest colours, theme-color and splash on the backstop. - The phone's glass, shadows and scrims are `--os-mobile-*` tokens. - Drag and drop off on a phone: DragManager.start(), dock reorder, the OS file-drop sentinel/manager and WP Explorer's marquee refuse it. - Trash's toolbar and WP Explorer's preview fold under a narrow container. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The thirteen palette tokens minted for the phone layer and the kit fields had no Legacy entry, so the frozen theme would have handed each to the brand. Each is answered at the value its consuming rule falls back to — the pre-brand white glass, the shadows and scrims as they were, 13px/12px/6px for the fields — and the mobile sheet's glass fallbacks are moved to the same pre-brand literals, which the standing rule always asked for. The frozen count rises to 482. 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
Installed on an iPhone home screen, OpenStation left a band of nothing under the tab bar, showed a translucent status bar over the shell's top edge, zoomed the page whenever the home search was focused, and let a pinch scale the chrome off screen. Nothing in the shell knew it was running as an app, the mobile sheet's glass and shadows were literals outside the palette, and two native windows (Trash, WP Explorer) were laid out for a desktop's width.
What
The display stamp.
data-os-display="standalone|browser"on<html>, written by the PHP head stamp before the first paint and kept current by the mode controller (thedisplay-mode: standalonequery, or Safari'snavigator.standalone). Exposed aswp.os.mode.getDisplay()/isStandalone(). Orthogonal to the mode.No zoom. Three layers, each covering what the others cannot:
maximum-scale=1,user-scalable=noin the shell's viewport meta;src/mode/zoom-guard.ts, cancelling Safari'sgesture*events, a two-fingertouchmoveand a ctrl-wheelwhile the document is stampedmobileorstandalone(never on a desktop in a tab, where zoom is an accessibility affordance); andtouch-action: pan-x pan-yon the root plus every kit field at 16px on the phone, through new--os-ui-field-font-size/-compact/--os-ui-field-radiustokens the text field, textarea, tag input and category picker read.The tab bar hugs the bottom edge. It is
position: fixedto the viewport with the home-indicator inset as padding, instead of the shell's last flex child; the shell body keeps its footprint clear. A viewport-sized fixed box is what mobile Safari has ended short of the screen before.--wp-admin--admin-bar--heightis 0 on a phone.One surface with the system. The iOS status bar is opaque
black(new filteropenstation_pwa_status_bar_styleto go back toblack-translucentordefault); the manifest's colours, thetheme-colormeta and the splash use the backstop#0c0b0f.The phone wears the palette. Ten
--os-mobile-*tokens invariables.cssfor the glass, its border, the shadows and the scrims; every--_m-*alias reads a token with the old literal as its floor.No drag and drop on a phone. One refusal in
DragManager.start()covers every shell drag; the three gestures that are not manager sessions refuse it themselves: the dock reorder, the OS file-drop sentinel and manager, WP Explorer's marquee.Narrow apps. Trash's toolbar takes three rows under a 560px container (type filter scrolling sideways under the search); WP Explorer's preview becomes a bottom sheet under 640px, at most 45% tall, present only while something is selected.
Tests
tests/vitest/mode-display.test.ts,zoom-guard.test.ts,mobile-viewport.test.ts(the stylesheet contract: anchoring, touch-action, 16px fields, alias-to-token, container queries, the drag refusals).tests/phpunit/tests/mobileMode.php(display stamp, viewport meta on the shell),openStationPwaStatusBarStyle.php.Docs
mobile.md(the display, the two system edges, the no-zoom policy, drag off, narrow apps),pwa.md,javascript-reference.md,hooks-reference.md,desktop-themes.md,api-index.md.Testing on a device
Delete and re-add the home-screen app: iOS captures the status-bar style at install.
🤖 Generated with Claude Code