release nouri 0.6.0 polish backup and pwa
This commit is contained in:
@@ -6,9 +6,16 @@
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"display_override": ["standalone", "minimal-ui"],
|
||||
"background_color": "#fff6ef",
|
||||
"theme_color": "#efab72",
|
||||
"theme_color": "#de9862",
|
||||
"categories": ["food", "lifestyle", "productivity"],
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/brand/pwa-180.png",
|
||||
"sizes": "180x180",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/brand/pwa-192.png",
|
||||
"sizes": "192x192",
|
||||
@@ -18,6 +25,12 @@
|
||||
"src": "/static/brand/pwa-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/brand/pwa-maskable-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Nouri offline</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--bg: #fff6ef;
|
||||
--surface: rgba(255, 255, 255, 0.92);
|
||||
--line: rgba(126, 104, 85, 0.14);
|
||||
--text: #352d2b;
|
||||
--muted: #7d7069;
|
||||
--accent: #de9862;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 1.5rem;
|
||||
font-family: "Avenir Next", "Segoe UI", sans-serif;
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(255, 205, 174, 0.42), transparent 24rem),
|
||||
radial-gradient(circle at 90% 8%, rgba(190, 226, 203, 0.34), transparent 24rem),
|
||||
linear-gradient(180deg, var(--bg), #fdf0e6);
|
||||
}
|
||||
|
||||
.card {
|
||||
width: min(28rem, 100%);
|
||||
padding: 1.4rem;
|
||||
border-radius: 24px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
box-shadow: 0 22px 48px rgba(125, 92, 68, 0.12);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 0.45rem;
|
||||
font-family: "Iowan Old Style", "Palatino Linotype", serif;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.35rem 0;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
padding: 0.82rem 1.1rem;
|
||||
border-radius: 999px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="card">
|
||||
<h1>Nouri ist gerade kurz offline</h1>
|
||||
<p>Die App bleibt da und versucht es gleich wieder. Sobald die Verbindung zurück ist, kannst du normal weitermachen.</p>
|
||||
<p class="muted">Ein Teil der Oberfläche ist schon lokal verfügbar. Für aktuelle Haushaltsdaten braucht Nouri aber wieder eine Verbindung.</p>
|
||||
<a href="/">Erneut versuchen</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +1,32 @@
|
||||
const CACHE_NAME = "nouri-v0-5-1-1";
|
||||
const CACHE_NAME = "nouri-v0-6-0";
|
||||
const OFFLINE_URL = "/static/pwa/offline.html";
|
||||
const STATIC_ASSETS = [
|
||||
"/static/css/styles.css",
|
||||
"/static/js/theme.js",
|
||||
"/static/js/ui.js",
|
||||
"/static/js/planner.js",
|
||||
"/static/js/pwa.js",
|
||||
"/static/brand/pwa-180.png",
|
||||
"/static/brand/pwa-192.png",
|
||||
"/static/brand/pwa-512.png",
|
||||
"/static/brand/pwa-maskable-512.png",
|
||||
"/static/brand/pwa-badge.png",
|
||||
"/static/brand/favicon.svg",
|
||||
"/app.webmanifest",
|
||||
OFFLINE_URL,
|
||||
];
|
||||
|
||||
const cacheFirst = async (request) => {
|
||||
const cached = await caches.match(request);
|
||||
if (cached) return cached;
|
||||
const response = await fetch(request);
|
||||
if (response && response.ok && response.type === "basic") {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
cache.put(request, response.clone());
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => cache.addAll(STATIC_ASSETS)).then(() => self.skipWaiting())
|
||||
@@ -28,40 +45,32 @@ self.addEventListener("fetch", (event) => {
|
||||
if (event.request.method !== "GET") return;
|
||||
|
||||
const requestUrl = new URL(event.request.url);
|
||||
const isStaticAsset =
|
||||
requestUrl.origin === self.location.origin &&
|
||||
(
|
||||
requestUrl.pathname.startsWith("/static/")
|
||||
|| requestUrl.pathname === "/app.webmanifest"
|
||||
|| requestUrl.pathname === "/service-worker.js"
|
||||
);
|
||||
const isSameOrigin = requestUrl.origin === self.location.origin;
|
||||
const isStaticAsset = isSameOrigin && (
|
||||
requestUrl.pathname.startsWith("/static/")
|
||||
|| requestUrl.pathname === "/app.webmanifest"
|
||||
|| requestUrl.pathname === "/service-worker.js"
|
||||
);
|
||||
const isUpload = isSameOrigin && requestUrl.pathname.startsWith("/uploads/");
|
||||
|
||||
if (event.request.mode === "navigate") {
|
||||
event.respondWith(
|
||||
fetch(event.request).catch(() => caches.match(event.request))
|
||||
fetch(event.request)
|
||||
.then((response) => {
|
||||
const copy = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, copy));
|
||||
return response;
|
||||
})
|
||||
.catch(async () => {
|
||||
return (await caches.match(event.request)) || caches.match(OFFLINE_URL);
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isStaticAsset) {
|
||||
return;
|
||||
if (isStaticAsset || isUpload) {
|
||||
event.respondWith(cacheFirst(event.request));
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(event.request).then((cached) => {
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return fetch(event.request).then((response) => {
|
||||
if (!response || response.status !== 200 || response.type !== "basic") {
|
||||
return response;
|
||||
}
|
||||
const clone = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
|
||||
return response;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("push", (event) => {
|
||||
|
||||
Reference in New Issue
Block a user