navigator/src/routes/+page.svelte
hermes-explorigin 347e9b2a0a Add custom zones & POI layers with user-editable config and example data
- scripts/custom-layers.mjs: hand-authored, self-documenting config for
  custom zones (polygons) and points of interest, shipped with example
  Tulsa POIs and district zones plus a copy-paste template
- osm-data.mjs: merges custom layers into static/data/custom/<id>.geojson
  and includes them in the _index.json manifest with category, layerType,
  and color metadata
- MapView.svelte: renders each manifest entry as an independent toggleable
  Leaflet layer with per-layer styling and an on-map legend panel
- +page.svelte: loads all data sources (OSM + custom) from the manifest
2026-08-08 16:09:39 +00:00

70 lines
2.0 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import MapView, { type MapLayer } from '$lib/components/MapView.svelte';
type AreaManifest = MapLayer;
let areas = $state<MapLayer[]>([]);
let loading = $state(true);
let manifestError = $state<string | null>(null);
onMount(async () => {
try {
const res = await fetch('/data/_index.json');
if (!res.ok) throw new Error(`manifest HTTP ${res.status}`);
areas = (await res.json()) as MapLayer[];
} catch (e) {
manifestError = (e as Error).message;
}
loading = false;
});
const totalFeatures = $derived(areas.reduce((n, a) => n + a.featureCount, 0));
</script>
<svelte:head>
<title>Navigator — OSM Map</title>
</svelte:head>
<div class="app">
<div class="controls">
<strong>({areas.length}) data sources</strong>
{#if totalFeatures > 0}
<span class="stats">{totalFeatures} features</span>
{/if}
<span class="hint">Toggle layers on the map (top-right).</span>
</div>
{#if manifestError}
<div class="error">
Could not load data manifest (<code>/data/_index.json</code>).<br />
Run <code>npm run build:data</code> to fetch OSM data and merge custom
layers, then rebuild.
<p class="detail">{manifestError}</p>
</div>
{:else if areas.length}
<MapView layers={areas} title="Navigator" />
{:else if !loading}
<div class="error">
No built data found. Run <code>npm run build:data</code> to fetch OSM
data and/or add zones &amp; POIs in <code>scripts/custom-layers.mjs</code>.
</div>
{/if}
</div>
<style>
.app { display: grid; grid-template-rows: auto 1fr; height: 100vh; }
.controls {
display: flex; align-items: center; gap: 1.25rem;
padding: 0.75rem 1.25rem;
background: #1e293b; color: #e2e8f0;
font: 0.85rem system-ui, sans-serif; z-index: 500;
}
.controls strong { color: #fff; }
.stats { color: #94a3b8; }
.hint { color: #64748b; margin-left: auto; }
.error {
padding: 3rem 2rem; font: 0.95rem/1.5 system-ui, sans-serif; color: #b91c1c;
}
.detail { color: #64748b; font-size: 0.8rem; }
</style>