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