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
57
pwa/src/ui/loading-overlay.ts
Normal file
57
pwa/src/ui/loading-overlay.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Loading overlay: spinner + message + OK/Skip buttons.
|
||||
* Same flow as Android: prompt before map caching, user can skip.
|
||||
*/
|
||||
|
||||
/** Show the loading overlay with a message and optional spinner. */
|
||||
export function showLoading(message: string, showSpinner = true): void {
|
||||
const overlay = document.getElementById('loading-overlay')!;
|
||||
const text = document.getElementById('loading-text')!;
|
||||
const spinner = document.getElementById('loading-spinner')!;
|
||||
const buttonRow = document.getElementById('loading-button-row')!;
|
||||
|
||||
text.textContent = message;
|
||||
spinner.style.display = showSpinner ? 'block' : 'none';
|
||||
buttonRow.style.display = 'none';
|
||||
overlay.style.display = 'flex';
|
||||
}
|
||||
|
||||
/** Show the cache prompt (OK / Skip buttons, no spinner). */
|
||||
export function showCachePrompt(
|
||||
message: string,
|
||||
onOk: () => void,
|
||||
onSkip: () => void,
|
||||
): void {
|
||||
const overlay = document.getElementById('loading-overlay')!;
|
||||
const text = document.getElementById('loading-text')!;
|
||||
const spinner = document.getElementById('loading-spinner')!;
|
||||
const buttonRow = document.getElementById('loading-button-row')!;
|
||||
const okBtn = document.getElementById('loading-ok-btn')!;
|
||||
const skipBtn = document.getElementById('loading-skip-btn')!;
|
||||
|
||||
text.textContent = message;
|
||||
spinner.style.display = 'none';
|
||||
buttonRow.style.display = 'flex';
|
||||
overlay.style.display = 'flex';
|
||||
|
||||
okBtn.onclick = () => {
|
||||
hideLoading();
|
||||
onOk();
|
||||
};
|
||||
skipBtn.onclick = () => {
|
||||
hideLoading();
|
||||
onSkip();
|
||||
};
|
||||
}
|
||||
|
||||
/** Update loading text (e.g. progress). */
|
||||
export function updateLoadingText(message: string): void {
|
||||
const text = document.getElementById('loading-text');
|
||||
if (text) text.textContent = message;
|
||||
}
|
||||
|
||||
/** Hide the loading overlay. */
|
||||
export function hideLoading(): void {
|
||||
const overlay = document.getElementById('loading-overlay');
|
||||
if (overlay) overlay.style.display = 'none';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue