Add progressive web app companion for cross-platform access
Vite + TypeScript PWA that mirrors the Android app's core features: - Pre-processed shelter data (build-time UTM33N→WGS84 conversion) - Leaflet map with shelter markers, user location, and offline tiles - Canvas compass arrow (ported from DirectionArrowView.kt) - IndexedDB shelter cache with 7-day staleness check - Service worker with CacheFirst tiles and precached app shell - i18n for en, nb, nn (ported from Android strings.xml) - iOS/Android compass handling with low-pass filter - Respects user map interaction (no auto-snap on pan/zoom) - Build revision cache-breaker for reliable SW updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
46365b713b
commit
e8428de775
12051 changed files with 1799735 additions and 0 deletions
1
pwa/dist/assets/index-Cki23tZT.css
vendored
Normal file
1
pwa/dist/assets/index-Cki23tZT.css
vendored
Normal file
File diff suppressed because one or more lines are too long
13
pwa/dist/assets/index-Db4vftzp.js
vendored
Normal file
13
pwa/dist/assets/index-Db4vftzp.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4450
pwa/dist/data/shelters.json
vendored
Normal file
4450
pwa/dist/data/shelters.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
pwa/dist/icons/generate-icons.sh
vendored
Normal file
13
pwa/dist/icons/generate-icons.sh
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
# Generate simple SVG-based placeholder icons for the PWA
|
||||
# These should be replaced with proper icons later
|
||||
|
||||
for size in 192 512; do
|
||||
cat > "public/icons/icon-${size}.svg" << EOF
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
|
||||
<rect width="${size}" height="${size}" fill="#1A1A2E" rx="32"/>
|
||||
<path d="M${size/2} ${size*15/100}L${size*15/100} ${size*55/100}h${size*15/100}v${size*30/100}h${size*40/100}v-${size*30/100}h${size*15/100}Z" fill="#FF6B35" stroke="#fff" stroke-width="${size/50}"/>
|
||||
<text x="${size/2}" y="${size*75/100}" text-anchor="middle" fill="#fff" font-size="${size*15/100}" font-weight="bold" font-family="sans-serif">T</text>
|
||||
</svg>
|
||||
EOF
|
||||
done
|
||||
BIN
pwa/dist/icons/icon-192.png
vendored
Normal file
BIN
pwa/dist/icons/icon-192.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 963 B |
BIN
pwa/dist/icons/icon-512.png
vendored
Normal file
BIN
pwa/dist/icons/icon-512.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
69
pwa/dist/index.html
vendored
Normal file
69
pwa/dist/index.html
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#1A1A2E" />
|
||||
<meta name="description" content="Find the nearest public shelter in Norway" />
|
||||
<title>Tilfluktsrom</title>
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png" />
|
||||
<link rel="apple-touch-icon" href="/icons/icon-192.png" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||||
crossorigin="" />
|
||||
<script type="module" crossorigin src="/assets/index-Db4vftzp.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Cki23tZT.css">
|
||||
<script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- Status bar -->
|
||||
<div id="status-bar">
|
||||
<span id="status-text"></span>
|
||||
<button id="refresh-btn" aria-label="Refresh data">↻</button>
|
||||
</div>
|
||||
|
||||
<!-- Main content: map or compass -->
|
||||
<div id="main-content">
|
||||
<div id="map-container"></div>
|
||||
<div id="compass-container">
|
||||
<span id="compass-address"></span>
|
||||
<span id="compass-distance"></span>
|
||||
</div>
|
||||
<!-- Toggle map/compass FAB -->
|
||||
<button id="toggle-fab" aria-label="Toggle map/compass view">🧭</button>
|
||||
<!-- Reset view button -->
|
||||
<button id="reset-view-btn" aria-label="Reset view">⌖</button>
|
||||
</div>
|
||||
|
||||
<!-- No-cache warning banner -->
|
||||
<div id="no-cache-banner">
|
||||
<span id="no-cache-text"></span>
|
||||
<button id="cache-retry-btn"></button>
|
||||
</div>
|
||||
|
||||
<!-- Bottom sheet with shelter info -->
|
||||
<div id="bottom-sheet">
|
||||
<div id="selected-shelter">
|
||||
<canvas id="mini-arrow" width="96" height="96"></canvas>
|
||||
<div id="selected-shelter-info">
|
||||
<div id="selected-shelter-address"></div>
|
||||
<div id="selected-shelter-details"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="shelter-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading overlay -->
|
||||
<div id="loading-overlay">
|
||||
<div id="loading-spinner"></div>
|
||||
<div id="loading-text"></div>
|
||||
<div id="loading-button-row">
|
||||
<button id="loading-skip-btn"></button>
|
||||
<button id="loading-ok-btn"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
24
pwa/dist/manifest.webmanifest
vendored
Normal file
24
pwa/dist/manifest.webmanifest
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "Tilfluktsrom",
|
||||
"short_name": "Tilfluktsrom",
|
||||
"description": "Find the nearest public shelter in Norway",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"theme_color": "#1A1A2E",
|
||||
"background_color": "#1A1A2E",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
pwa/dist/registerSW.js
vendored
Normal file
1
pwa/dist/registerSW.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
||||
1
pwa/dist/sw.js
vendored
Normal file
1
pwa/dist/sw.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,t)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let r={};const o=e=>i(e,c),a={module:{uri:c},exports:r,require:o};s[c]=Promise.all(n.map(e=>a[e]||o(e))).then(e=>(t(...e),r))}}define(["./workbox-1d305bb8"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"manifest.webmanifest",revision:"90bba3b1e58044451de0bb5ba407f418"},{url:"index.html",revision:"d6eecdbc0aac35ef5e1a06a075a90183"},{url:"icons/icon-512.png",revision:"81e7312ad6a641949a2c5140d3716895"},{url:"icons/icon-192.png",revision:"b9ecccceab7cf3ec7d7a02fd45277247"},{url:"data/shelters.json",revision:"f28e872a285d4647cd1ba9ea98e0b06c"},{url:"assets/index-Db4vftzp.js",revision:"3be3eacc39fbc435514f11a4f412e97d"},{url:"assets/index-Cki23tZT.css",revision:"e11597b4bbc77264a7ef0e725bcac53a"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"))),e.registerRoute(/^https:\/\/[abc]\.tile\.openstreetmap\.org\/.*/,new e.CacheFirst({cacheName:"osm-tiles",plugins:[new e.ExpirationPlugin({maxEntries:5e3,maxAgeSeconds:2592e3}),new e.CacheableResponsePlugin({statuses:[0,200]})]}),"GET")});
|
||||
1
pwa/dist/workbox-1d305bb8.js
vendored
Normal file
1
pwa/dist/workbox-1d305bb8.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue