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:
Ole-Morten Duesund 2026-03-08 17:41:38 +01:00
commit e8428de775
12051 changed files with 1799735 additions and 0 deletions

View file

@ -0,0 +1,70 @@
"use strict";
exports.__esModule = true;
exports.applyMissingDependenciesDefaults = applyMissingDependenciesDefaults;
exports.validateIncludeExclude = validateIncludeExclude;
var _utils = require("./utils");
function patternToRegExp(pattern) {
if (pattern instanceof RegExp) return pattern;
try {
return new RegExp(`^${pattern}$`);
} catch (_unused) {
return null;
}
}
function buildUnusedError(label, unused) {
if (!unused.length) return "";
return ` - The following "${label}" patterns didn't match any polyfill:\n` + unused.map(original => ` ${String(original)}\n`).join("");
}
function buldDuplicatesError(duplicates) {
if (!duplicates.size) return "";
return ` - The following polyfills were matched both by "include" and "exclude" patterns:\n` + Array.from(duplicates, name => ` ${name}\n`).join("");
}
function validateIncludeExclude(provider, polyfills, includePatterns, excludePatterns) {
let current;
const filter = pattern => {
const regexp = patternToRegExp(pattern);
if (!regexp) return false;
let matched = false;
for (const polyfill of polyfills.keys()) {
if (regexp.test(polyfill)) {
matched = true;
current.add(polyfill);
}
}
return !matched;
};
// prettier-ignore
const include = current = new Set();
const unusedInclude = Array.from(includePatterns).filter(filter);
// prettier-ignore
const exclude = current = new Set();
const unusedExclude = Array.from(excludePatterns).filter(filter);
const duplicates = (0, _utils.intersection)(include, exclude);
if (duplicates.size > 0 || unusedInclude.length > 0 || unusedExclude.length > 0) {
throw new Error(`Error while validating the "${provider}" provider options:\n` + buildUnusedError("include", unusedInclude) + buildUnusedError("exclude", unusedExclude) + buldDuplicatesError(duplicates));
}
return {
include,
exclude
};
}
function applyMissingDependenciesDefaults(options, babelApi) {
const {
missingDependencies = {}
} = options;
if (missingDependencies === false) return false;
const caller = babelApi.caller(caller => caller == null ? void 0 : caller.name);
const {
log = "deferred",
inject = caller === "rollup-plugin-babel" ? "throw" : "import",
all = false
} = missingDependencies;
return {
log,
inject,
all
};
}