@@ -215,9 +214,9 @@ - - - + + + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index c863241..738cee6 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -193,7 +193,11 @@ const App = (() => { } function _openSidebar() { - document.getElementById('sidebar')?.classList.add('open'); + const s = document.getElementById('sidebar'); + if (!s) { UI.toast.error('sidebar: NULL'); return; } + s.classList.add('open'); + const cs = getComputedStyle(s); + UI.toast.info(`display:${cs.display} | transform:${cs.transform} | z:${cs.zIndex}`); document.getElementById('sidebar-backdrop')?.classList.add('visible'); } diff --git a/backend/static/js/pages/map.js b/backend/static/js/pages/map.js index 3f81735..abff813 100644 --- a/backend/static/js/pages/map.js +++ b/backend/static/js/pages/map.js @@ -148,8 +148,9 @@ window.Page_map = (() => { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }) .addTo(_map); - // invalidateSize nach kurzer Verzögerung, damit der Browser das Layout abgeschlossen hat - setTimeout(() => _map.invalidateSize(), 150); + // invalidateSize zweimal: einmal früh, einmal nach möglichen Layout-Delays + setTimeout(() => _map.invalidateSize(), 100); + setTimeout(() => _map.invalidateSize(), 600); window.addEventListener('resize', () => _map.invalidateSize()); } diff --git a/backend/static/sw.js b/backend/static/sw.js index 26956b7..9c80bfb 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,12 +3,11 @@ Offline-Cache + Push Notifications ============================================================ */ -const CACHE_VERSION = 'by-v27'; +const CACHE_VERSION = 'by-v33'; const CACHE_STATIC = `${CACHE_VERSION}-static`; -// Diese Dateien werden beim Install gecacht (App Shell) +// index.html wird NICHT pre-gecacht (immer Network-First) const STATIC_ASSETS = [ - '/', '/css/design-system.css', '/css/layout.css', '/css/components.css', @@ -44,7 +43,7 @@ self.addEventListener('activate', event => { }); // ---------------------------------------------------------- -// FETCH — Cache-First für statische Assets, Network-First für API +// FETCH — Network-First für HTML, Cache-First für Assets, Network für API // ---------------------------------------------------------- self.addEventListener('fetch', event => { const url = new URL(event.request.url); @@ -60,12 +59,25 @@ self.addEventListener('fetch', event => { return; } + // Navigation (index.html): immer Network-First + if (event.request.mode === 'navigate') { + event.respondWith( + fetch(event.request) + .then(response => { + const clone = response.clone(); + caches.open(CACHE_STATIC).then(c => c.put(event.request, clone)); + return response; + }) + .catch(() => caches.match('/')) + ); + return; + } + // Statische Assets: Cache-First event.respondWith( caches.match(event.request) .then(cached => cached || fetch(event.request) .then(response => { - // Erfolgreiche Responses für statische Assets cachen if (response.ok && event.request.method === 'GET') { const clone = response.clone(); caches.open(CACHE_STATIC).then(c => c.put(event.request, clone)); @@ -74,7 +86,6 @@ self.addEventListener('fetch', event => { }) ) .catch(() => { - // Offline-Fallback: App Shell zurückgeben if (event.request.mode === 'navigate') { return caches.match('/'); } @@ -136,7 +147,6 @@ self.addEventListener('notificationclick', event => { event.waitUntil( clients.matchAll({ type: 'window', includeUncontrolled: true }) .then(windowClients => { - // Offenes Fenster fokussieren for (const client of windowClients) { if (client.url.includes(self.location.origin)) { client.focus(); @@ -144,7 +154,6 @@ self.addEventListener('notificationclick', event => { return; } } - // Neues Fenster öffnen return clients.openWindow(url); }) );