Offline trip day tracker: app, service worker, manifest, icon
This commit is contained in:
parent
8fa923dd9f
commit
c84cbf6345
4 changed files with 1315 additions and 0 deletions
BIN
icon-512.png
Normal file
BIN
icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
1247
index.html
Normal file
1247
index.html
Normal file
File diff suppressed because it is too large
Load diff
15
manifest.webmanifest
Normal file
15
manifest.webmanifest
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "Business Trip Day Tracker",
|
||||||
|
"short_name": "Trip Log",
|
||||||
|
"description": "Offline day-by-day record of a business trip for tax substantiation.",
|
||||||
|
"start_url": "./index.html",
|
||||||
|
"scope": "./",
|
||||||
|
"display": "standalone",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"background_color": "#0b1220",
|
||||||
|
"theme_color": "#0b1220",
|
||||||
|
"icons": [
|
||||||
|
{ "src": "icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
||||||
|
{ "src": "icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
||||||
|
]
|
||||||
|
}
|
||||||
53
sw.js
Normal file
53
sw.js
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* Business Trip Day Tracker — offline shell.
|
||||||
|
Cache-first on purpose: this app is a static document whose whole point is
|
||||||
|
working in airplane mode, so a stale-by-a-day shell beats a failed load.
|
||||||
|
Bump CACHE when index.html changes; activate() drops every older cache. */
|
||||||
|
var CACHE = "trip-tracker-v3";
|
||||||
|
var ASSETS = ["./", "./index.html", "./manifest.webmanifest", "./icon-512.png"];
|
||||||
|
|
||||||
|
self.addEventListener("install", function(e){
|
||||||
|
e.waitUntil(
|
||||||
|
caches.open(CACHE).then(function(c){
|
||||||
|
/* addAll is all-or-nothing; one 404 would leave us with no offline copy
|
||||||
|
at all, so fetch them individually and keep whatever succeeds. */
|
||||||
|
return Promise.all(ASSETS.map(function(u){
|
||||||
|
return fetch(u, {cache:"reload"})
|
||||||
|
.then(function(r){ if(r && r.ok) return c.put(u, r); })
|
||||||
|
.catch(function(){});
|
||||||
|
}));
|
||||||
|
}).then(function(){ return self.skipWaiting(); })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener("activate", function(e){
|
||||||
|
e.waitUntil(
|
||||||
|
caches.keys().then(function(keys){
|
||||||
|
return Promise.all(keys.map(function(k){
|
||||||
|
return k === CACHE ? null : caches.delete(k);
|
||||||
|
}));
|
||||||
|
}).then(function(){ return self.clients.claim(); })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener("fetch", function(e){
|
||||||
|
var req = e.request;
|
||||||
|
if(req.method !== "GET") return;
|
||||||
|
if(new URL(req.url).origin !== self.location.origin) return;
|
||||||
|
|
||||||
|
e.respondWith(
|
||||||
|
caches.match(req, {ignoreSearch:true}).then(function(hit){
|
||||||
|
if(hit) return hit;
|
||||||
|
return fetch(req).then(function(res){
|
||||||
|
if(res && res.ok){
|
||||||
|
var copy = res.clone();
|
||||||
|
caches.open(CACHE).then(function(c){ c.put(req, copy); });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}).catch(function(){
|
||||||
|
/* Offline and not cached — a navigation still gets the app shell. */
|
||||||
|
if(req.mode === "navigate") return caches.match("./index.html");
|
||||||
|
throw new Error("offline");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue