Offlinehandling hinzugefügt

This commit is contained in:
Borgal
2025-09-17 14:41:20 +02:00
parent 73efeba2b9
commit c5b7f3ecbd
3 changed files with 159 additions and 4 deletions

View File

@@ -1,9 +1,11 @@
{ {
"name": "DoMiLi", "name": "DoMiLi - Dönerstag-Runde",
"short_name": "DoMiLi", "short_name": "DoMiLi",
"description": "Dönerstag-Runde", "description": "Die Dönerstag-Runde des Domili Treffs",
"start_url": "index.php", "start_url": "/",
"scope": "./",
"display": "standalone", "display": "standalone",
"orientation": "portrait",
"theme_color": "#212529", "theme_color": "#212529",
"background_color": "#212529", "background_color": "#212529",
"icons": [ "icons": [
@@ -16,6 +18,17 @@
"src": "img/icon-512.png", "src": "img/icon-512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
},
{
"src": "img/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
} }
] ],
"serviceworker": {
"src": "sw.js",
"scope": "/",
"update_via_cache": "none"
}
} }

65
offline.html Executable file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DoMiLi - Offline</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
body {
padding-top: 60px;
}
.offline-content {
padding: 20px;
text-align: center;
}
.center-content {
display: flex;
justify-content: center;
align-items: center;
min-height: 70vh;
}
</style>
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<a class="navbar-brand d-flex align-items-center" href="index.php">
<img src="img/icon-192.png" alt="Logo" width="32" height="32" class="me-2">
DoMiLi
</a>
</div>
</nav>
<!-- Offline Content -->
<div class="center-content">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-8">
<div class="card">
<div class="card-body p-4">
<div class="text-center mb-4">
<span class="material-icons" style="font-size: 4rem; color: #6c757d;">cloud_off</span>
</div>
<h2 class="text-center mb-3">Keine Internetverbindung</h2>
<p class="text-center text-muted mb-4">
Bitte überprüfe deine Netzwerkverbindung und versuche es erneut.
</p>
<div class="text-center">
<button class="btn btn-primary" onclick="location.reload()">
<span class="material-icons me-1">refresh</span>
Erneut versuchen
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

77
sw.js Executable file
View File

@@ -0,0 +1,77 @@
const CACHE_NAME = 'domili-v' + new Date().getTime();
const urlsToCache = [
'/',
//'/index.php',
//'/login.php',
'/offline.html',
'/css/style.css',
'/img/icon-192.png',
'/img/icon-512.png'
];
// Installation - immer neue Version
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
self.skipWaiting(); // Sofort aktivieren
});
// Aktivierung - alte Caches automatisch löschen
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(name => name !== CACHE_NAME)
.map(name => caches.delete(name))
);
})
);
return self.clients.claim(); // Sofort Kontrolle übernehmen
});
// Fetch mit Network First für PHP, Cache First für statische Dateien
self.addEventListener('fetch', event => {
if (!event.request.url.startsWith('http')) return;
const url = new URL(event.request.url);
// Statische Ressourcen - Cache First
if (url.pathname.endsWith('.css') ||
url.pathname.endsWith('.png') ||
url.pathname.endsWith('.jpg') ||
url.pathname.endsWith('.js')) {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
}
// Dynamische Seiten - Network First mit Offline-Fallback
else {
event.respondWith(
fetch(event.request)
.then(response => {
// Bei erfolgreicher Antwort: in Cache speichern
if (response && response.status === 200) {
const responseToCache = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
}
return response;
})
.catch(() => caches.match('/offline.html'))
);
}
});
// Nachrichten vom Client empfangen
self.addEventListener('message', event => {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});