fix(pwa): restore apple-mobile-web-app-capable so iOS installs standalone

Adding /rep to an iPad home screen and tapping it opened the main app,
not the rep app — while the shortcut URL was still /rep.

Cause: Next 16 renders `appleWebApp.capable: true` as the standardised
<meta name="mobile-web-app-capable"> and no longer emits the
apple-prefixed name. iOS only reads the apple-prefixed one. Without it
the icon is a plain Safari bookmark rather than a standalone app, so
tapping it foregrounds Safari on whatever tab was already open — which
presents exactly as "it opened the main app instead".

This was not specific to /rep. Verified against the running app that
/m (Boss Phone) had the same gap, so it has never actually launched
standalone on iOS either; /counter likewise. The comment in
(counter)/layout.tsx asserting the root layout already supplied this
tag was wrong — the root also only set `appleWebApp.capable`.

Declared in the root layout so all four surfaces inherit it, and
repeated in the (rep) and (mobile) layouts because a child's
`metadata.other` replaces the parent's rather than merging into it.
Corrected the misleading counter comment.

Verified by fetching each route and asserting the rendered head:
/rep, /m, /new-order and /dashboard now all emit
apple-mobile-web-app-capable="yes" while still resolving their own
manifest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-09-06 21:56:01 +02:00
parent ad1a3ed7cf
commit a7341397a6
4 changed files with 43 additions and 4 deletions

View file

@ -4,10 +4,13 @@ import { CounterShell } from "./shell";
export const metadata: Metadata = {
title: "Counter · WFDASH",
manifest: "/manifest-counter.json",
// Standalone display for the installed PWA. iOS reads this from
// <meta name="apple-mobile-web-app-capable"> via the same value in
// the root layout — duplicating it here so each route segment's
// metadata is self-contained.
// Standalone display comes from `apple-mobile-web-app-capable`,
// which the root layout declares via `metadata.other` and this
// segment inherits (it defines no `other` of its own, so nothing
// overrides it). The previous comment here claimed the root already
// supplied that tag — it didn't: the root only set
// `appleWebApp.capable`, which Next 16 renders under the
// standardised name that iOS ignores.
applicationName: "WFDASH Counter",
};

View file

@ -14,6 +14,13 @@ export const metadata: Metadata = {
statusBarStyle: "default",
title: "Boss",
},
other: {
// Next 16 emits only the standardised `mobile-web-app-capable` for
// `appleWebApp.capable`, and iOS ignores that name — so without
// this the home-screen icon opens as a Safari bookmark rather than
// a standalone app. See the same note in `(rep)/rep/layout.tsx`.
"apple-mobile-web-app-capable": "yes",
},
};
export const viewport: Viewport = {

View file

@ -24,6 +24,18 @@ export const metadata: Metadata = {
statusBarStyle: "default",
title: "Visits",
},
other: {
// `appleWebApp.capable: true` emits the standardised
// `mobile-web-app-capable` in Next 16 — and **iOS only honours the
// apple-prefixed name**. Without this tag the home-screen icon is
// a plain Safari bookmark, not a standalone app: tapping it just
// foregrounds Safari on whatever tab was already open, which looks
// exactly like "it opened the main app instead".
//
// Verified on the running app: only `mobile-web-app-capable` was
// present until this was added.
"apple-mobile-web-app-capable": "yes",
},
};
export const viewport: Viewport = {

View file

@ -130,6 +130,23 @@ export const metadata: Metadata = {
statusBarStyle: "default",
title: "WFDASH",
},
other: {
// Next 16 renders `appleWebApp.capable: true` as the standardised
// `<meta name="mobile-web-app-capable">` and no longer emits the
// apple-prefixed name — which is the only one iOS actually reads.
//
// Without this, an "Add to Home Screen" icon is a plain Safari
// bookmark rather than a standalone app: tapping it foregrounds
// Safari on whatever tab was already open, which presents as "it
// opened the main app instead of mine". Verified missing on /m and
// /rep against the running app before this was added.
//
// Declared at the root so every surface inherits it (/, /m,
// /counter, /rep). The PWA layouts that define their own `other`
// repeat it, because a child's `other` replaces the parent's
// rather than merging into it.
"apple-mobile-web-app-capable": "yes",
},
openGraph: {
type: "website",
title: "WFDASH - Business CRM",