From fea5fe9cbbd70e9833ef355fca10a4b4bb00bc4a Mon Sep 17 00:00:00 2001 From: Oliver G Date: Sun, 15 Feb 2026 16:12:04 +0100 Subject: [PATCH] feat: add iOS-focused PWA shell with service worker and manifest --- README.md | 4 ++ src/datenschutz.html | 10 ++++- src/icons/icon.svg | 11 +++++ src/index.html | 11 ++++- src/manifest.webmanifest | 19 +++++++++ src/pwa.js | 16 ++++++++ src/quellen.html | 10 ++++- src/service-worker.js | 88 ++++++++++++++++++++++++++++++++++++++++ src/styles.css | 10 +++++ 9 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 src/icons/icon.svg create mode 100644 src/manifest.webmanifest create mode 100644 src/pwa.js create mode 100644 src/service-worker.js diff --git a/README.md b/README.md index 5ca402b..e945387 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Implementiert: - API: `GET /spot/score`, `POST /spot/signal` - Kartenwahl via OpenStreetMap (Leaflet), inkl. Klickauswahl und Ortssuche - API: `GET /geocode/search` (Nominatim-Proxy), `GET /map/tile/{z}/{x}/{y}.png` (OSM-Tile-Proxy) +- PWA-Basis (Manifest, Service Worker, iOS-Standalone-Meta, Offline-Shell) - Admin-Bereich (Setup/Login, geschuetzt per User/Passwort + Session-Token) - Admin-API fuer Uebersicht und Event-Verwaltung (`/admin/*`) - Anti-Spam ohne Account: lokaler Token + serverseitiger HMAC-Hash @@ -43,6 +44,9 @@ Nicht im MVP: - `python3 -m http.server 8080` 7. App oeffnen: - `http://localhost:8080` +8. PWA-Test: + - iOS Safari: Seite aufrufen -> Teilen -> "Zum Home-Bildschirm" + - Danach aus Home-Screen starten (Standalone-Modus) ## OpenData Connector Config diff --git a/src/datenschutz.html b/src/datenschutz.html index 32647e0..9c6d681 100644 --- a/src/datenschutz.html +++ b/src/datenschutz.html @@ -2,8 +2,15 @@ - + + + + + Datenschutz | StaySense + + + @@ -105,6 +112,7 @@ + diff --git a/src/icons/icon.svg b/src/icons/icon.svg new file mode 100644 index 0000000..9bfdc08 --- /dev/null +++ b/src/icons/icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/index.html b/src/index.html index 93f3ba7..8792d35 100644 --- a/src/index.html +++ b/src/index.html @@ -2,8 +2,15 @@ - + + + + + StaySense NRW MVP + + + @@ -14,6 +21,7 @@

StaySense

Kreis Mettmann Pilot: ruhige Nacht in weniger als 10 Sekunden bewerten.

+ Netzwerkstatus wird geprüft ... Datenstand: -
@@ -190,6 +198,7 @@ + diff --git a/src/manifest.webmanifest b/src/manifest.webmanifest new file mode 100644 index 0000000..268ba5f --- /dev/null +++ b/src/manifest.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "StaySense NRW", + "short_name": "StaySense", + "description": "Night Safety Score für ruhige Nächte (22-06 Uhr) in NRW.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait", + "background_color": "#f3f7f6", + "theme_color": "#006680", + "icons": [ + { + "src": "/icons/icon.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any maskable" + } + ] +} diff --git a/src/pwa.js b/src/pwa.js new file mode 100644 index 0000000..cebc678 --- /dev/null +++ b/src/pwa.js @@ -0,0 +1,16 @@ +(function () { + if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker.register("/service-worker.js").catch(() => {}); + }); + } + + const isIos = /iphone|ipad|ipod/i.test(window.navigator.userAgent); + const isStandalone = + window.matchMedia("(display-mode: standalone)").matches || Boolean(window.navigator.standalone); + const hintEl = document.getElementById("ios-install-hint"); + if (hintEl && isIos && !isStandalone) { + hintEl.textContent = "Tipp: Über Teilen > Zum Home-Bildschirm hinzufügen für App-Modus auf iOS."; + hintEl.classList.remove("hidden"); + } +})(); diff --git a/src/quellen.html b/src/quellen.html index 60e3fed..8176a5e 100644 --- a/src/quellen.html +++ b/src/quellen.html @@ -2,8 +2,15 @@ - + + + + + StaySense Quellen & Attribution + + + @@ -72,6 +79,7 @@ +