00121aaec9
CI / test (push) Has been cancelled
The captive-portal Step-2 QR opens pictureframe.edholm.me in Safari, which is the perfect moment to also offer "pin this to your home screen" so the recipient gets one-tap access without typing the URL again. Two pieces: * Service worker at /sw.js (document root, scope "/"). Minimal — install/activate calls skipWaiting + clients.claim, fetch is passthrough. Real offline caching is intentionally out of scope; we only need the SW to exist so Chrome's PWA-install heuristic fires. * Settings → Install app section, hidden when display-mode standalone. Android Chrome path: native beforeinstallprompt button. iOS Safari (and any other non-prompt browser): button opens a modal with step-by-step Share → Add to Home Screen instructions. usePwaInstall composable handles the singleton lifecycle — beforeinstallprompt fires once per page load and may fire before the user navigates to Settings, so we register on module import and stash the event for later. Tests cover: install button rendered when not standalone, modal opens on click without a native prompt, modal close button works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
26 lines
1.0 KiB
JavaScript
26 lines
1.0 KiB
JavaScript
// Minimal service worker — present so Chrome's PWA install criteria
|
|
// pass and the beforeinstallprompt event fires. Real offline caching
|
|
// is intentionally out of scope; we don't pre-cache the SPA shell or
|
|
// intercept fetches in any meaningful way.
|
|
//
|
|
// Lives at /sw.js (document root, not /build/sw.js) so its default
|
|
// scope is /, matching the manifest's "scope": "/". Don't move it
|
|
// without setting Service-Worker-Allowed: / on the response.
|
|
|
|
self.addEventListener('install', () => {
|
|
// Activate immediately, don't wait for old tabs to close
|
|
self.skipWaiting()
|
|
})
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
// Take control of all clients (including ones that loaded before
|
|
// this SW activated) so subsequent navigations go through us.
|
|
event.waitUntil(self.clients.claim())
|
|
})
|
|
|
|
self.addEventListener('fetch', () => {
|
|
// Passthrough — we don't call event.respondWith(), so the browser
|
|
// proceeds with its normal network fetch. The handler existing at
|
|
// all is what Chrome's PWA install heuristic looks for.
|
|
})
|