100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
import "ol/ol.css";
|
|
import "./style.css";
|
|
import { registerSW } from "virtual:pwa-register";
|
|
import { createCacheStorage } from "./adapters/cache-storage";
|
|
import { createKachelFetch } from "./adapters/kachel-fetch";
|
|
import { createMarksDb } from "./adapters/marks-db";
|
|
import { toEtrs, watchStandort } from "./adapters/standort";
|
|
import { shippedConfig } from "./config";
|
|
import { openKarte } from "./karte/session";
|
|
import type { Point, Uebersicht } from "./karte/types";
|
|
import { mountScreen } from "./ui/screen";
|
|
|
|
void main();
|
|
|
|
async function main(): Promise<void> {
|
|
const root = document.querySelector("#app");
|
|
if (!(root instanceof HTMLElement)) return;
|
|
|
|
if (navigator.storage?.persist) void navigator.storage.persist();
|
|
registerSW({ immediate: true });
|
|
|
|
try {
|
|
const [uebersicht, standort] = await Promise.all([
|
|
loadUebersicht(),
|
|
readOpeningStandort(),
|
|
]);
|
|
const session = await openKarte({
|
|
uebersicht,
|
|
cache: createCacheStorage(),
|
|
marks: createMarksDb(),
|
|
kacheln: createKachelFetch(),
|
|
config: shippedConfig,
|
|
viewport: {
|
|
widthPx: window.innerWidth,
|
|
heightPx: window.innerHeight,
|
|
},
|
|
...(standort !== undefined ? { standort } : {}),
|
|
online: navigator.onLine,
|
|
appOpen: document.visibilityState === "visible",
|
|
});
|
|
|
|
mountScreen(root, session, uebersicht);
|
|
bindDevice(session);
|
|
} catch {
|
|
root.replaceChildren();
|
|
const message = document.createElement("p");
|
|
message.className = "boot-error";
|
|
message.textContent = "Die Karte konnte nicht geöffnet werden.";
|
|
root.append(message);
|
|
}
|
|
}
|
|
|
|
async function loadUebersicht(): Promise<Uebersicht> {
|
|
const response = await fetch("/uebersicht.json");
|
|
if (!response.ok) throw new Error("Übersicht fehlt");
|
|
return (await response.json()) as Uebersicht;
|
|
}
|
|
|
|
function readOpeningStandort(): Promise<Point | "denied" | undefined> {
|
|
if (!navigator.geolocation) return Promise.resolve("denied");
|
|
return new Promise((resolve) => {
|
|
navigator.geolocation.getCurrentPosition(
|
|
(position) => {
|
|
resolve(toEtrs(position.coords.longitude, position.coords.latitude));
|
|
},
|
|
(error) => {
|
|
if (error.code === error.TIMEOUT) resolve(undefined);
|
|
else resolve("denied");
|
|
},
|
|
{ maximumAge: 30_000, timeout: 2_000 },
|
|
);
|
|
});
|
|
}
|
|
|
|
function bindDevice(session: Awaited<ReturnType<typeof openKarte>>): void {
|
|
let stopWatch: (() => void) | null = null;
|
|
|
|
const watch = (open: boolean) => {
|
|
stopWatch?.();
|
|
stopWatch = null;
|
|
if (!open) return;
|
|
stopWatch = watchStandort((standort) => session.reportStandort(standort));
|
|
};
|
|
|
|
document.addEventListener("visibilitychange", () => {
|
|
const open = document.visibilityState === "visible";
|
|
if (!open) {
|
|
watch(false);
|
|
session.setAppOpen(false);
|
|
return;
|
|
}
|
|
session.setAppOpen(true);
|
|
watch(true);
|
|
});
|
|
|
|
window.addEventListener("online", () => session.setOnline(true));
|
|
window.addEventListener("offline", () => session.setOnline(false));
|
|
watch(document.visibilityState === "visible");
|
|
}
|