feat: add pwa manifest and service worker
Wire up a production service worker and web app manifest with install metadata and icon assets. Bump project version to 2.1.0 and register the worker from the main page for offline-ready behavior. Made-with: Cursor
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "growing-galaxy",
|
||||
"version": "0.0.1",
|
||||
"version": "2.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "growing-galaxy",
|
||||
"version": "0.0.1",
|
||||
"version": "2.1.0",
|
||||
"dependencies": {
|
||||
"@astrojs/preact": "^4.1.3",
|
||||
"astro": "^5.15.5",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "growing-galaxy",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"version": "2.1.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev --host",
|
||||
"build": "astro build",
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "BSC Score",
|
||||
"short_name": "BSC Score",
|
||||
"description": "Professional pool and billiards scoring application",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#1a1a1a",
|
||||
"theme_color": "#1a1a1a",
|
||||
"lang": "de",
|
||||
"categories": [
|
||||
"sports",
|
||||
"utilities",
|
||||
"productivity"
|
||||
],
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
const CACHE_NAME = 'bscscore-v2.1.0';
|
||||
const APP_SHELL = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/manifest.webmanifest',
|
||||
'/favicon.ico',
|
||||
'/icon-192.png',
|
||||
'/icon-512.png',
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)),
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((keys) =>
|
||||
Promise.all(
|
||||
keys.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
return caches.delete(key);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { request } = event;
|
||||
const requestUrl = new URL(request.url);
|
||||
|
||||
if (request.method !== 'GET' || requestUrl.origin !== self.location.origin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.mode === 'navigate') {
|
||||
event.respondWith(
|
||||
fetch(request)
|
||||
.then((response) => {
|
||||
const responseClone = response.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, responseClone));
|
||||
return response;
|
||||
})
|
||||
.catch(() => caches.match(request).then((cached) => cached || caches.match('/'))),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(request).then((cachedResponse) => {
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
return fetch(request).then((networkResponse) => {
|
||||
const networkClone = networkResponse.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, networkClone));
|
||||
return networkResponse;
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -19,11 +19,14 @@ import App from "../components/App";
|
||||
<meta name="theme-color" content="#1a1a1a">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png">
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="/icon-512.png">
|
||||
<link rel="apple-touch-icon" href="/icon-192.png">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -34,5 +37,14 @@ import App from "../components/App";
|
||||
-->
|
||||
<App client:only="preact" slot="app-content" />
|
||||
</BscScoreApp>
|
||||
<script>
|
||||
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js').catch((error) => {
|
||||
console.error('Service worker registration failed:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user