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 <select> dropdown - Add settings.localeLabel i18n key (de + en) - Bump SW cache to v22 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* oikos-locale-picker — Sprachauswahl-Web-Component
|
* oikos-locale-picker — Sprachauswahl-Web-Component
|
||||||
* Zeigt Radio-Buttons für System/Deutsch/English.
|
* Zeigt ein <select>-Dropdown für System/Deutsch/English.
|
||||||
* Bei Auswahl: setLocale() oder localStorage-Eintrag löschen (System).
|
* Bei Auswahl: setLocale() oder localStorage-Eintrag löschen (System).
|
||||||
* Dependencies: i18n.js
|
* Dependencies: i18n.js
|
||||||
*/
|
*/
|
||||||
@@ -24,56 +24,43 @@ class OikosLocalePicker extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_render() {
|
_render() {
|
||||||
this.textContent = '';
|
|
||||||
|
|
||||||
const stored = localStorage.getItem('oikos-locale');
|
const stored = localStorage.getItem('oikos-locale');
|
||||||
|
|
||||||
const wrapper = document.createElement('div');
|
const label = document.createElement('label');
|
||||||
wrapper.className = 'locale-picker';
|
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
|
// System-Option
|
||||||
const systemOption = this._createOption(
|
const systemOpt = document.createElement('option');
|
||||||
'system',
|
systemOpt.value = 'system';
|
||||||
t('settings.localeSystem'),
|
systemOpt.textContent = t('settings.localeSystem');
|
||||||
!stored,
|
systemOpt.selected = !stored;
|
||||||
() => {
|
select.appendChild(systemOpt);
|
||||||
localStorage.removeItem('oikos-locale');
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
wrapper.appendChild(systemOption);
|
|
||||||
|
|
||||||
// Sprach-Optionen
|
// Sprach-Optionen
|
||||||
for (const locale of getSupportedLocales()) {
|
for (const locale of getSupportedLocales()) {
|
||||||
const option = this._createOption(
|
const opt = document.createElement('option');
|
||||||
locale,
|
opt.value = locale;
|
||||||
LOCALE_LABELS[locale] || locale,
|
opt.textContent = LOCALE_LABELS[locale] || locale;
|
||||||
stored === locale,
|
opt.selected = stored === locale;
|
||||||
() => setLocale(locale)
|
select.appendChild(opt);
|
||||||
);
|
|
||||||
wrapper.appendChild(option);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
this.replaceChildren(label, select);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -510,6 +510,7 @@
|
|||||||
"googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
|
"googleDisconnectConfirm": "Google Calendar-Verbindung trennen?",
|
||||||
"appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?",
|
"appleDisconnectConfirm": "Apple Calendar-Verbindung trennen?",
|
||||||
"localeSystem": "System",
|
"localeSystem": "System",
|
||||||
|
"localeLabel": "Sprache",
|
||||||
"languageTitle": "Sprache"
|
"languageTitle": "Sprache"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -510,6 +510,7 @@
|
|||||||
"googleDisconnectConfirm": "Disconnect Google Calendar?",
|
"googleDisconnectConfirm": "Disconnect Google Calendar?",
|
||||||
"appleDisconnectConfirm": "Disconnect Apple Calendar?",
|
"appleDisconnectConfirm": "Disconnect Apple Calendar?",
|
||||||
"localeSystem": "System",
|
"localeSystem": "System",
|
||||||
|
"localeLabel": "Language",
|
||||||
"languageTitle": "Language"
|
"languageTitle": "Language"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -12,9 +12,9 @@
|
|||||||
* API: Immer Netzwerk (kein Caching von Nutzerdaten)
|
* API: Immer Netzwerk (kein Caching von Nutzerdaten)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const SHELL_CACHE = 'oikos-shell-v21';
|
const SHELL_CACHE = 'oikos-shell-v22';
|
||||||
const PAGES_CACHE = 'oikos-pages-v21';
|
const PAGES_CACHE = 'oikos-pages-v22';
|
||||||
const ASSETS_CACHE = 'oikos-assets-v21';
|
const ASSETS_CACHE = 'oikos-assets-v22';
|
||||||
const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE];
|
const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE];
|
||||||
|
|
||||||
// App-Shell: sofort benötigt für ersten Render
|
// App-Shell: sofort benötigt für ersten Render
|
||||||
@@ -123,8 +123,10 @@ self.addEventListener('fetch', (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bilder + Fonts: Cache-First, langer TTL
|
// Bilder + Fonts: Cache-First, langer TTL — nur Same-Origin
|
||||||
if (isAsset(url.pathname)) {
|
// 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));
|
event.respondWith(cacheFirst(request, ASSETS_CACHE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user