0f2e109aa2
The three things a browser asks for, without a plugin: a manifest in
public/ (name, /app as the start, three icons cut from the one piece of
art this repo has), a service worker, and the two metas iOS reads
instead of the manifest.
The worker caches the shell — /, /app, /library, all one document under
the SPA fallback — and the hashed assets the build emits. A navigation
is network-first, so a deploy is never pinned behind the cache; a
hashed asset or the wasm is cache-first, because under a given build
those never change. /api and any non-GET go straight out: a worker is a
cache, not a proxy. nginx serves sw.js and manifest.json `no-cache`
(both names outlive their contents) with the isolation headers the
worker script needs under COEP.
The offer is the app's own dialog, not Chromium's mini-infobar: the
event is held, and it is spent either after the visitor has been in the
studio two minutes or the moment an export lands — the point at which
the app has done their work. Safari never fires the event, so it gets
the Share > Add to Home Screen line instead. A refusal is remembered and
never asked again.
node scripts/make-icons.mjs 192x192 39785B / 512x512 159296B / maskable 512x512 123723B
node scripts/pwa-check.mjs manifest 3 icons · worker activated · shell cached
· offline reload of /app paints
off (https://localhost:8090) same four, through nginx
50 lines
3.2 KiB
HTML
50 lines
3.2 KiB
HTML
<!doctype html>
|
|
<html lang="vi" data-theme="dark" data-accent="amber" data-fonts="studio">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#0a0a0a" />
|
|
<link rel="icon" type="image/png" href="/assets/RecipesCamIcon.png" />
|
|
<link rel="apple-touch-icon" href="/assets/RecipesCamIcon.png" />
|
|
<!-- The installed app. The manifest is a static file in public/ (see
|
|
public/manifest.json and scripts/make-icons.mjs for its icons), so a build
|
|
needs no plugin to ship it. iOS ignores most of the manifest and reads these
|
|
three metas instead: 'capable' is what makes a home-screen bookmark open
|
|
without Safari's chrome, 'black-translucent' gives it the app's black bars,
|
|
and 'title' is the name under the icon. -->
|
|
<link rel="manifest" href="/manifest.json" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
<meta name="apple-mobile-web-app-title" content="RecipesCam" />
|
|
<title>RecipesCam — web</title>
|
|
<meta name="description" content="RecipesCam web — grade photos with the same film recipes as the app." />
|
|
<link rel="canonical" href="/" />
|
|
|
|
<!-- Share card. The URLs are relative on purpose: a crawler resolves them
|
|
against whatever host serves the page, so the same build previews
|
|
correctly on any deployment. og:image is the 1200x630 hero shot in
|
|
public/assets/og-cover.png (see the og-cover script in the repo notes). -->
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:site_name" content="RecipesCam" />
|
|
<meta property="og:title" content="RecipesCam — Color Recipes & Film Camera Studio" />
|
|
<meta property="og:description" content="Grade ảnh bằng công thức màu phim Kodak & Fuji — tone curve, hạt phim và halation. Cùng một pipeline trên điện thoại và web studio, ảnh không rời khỏi máy bạn." />
|
|
<meta property="og:url" content="/" />
|
|
<meta property="og:image" content="/assets/og-cover.png" />
|
|
<meta property="og:image:type" content="image/png" />
|
|
<meta property="og:image:width" content="1200" />
|
|
<meta property="og:image:height" content="630" />
|
|
<meta property="og:image:alt" content="RecipesCam landing page — capture and grade photos with exclusive color recipes" />
|
|
<meta property="og:locale" content="vi_VN" />
|
|
<meta property="og:locale:alternate" content="en_US" />
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content="RecipesCam — Color Recipes & Film Camera Studio" />
|
|
<meta name="twitter:description" content="Grade ảnh bằng công thức màu phim Kodak & Fuji — tone curve, hạt phim và halation. Cùng một pipeline trên điện thoại và web studio." />
|
|
<meta name="twitter:image" content="/assets/og-cover.png" />
|
|
<meta name="twitter:image:alt" content="RecipesCam landing page — capture and grade photos with exclusive color recipes" />
|
|
</head>
|
|
<body>
|
|
<div id="root"></div>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|