add PWA support

This commit is contained in:
2026-01-28 10:26:28 +01:00
parent 45e6f2b1ed
commit 10d03fa56b
5 changed files with 101 additions and 3 deletions

BIN
icon-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -2,8 +2,16 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Camera Text Recognition - API Integrated</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Ground Scanner</title>
<!-- PWA -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#06b6d4">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Ground Scanner">
<link rel="apple-touch-icon" href="/icon-192.png">
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"></script>
<style>
* {
@@ -817,6 +825,13 @@
await tesseractWorker.terminate();
}
});
// Register Service Worker for PWA
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then((reg) => console.log('✅ Service Worker registered'))
.catch((err) => console.log('Service Worker registration failed:', err));
}
</script>
</body>
</html>

24
manifest.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "Ground Scanner",
"short_name": "Scanner",
"description": "Scan text to discover European hotspots",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#0f172a",
"theme_color": "#06b6d4",
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}

59
sw.js Normal file
View File

@@ -0,0 +1,59 @@
const CACHE_NAME = 'ground-scanner-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/manifest.json',
'/icon-192.png',
'/icon-512.png'
];
// Install - cache assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(ASSETS_TO_CACHE);
})
);
self.skipWaiting();
});
// Activate - clean old 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();
});
// Fetch - network first, fallback to cache
self.addEventListener('fetch', (event) => {
// Skip non-GET requests
if (event.request.method !== 'GET') return;
// Skip API calls (always fetch from network)
if (event.request.url.includes('api.hotspots.fabio.ovh')) return;
event.respondWith(
fetch(event.request)
.then((response) => {
// Clone and cache successful responses
if (response.status === 200) {
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
}
return response;
})
.catch(() => {
// Fallback to cache
return caches.match(event.request);
})
);
});