feat: implémentation de la PWA avec service worker, manifest et installation

This commit is contained in:
Julien Froidefond
2025-02-12 21:56:22 +01:00
parent 26d4790b0a
commit 0e270b1f01
16 changed files with 807 additions and 8 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,17 +1,103 @@
{
"name": "StripStream",
"short_name": "StripStream",
"description": "A modern web reader for Komga",
"description": "Votre bibliothèque numérique pour lire vos BD, mangas et comics préférés",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#0F172A",
"theme_color": "#4F46E5",
"categories": ["books", "entertainment", "reading"],
"icons": [
{
"src": "/favicon.svg",
"sizes": "32x32",
"type": "image/svg+xml",
"src": "/images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
],
"screenshots": [
{
"src": "/images/screenshots/home.png",
"sizes": "1280x720",
"type": "image/png",
"platform": "wide",
"label": "Page d'accueil de StripStream"
},
{
"src": "/images/screenshots/reader.png",
"sizes": "1280x720",
"type": "image/png",
"platform": "wide",
"label": "Lecteur de BD StripStream"
}
],
"shortcuts": [
{
"name": "Accueil",
"url": "/",
"icons": [
{
"src": "/images/icons/home.png",
"sizes": "96x96",
"type": "image/png"
}
]
},
{
"name": "Bibliothèques",
"url": "/libraries",
"icons": [
{
"src": "/images/icons/library.png",
"sizes": "96x96",
"type": "image/png"
}
]
}
],
"related_applications": [],
"prefer_related_applications": false
}

62
public/offline.html Normal file
View File

@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hors ligne - StripStream</title>
<style>
body {
margin: 0;
padding: 0;
font-family: system-ui, -apple-system, sans-serif;
background-color: #0f172a;
color: #e2e8f0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 1rem;
}
.container {
max-width: 600px;
margin: 0 auto;
}
h1 {
font-size: 2rem;
margin-bottom: 1rem;
color: #4f46e5;
}
p {
font-size: 1.1rem;
line-height: 1.5;
color: #94a3b8;
margin-bottom: 2rem;
}
button {
background-color: #4f46e5;
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
background-color: #4338ca;
}
</style>
</head>
<body>
<div class="container">
<h1>Vous êtes hors ligne</h1>
<p>
Il semble que vous n'ayez pas de connexion internet. Certaines fonctionnalités de
StripStream peuvent ne pas être disponibles en mode hors ligne.
</p>
<button onclick="window.location.reload()">Réessayer</button>
</div>
</body>
</html>

58
public/sw.js Normal file
View File

@@ -0,0 +1,58 @@
const CACHE_NAME = "stripstream-cache-v1";
const OFFLINE_PAGE = "/offline.html";
const STATIC_ASSETS = [
"/",
"/offline.html",
"/manifest.json",
"/favicon.svg",
"/images/icons/icon-192x192.png",
"/images/icons/icon-512x512.png",
];
// Installation du service worker
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(STATIC_ASSETS);
})
);
self.skipWaiting();
});
// Activation et nettoyage des anciens caches
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.filter((name) => name !== CACHE_NAME).map((name) => caches.delete(name))
);
})
);
self.clients.claim();
});
// Stratégie de cache : Network First avec fallback sur le cache
self.addEventListener("fetch", (event) => {
// Ne pas intercepter les requêtes vers l'API
if (event.request.url.includes("/api/")) {
return;
}
event.respondWith(
fetch(event.request)
.then((response) => {
// Mettre en cache la nouvelle réponse
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(async () => {
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(event.request);
return cachedResponse || cache.match(OFFLINE_PAGE);
})
);
});