From c84cbf6345dc0baed2356fff58e2df65dee1da58 Mon Sep 17 00:00:00 2001 From: gator Date: Wed, 9 Sep 2026 14:30:47 +0000 Subject: [PATCH] Offline trip day tracker: app, service worker, manifest, icon --- icon-512.png | Bin 0 -> 3233 bytes index.html | 1247 ++++++++++++++++++++++++++++++++++++++++++ manifest.webmanifest | 15 + sw.js | 53 ++ 4 files changed, 1315 insertions(+) create mode 100644 icon-512.png create mode 100644 index.html create mode 100644 manifest.webmanifest create mode 100644 sw.js diff --git a/icon-512.png b/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..817c09d355806cd67b44b5274841b849650be5e7 GIT binary patch literal 3233 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 sdUDWYfCnf5{SELp$^MU}f + + + + + + + + + + + +Business Trip Day Tracker + + + + +
Saved
+ + +
+
Business Trip Day Tracker
+
Set up your trip to begin
+
+ +
+
+ + +
+ + + +
+ + + + diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 0000000..59cb231 --- /dev/null +++ b/manifest.webmanifest @@ -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" } + ] +} diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..5cfaf16 --- /dev/null +++ b/sw.js @@ -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"); + }); + }) + ); +});