feat(web): installable PWA shell so the web build works as an iPhone home-screen app
There is no iOS binary — CI only produces a signed APK — so Safari's Add to Home Screen is the only way onto an iPhone today. Without a manifest and the apple-* meta tags that lands a bookmark that opens inside browser chrome, so add both, plus a viewport that covers the notch and stops focus-zoom.
This commit is contained in:
BIN
app/public/icon-180.png
Normal file
BIN
app/public/icon-180.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
app/public/icon-192.png
Normal file
BIN
app/public/icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
app/public/icon-512.png
Normal file
BIN
app/public/icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
16
app/public/manifest.json
Normal file
16
app/public/manifest.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "GTD",
|
||||
"short_name": "GTD",
|
||||
"description": "Capture, clarify, do.",
|
||||
"start_url": "/today",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#F7F7F9",
|
||||
"theme_color": "#F7F7F9",
|
||||
"icons": [
|
||||
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
||||
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
||||
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
||||
]
|
||||
}
|
||||
49
app/src/app/+html.tsx
Normal file
49
app/src/app/+html.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
// The HTML shell for the web build.
|
||||
//
|
||||
// The web export is the iPhone story — there is no iOS binary, so Safari's "Add
|
||||
// to Home Screen" has to produce something that opens full-screen and looks
|
||||
// installed rather than a bookmark with a browser chrome on top. That takes the
|
||||
// manifest, the apple-* meta tags and a viewport that covers the notch; none of
|
||||
// them are reachable from app.json, so the shell is written out by hand.
|
||||
import { ScrollViewStyleReset } from "expo-router/html";
|
||||
import type { PropsWithChildren } from "react";
|
||||
|
||||
// Match the app background on both schemes so the status bar and the rubber-band
|
||||
// overscroll never flash white against a dark list.
|
||||
const background = `
|
||||
:root { color-scheme: light dark; }
|
||||
body { background-color: #F7F7F9; overscroll-behavior-y: none; }
|
||||
@media (prefers-color-scheme: dark) { body { background-color: #0C0C0F; } }
|
||||
`;
|
||||
|
||||
export default function Root({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||
{/* viewport-fit=cover lets the layout run under the notch; disabling
|
||||
user scaling stops iOS zooming in every time a title field focuses. */}
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="application-name" content="GTD" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-title" content="GTD" />
|
||||
{/* "default" keeps the iOS status bar legible over a light header. */}
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/icon-180.png" />
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#F7F7F9" />
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0C0C0F" />
|
||||
|
||||
<ScrollViewStyleReset />
|
||||
<style dangerouslySetInnerHTML={{ __html: background }} />
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user