feat(pwa): Offline-Banner in App-Shell, reminders.css lazy geladen
Zeigt automatisch wenn navigator.onLine === false. Blendet sich aus sobald Verbindung wiederhergestellt. reminders.css aus globalem <link> entfernt (wird lazy geladen).
This commit is contained in:
+16
-2
@@ -38,8 +38,6 @@
|
||||
<link rel="stylesheet" href="/styles/layout.css" />
|
||||
<link rel="stylesheet" href="/styles/glass.css" />
|
||||
<link rel="stylesheet" href="/styles/login.css" />
|
||||
<link rel="stylesheet" href="/styles/reminders.css" />
|
||||
|
||||
<!-- Theme: explizite Nutzer-Overrides vor CSS-Rendering anwenden (Flash-Prevention).
|
||||
System-Präferenz wird durch @media (prefers-color-scheme: dark) in tokens.css
|
||||
direkt per CSS behandelt — kein JS-matchMedia erforderlich. -->
|
||||
@@ -62,6 +60,22 @@
|
||||
<!-- Skip-Link: sichtbar bei Keyboard-Fokus, verknüpft mit <main id="main-content"> -->
|
||||
<a href="#main-content" class="sr-only">Zum Hauptinhalt springen</a>
|
||||
|
||||
<!-- Offline-Banner: sichtbar wenn navigator.onLine === false -->
|
||||
<div id="offline-banner" class="offline-banner" hidden aria-live="polite" role="status">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" aria-hidden="true">
|
||||
<line x1="1" y1="1" x2="23" y2="23"></line>
|
||||
<path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"></path>
|
||||
<path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"></path>
|
||||
<path d="M10.71 5.05A16 16 0 0 1 22.56 9"></path>
|
||||
<path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"></path>
|
||||
<path d="M8.53 16.11a6 6 0 0 1 6.95 0"></path>
|
||||
<line x1="12" y1="20" x2="12.01" y2="20"></line>
|
||||
</svg>
|
||||
<span data-i18n="offline.banner"></span>
|
||||
</div>
|
||||
|
||||
<!-- App-Shell - wird durch JavaScript gefüllt -->
|
||||
<div id="app" class="app-shell">
|
||||
<!-- Skeleton-Loading während Initialisierung -->
|
||||
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -888,5 +888,8 @@
|
||||
"next": "Weiter",
|
||||
"done": "Loslegen",
|
||||
"skip": "Überspringen"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – Verbindung wird wiederhergestellt…"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,5 +869,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,5 +869,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -868,5 +868,8 @@
|
||||
"next": "Next",
|
||||
"done": "Get started",
|
||||
"skip": "Skip"
|
||||
},
|
||||
"offline": {
|
||||
"banner": "Offline – reconnecting…"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,6 +541,20 @@ function renderAppShell(container) {
|
||||
initMoreSheet(container);
|
||||
initNavHideOnScroll(container);
|
||||
initSearch(container);
|
||||
initOfflineBanner();
|
||||
}
|
||||
|
||||
function initOfflineBanner() {
|
||||
const banner = document.getElementById('offline-banner');
|
||||
if (!banner) return;
|
||||
const i18nSpan = banner.querySelector('[data-i18n]');
|
||||
function update() {
|
||||
banner.hidden = navigator.onLine;
|
||||
if (i18nSpan) i18nSpan.textContent = t('offline.banner');
|
||||
}
|
||||
window.addEventListener('online', update);
|
||||
window.addEventListener('offline', update);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1897,6 +1897,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------
|
||||
* Offline-Banner
|
||||
* -------------------------------------------------------- */
|
||||
.offline-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: calc(var(--z-toast) + 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-2) var(--space-4);
|
||||
background-color: var(--color-warning-light);
|
||||
color: var(--color-warning);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--color-warning) 20%, transparent);
|
||||
animation: offline-banner-in 0.2s var(--ease-out);
|
||||
}
|
||||
|
||||
.offline-banner[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes offline-banner-in {
|
||||
from { opacity: 0; transform: translateY(-100%); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.offline-banner { animation: none; }
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------
|
||||
* Print-Styles
|
||||
* -------------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user