Files
dapelza ee55fb1cf9 Phase 0+1: Scaffold, Datenmodell, Karte und Liste
Reines HTML5/CSS3/JavaScript ohne Build-Tooling, lauffaehig direkt per
Doppelklick auf index.html (file://, kein Server noetig):

- Datenmodell fuer Ausflugsziele mit allen Feldern aus der Anforderung,
  15 feste Kategorien inkl. Farbe/Icon
- Zentraler Pub/Sub-Store mit LocalStorage-Persistenz und
  Migrations-Grundgeruest
- Interaktive Karte (Leaflet + Leaflet.markercluster, lokal vendored)
  mit kategoriefarbenen Markern, Clustering, Popups, Geolocation-Button
- Kartengrundlage ueber CARTO-Basemaps statt tile.openstreetmap.org, da
  dessen Referer-Pflicht file://-Aufrufe blockiert
- Seed-Daten als eingebettetes Script (data/seed.js) statt JSON-Datei,
  da fetch() auf lokale Dateien unter file:// nicht zuverlaessig
  funktioniert
- Ergebnisliste mit 10 Beispiel-Ausflugszielen, sicher gerendert ueber
  textContent/DOM-APIs statt innerHTML (Vorbereitung fuer spaeteren
  KI-JSON-Import mit Fremddaten)
- Responsives Layout (Desktop nebeneinander, Mobile gestapelt)
2026-07-24 11:24:47 +02:00

64 lines
1.8 KiB
JavaScript

// Persistenzschicht: liest/schreibt die beiden LocalStorage-Keys
// eventmap.data.v1 und eventmap.settings.v1.
(function () {
const { STORAGE_KEYS, CURRENT_SCHEMA_VERSION } = EventMap.config;
const { migrate } = EventMap.store;
function createDefaultSettings() {
return {
lastFilters: null,
lastMapView: null,
userConsentGeo: null,
defaultCenter: null,
};
}
/** Liest die persistierten Places. Gibt null zurück, falls noch nichts gespeichert ist. */
function loadData() {
const raw = window.localStorage.getItem(STORAGE_KEYS.DATA);
if (!raw) {
return null;
}
try {
const parsed = JSON.parse(raw);
return migrate(parsed);
} catch (err) {
console.warn('EventMap: Gespeicherte Daten sind beschädigt und werden verworfen.', err);
return null;
}
}
function saveData(places) {
const payload = {
schemaVersion: CURRENT_SCHEMA_VERSION,
places,
updatedAt: new Date().toISOString(),
};
window.localStorage.setItem(STORAGE_KEYS.DATA, JSON.stringify(payload));
}
function loadSettings() {
const raw = window.localStorage.getItem(STORAGE_KEYS.SETTINGS);
if (!raw) {
return createDefaultSettings();
}
try {
return { ...createDefaultSettings(), ...JSON.parse(raw) };
} catch (err) {
console.warn('EventMap: Gespeicherte Einstellungen sind beschädigt, Defaults werden verwendet.', err);
return createDefaultSettings();
}
}
function saveSettings(settings) {
window.localStorage.setItem(STORAGE_KEYS.SETTINGS, JSON.stringify(settings));
}
EventMap.store.createDefaultSettings = createDefaultSettings;
EventMap.store.loadData = loadData;
EventMap.store.saveData = saveData;
EventMap.store.loadSettings = loadSettings;
EventMap.store.saveSettings = saveSettings;
})();