diff --git a/pwa/index.html b/pwa/index.html index 2005b54..1a66208 100644 --- a/pwa/index.html +++ b/pwa/index.html @@ -25,7 +25,11 @@ diff --git a/pwa/src/main.ts b/pwa/src/main.ts index 6b1a920..8701c0f 100644 --- a/pwa/src/main.ts +++ b/pwa/src/main.ts @@ -11,12 +11,44 @@ import './styles/main.css'; import 'leaflet/dist/leaflet.css'; import { initLocale } from './i18n/i18n'; import { init } from './app'; -import { setStatus } from './ui/status-bar'; -import { t } from './i18n/i18n'; import { maybeShow as maybeShowIosInstallHint } from './ui/install-hint'; console.info(`[tilfluktsrom] build ${__BUILD_REVISION__}`); +// Make `registerType: 'autoUpdate'` actually auto-update the running tab. +// vite-plugin-pwa's autoUpdate strategy makes the new service worker +// skipWaiting + clientsClaim, but the JS already loaded in the open tab is +// the *old* build until something triggers a navigation. Without this +// listener, a deploy is invisible until the user manually refreshes. +// +// We *defer* the reload until the user next backgrounds the app +// (visibilityState === 'hidden') instead of reloading immediately. This is +// an emergency app: a mid-task reload would lose the selected shelter, +// compass mode, and any in-flight UI state right when the user can least +// afford to be surprised. Deferring keeps the "auto" promise (they're on +// the new version next time they look at the screen) without interrupting +// active use. +// +// The `wasAlreadyControlled` guard avoids reloading on the very first SW +// install (when there was no previous controller — that's a fresh visit, +// not an update). +if ('serviceWorker' in navigator) { + const wasAlreadyControlled = !!navigator.serviceWorker.controller; + let pendingReload = false; + + navigator.serviceWorker.addEventListener('controllerchange', () => { + if (!wasAlreadyControlled) return; + pendingReload = true; + }); + + document.addEventListener('visibilitychange', () => { + if (pendingReload && document.visibilityState === 'hidden') { + pendingReload = false; + window.location.reload(); + } + }); +} + document.addEventListener('DOMContentLoaded', async () => { initLocale(); @@ -25,14 +57,6 @@ document.addEventListener('DOMContentLoaded', async () => { await navigator.storage.persist(); } - // Listen for service worker updates — flash a status message when a new - // version activates so the user knows they have fresh code/data. - if ('serviceWorker' in navigator) { - navigator.serviceWorker.addEventListener('controllerchange', () => { - setStatus(t('update_success')); - }); - } - await init(); // Shown only on first iOS Safari visit, once per device. Placed after init() diff --git a/pwa/src/styles/main.css b/pwa/src/styles/main.css index 9e89200..f045d71 100644 --- a/pwa/src/styles/main.css +++ b/pwa/src/styles/main.css @@ -86,6 +86,13 @@ html, body { cursor: not-allowed; } +#share-btn svg { + display: block; + /* `↻` and `ℹ` glyphs sit on a baseline; an SVG inside an inline-flex + container can otherwise pick up extra descender space and look + misaligned next to them. `display:block` removes that. */ +} + /* --- Main content area (map or compass) --- */ #main-content { flex: 1;