This commit is contained in:
2026-08-18 23:11:17 +02:00
parent 6b48fcb363
commit 52b46f09a4
11 changed files with 958 additions and 137 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+25
View File
@@ -0,0 +1,25 @@
{
"name": "FixFin",
"short_name": "FixFin",
"description": "Fixkostenplanung für Konten, regelmäßige Zahlungen und Rücklagen.",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#090d14",
"theme_color": "#111827",
"orientation": "any",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
+46
View File
@@ -0,0 +1,46 @@
const SHELL_CACHE='fixfin-shell-v3.14';
const DATA_CACHE='fixfin-data-v1';
const APP_SHELL=['/','/manifest.webmanifest','/icons/icon-192.png','/icons/icon-512.png','/icons/apple-touch-icon.png'];
self.addEventListener('install',event=>{
event.waitUntil(caches.open(SHELL_CACHE).then(cache=>cache.addAll(APP_SHELL)).then(()=>self.skipWaiting()));
});
self.addEventListener('activate',event=>{
event.waitUntil(Promise.all([
caches.keys().then(keys=>Promise.all(keys.filter(key=>key.startsWith('fixfin-shell-')&&key!==SHELL_CACHE).map(key=>caches.delete(key)))),
self.clients.claim(),
]));
});
self.addEventListener('fetch',event=>{
const request=event.request;
if(request.method!=='GET') return;
const url=new URL(request.url);
if(url.origin!==self.location.origin) return;
if(url.pathname==='/api/data') {
event.respondWith(fetch(request).then(response=>{
if(response.ok) caches.open(DATA_CACHE).then(cache=>cache.put(request,response.clone()));
return response;
}).catch(()=>caches.match(request).then(cached=>cached||new Response(JSON.stringify({error:'Offline und keine zwischengespeicherten Daten verfügbar.'}),{status:503,headers:{'Content-Type':'application/json'}}))));
return;
}
if(url.pathname.startsWith('/api/')) return;
if(request.mode==='navigate') {
event.respondWith(fetch(request).then(response=>{
caches.open(SHELL_CACHE).then(cache=>cache.put('/',response.clone()));
return response;
}).catch(()=>caches.match('/')));
return;
}
event.respondWith(caches.match(request).then(cached=>{
const network=fetch(request).then(response=>{
if(response.ok) caches.open(SHELL_CACHE).then(cache=>cache.put(request,response.clone()));
return response;
}).catch(()=>cached);
return cached||network;
}));
});