@@ -214,9 +215,9 @@ - - - + + + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 738cee6..c863241 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -193,11 +193,7 @@ const App = (() => { } function _openSidebar() { - 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')?.classList.add('open'); document.getElementById('sidebar-backdrop')?.classList.add('visible'); } diff --git a/backend/static/js/pages/map.js b/backend/static/js/pages/map.js index abff813..3f81735 100644 --- a/backend/static/js/pages/map.js +++ b/backend/static/js/pages/map.js @@ -148,9 +148,8 @@ window.Page_map = (() => { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }) .addTo(_map); - // invalidateSize zweimal: einmal früh, einmal nach möglichen Layout-Delays - setTimeout(() => _map.invalidateSize(), 100); - setTimeout(() => _map.invalidateSize(), 600); + // invalidateSize nach kurzer Verzögerung, damit der Browser das Layout abgeschlossen hat + setTimeout(() => _map.invalidateSize(), 150); window.addEventListener('resize', () => _map.invalidateSize()); } diff --git a/backend/static/sw.js b/backend/static/sw.js index 9c80bfb..26956b7 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,11 +3,12 @@ Offline-Cache + Push Notifications ============================================================ */ -const CACHE_VERSION = 'by-v33'; +const CACHE_VERSION = 'by-v27'; const CACHE_STATIC = `${CACHE_VERSION}-static`; -// index.html wird NICHT pre-gecacht (immer Network-First) +// Diese Dateien werden beim Install gecacht (App Shell) const STATIC_ASSETS = [ + '/', '/css/design-system.css', '/css/layout.css', '/css/components.css', @@ -43,7 +44,7 @@ self.addEventListener('activate', event => { }); // ---------------------------------------------------------- -// FETCH — Network-First für HTML, Cache-First für Assets, Network für API +// FETCH — Cache-First für statische Assets, Network-First für API // ---------------------------------------------------------- self.addEventListener('fetch', event => { const url = new URL(event.request.url); @@ -59,25 +60,12 @@ 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)); @@ -86,6 +74,7 @@ self.addEventListener('fetch', event => { }) ) .catch(() => { + // Offline-Fallback: App Shell zurückgeben if (event.request.mode === 'navigate') { return caches.match('/'); } @@ -147,6 +136,7 @@ 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(); @@ -154,6 +144,7 @@ self.addEventListener('notificationclick', event => { return; } } + // Neues Fenster öffnen return clients.openWindow(url); }) );