From af69431eaca494443c0eccaeda4f4d45c67ed773 Mon Sep 17 00:00:00 2001 From: Ulas Date: Wed, 1 Apr 2026 09:42:06 +0200 Subject: [PATCH] fix: weather icons in PWA + locale picker dropdown - SW: skip cross-origin asset requests (opaque responses caused weather icons to break in PWA standalone mode on Android) - Replace oikos-locale-picker radio buttons with -Dropdown für System/Deutsch/English. * Bei Auswahl: setLocale() oder localStorage-Eintrag löschen (System). * Dependencies: i18n.js */ @@ -24,56 +24,43 @@ class OikosLocalePicker extends HTMLElement { } _render() { - this.textContent = ''; - const stored = localStorage.getItem('oikos-locale'); - const wrapper = document.createElement('div'); - wrapper.className = 'locale-picker'; + const label = document.createElement('label'); + label.className = 'locale-picker__label'; + label.htmlFor = 'locale-select'; + label.textContent = t('settings.localeLabel'); + + const select = document.createElement('select'); + select.className = 'form-input locale-picker__select'; + select.id = 'locale-select'; // System-Option - const systemOption = this._createOption( - 'system', - t('settings.localeSystem'), - !stored, - () => { - localStorage.removeItem('oikos-locale'); - location.reload(); - } - ); - wrapper.appendChild(systemOption); + const systemOpt = document.createElement('option'); + systemOpt.value = 'system'; + systemOpt.textContent = t('settings.localeSystem'); + systemOpt.selected = !stored; + select.appendChild(systemOpt); // Sprach-Optionen for (const locale of getSupportedLocales()) { - const option = this._createOption( - locale, - LOCALE_LABELS[locale] || locale, - stored === locale, - () => setLocale(locale) - ); - wrapper.appendChild(option); + const opt = document.createElement('option'); + opt.value = locale; + opt.textContent = LOCALE_LABELS[locale] || locale; + opt.selected = stored === locale; + select.appendChild(opt); } - this.appendChild(wrapper); - } + select.addEventListener('change', () => { + if (select.value === 'system') { + localStorage.removeItem('oikos-locale'); + location.reload(); + } else { + setLocale(select.value); + } + }); - _createOption(value, label, checked, onChange) { - const item = document.createElement('label'); - item.className = 'locale-picker__option'; - - const radio = document.createElement('input'); - radio.type = 'radio'; - radio.name = 'locale'; - radio.value = value; - radio.checked = checked; - radio.addEventListener('change', onChange); - - const span = document.createElement('span'); - span.textContent = label; - - item.appendChild(radio); - item.appendChild(span); - return item; + this.replaceChildren(label, select); } } diff --git a/public/locales/de.json b/public/locales/de.json index c80f640..3065bef 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -510,6 +510,7 @@ "googleDisconnectConfirm": "Google Calendar-Verbindung trennen?", "appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?", "localeSystem": "System", + "localeLabel": "Sprache", "languageTitle": "Sprache" }, diff --git a/public/locales/en.json b/public/locales/en.json index d2f94a0..9ab35e8 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -510,6 +510,7 @@ "googleDisconnectConfirm": "Disconnect Google Calendar?", "appleDisconnectConfirm": "Disconnect Apple Calendar?", "localeSystem": "System", + "localeLabel": "Language", "languageTitle": "Language" }, diff --git a/public/sw.js b/public/sw.js index 8efa454..2cc8fd9 100644 --- a/public/sw.js +++ b/public/sw.js @@ -12,9 +12,9 @@ * API: Immer Netzwerk (kein Caching von Nutzerdaten) */ -const SHELL_CACHE = 'oikos-shell-v21'; -const PAGES_CACHE = 'oikos-pages-v21'; -const ASSETS_CACHE = 'oikos-assets-v21'; +const SHELL_CACHE = 'oikos-shell-v22'; +const PAGES_CACHE = 'oikos-pages-v22'; +const ASSETS_CACHE = 'oikos-assets-v22'; const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE]; // App-Shell: sofort benötigt für ersten Render @@ -123,8 +123,10 @@ self.addEventListener('fetch', (event) => { return; } - // Bilder + Fonts: Cache-First, langer TTL - if (isAsset(url.pathname)) { + // Bilder + Fonts: Cache-First, langer TTL — nur Same-Origin + // Cross-Origin-Assets (z.B. Wetter-Icons von openweathermap.org) nicht + // abfangen: opaque Responses führen im PWA-Modus zu Darstellungsfehlern. + if (isAsset(url.pathname) && url.origin === self.location.origin) { event.respondWith(cacheFirst(request, ASSETS_CACHE)); return; }