From 7c3b40c963d98fa9aedb6728cba8e858d3735343 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Tue, 28 Apr 2026 22:27:32 +0200 Subject: [PATCH] Add PWA manifest, service worker, and install prompt - manifest.webmanifest: standalone display mode, theme #2563eb, start_url=/app.html (so users who install land in the app shell, not the marketing page), scope=/. Three icons: 192px any-purpose, 512px any-purpose, 512px maskable for adaptive icons on Android. - icons/: PNGs generated from favicon.svg. - sw.js: cache-first for the precached app shell, network-first for /api/* and /auth/* (we never serve stale auth or notes). Versioned cache name (librenotes-shell-v1) so a SW update evicts old assets. skipWaiting + clients.claim so a new SW takes over without a manual reload. - pwa.js: registers the SW on every page and handles beforeinstallprompt by showing #install-btn. Hides the button again on appinstalled. Defer loaded so it never blocks render. - All HTML pages link the manifest, set the theme-color meta, and load pwa.js. Landing page exposes the install button next to the existing CTAs. Closes #19. Co-Authored-By: Claude Opus 4.7 (1M context) --- cmd/librenotes/web/public/app.html | 3 + cmd/librenotes/web/public/icons/icon-192.png | Bin 0 -> 5908 bytes cmd/librenotes/web/public/icons/icon-512.png | Bin 0 -> 29690 bytes .../web/public/icons/icon-maskable.png | Bin 0 -> 22777 bytes cmd/librenotes/web/public/index.html | 4 + cmd/librenotes/web/public/login.html | 3 + .../web/public/manifest.webmanifest | 32 +++++++ cmd/librenotes/web/public/pwa.js | 43 ++++++++++ cmd/librenotes/web/public/sw.js | 80 ++++++++++++++++++ cmd/librenotes/web/public/verify.html | 3 + 10 files changed, 168 insertions(+) create mode 100644 cmd/librenotes/web/public/icons/icon-192.png create mode 100644 cmd/librenotes/web/public/icons/icon-512.png create mode 100644 cmd/librenotes/web/public/icons/icon-maskable.png create mode 100644 cmd/librenotes/web/public/manifest.webmanifest create mode 100644 cmd/librenotes/web/public/pwa.js create mode 100644 cmd/librenotes/web/public/sw.js diff --git a/cmd/librenotes/web/public/app.html b/cmd/librenotes/web/public/app.html index 808d815..7c500d3 100644 --- a/cmd/librenotes/web/public/app.html +++ b/cmd/librenotes/web/public/app.html @@ -5,6 +5,8 @@ Notes — librenotes + + @@ -24,5 +26,6 @@ + diff --git a/cmd/librenotes/web/public/icons/icon-192.png b/cmd/librenotes/web/public/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..cfab37c4f436429519b96cdb8796d7987d89fddb GIT binary patch literal 5908 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 P#|d~Qr}ng52JZiVfyM2= literal 0 HcmV?d00001 diff --git a/cmd/librenotes/web/public/icons/icon-maskable.png b/cmd/librenotes/web/public/icons/icon-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..ca71935d1ab2ded14053ac3255ce31a5846b39d0 GIT binary patch literal 22777 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 literal 0 HcmV?d00001 diff --git a/cmd/librenotes/web/public/index.html b/cmd/librenotes/web/public/index.html index 53b0d2e..a744be5 100644 --- a/cmd/librenotes/web/public/index.html +++ b/cmd/librenotes/web/public/index.html @@ -10,6 +10,8 @@ + + @@ -34,6 +36,7 @@

Sign in with email Self-host it +

@@ -69,5 +72,6 @@

MIT licensed. Built on Notesium.

+ diff --git a/cmd/librenotes/web/public/login.html b/cmd/librenotes/web/public/login.html index ba4ed43..3b747a6 100644 --- a/cmd/librenotes/web/public/login.html +++ b/cmd/librenotes/web/public/login.html @@ -5,6 +5,8 @@ Sign in — librenotes + + @@ -34,5 +36,6 @@ + diff --git a/cmd/librenotes/web/public/manifest.webmanifest b/cmd/librenotes/web/public/manifest.webmanifest new file mode 100644 index 0000000..67bcb3e --- /dev/null +++ b/cmd/librenotes/web/public/manifest.webmanifest @@ -0,0 +1,32 @@ +{ + "name": "librenotes", + "short_name": "librenotes", + "description": "Open-source multi-tenant notes with bi-directional links.", + "start_url": "/app.html", + "scope": "/", + "display": "standalone", + "orientation": "any", + "background_color": "#ffffff", + "theme_color": "#2563eb", + "categories": ["productivity", "utilities"], + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-maskable.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/cmd/librenotes/web/public/pwa.js b/cmd/librenotes/web/public/pwa.js new file mode 100644 index 0000000..3874c9d --- /dev/null +++ b/cmd/librenotes/web/public/pwa.js @@ -0,0 +1,43 @@ +// pwa.js — service worker registration and install prompt. +// +// Loaded on every page. Registers the SW from the root scope so +// it controls the entire site, and surfaces an install button on +// browsers that fire beforeinstallprompt (Chrome / Edge / Android). + +(function () { + "use strict"; + + if ("serviceWorker" in navigator) { + window.addEventListener("load", function () { + navigator.serviceWorker.register("/sw.js", { scope: "/" }) + .catch(function (err) { + console.warn("librenotes: service worker registration failed", err); + }); + }); + } + + let deferredPrompt = null; + + window.addEventListener("beforeinstallprompt", function (ev) { + ev.preventDefault(); + deferredPrompt = ev; + const btn = document.getElementById("install-btn"); + if (btn) { + btn.hidden = false; + btn.addEventListener("click", function () { + if (!deferredPrompt) return; + deferredPrompt.prompt(); + deferredPrompt.userChoice.finally(function () { + deferredPrompt = null; + btn.hidden = true; + }); + }, { once: true }); + } + }); + + window.addEventListener("appinstalled", function () { + const btn = document.getElementById("install-btn"); + if (btn) btn.hidden = true; + deferredPrompt = null; + }); +})(); diff --git a/cmd/librenotes/web/public/sw.js b/cmd/librenotes/web/public/sw.js new file mode 100644 index 0000000..59848cc --- /dev/null +++ b/cmd/librenotes/web/public/sw.js @@ -0,0 +1,80 @@ +// sw.js — librenotes service worker. +// +// Strategy: +// - App shell (HTML/CSS/JS in PRECACHE): cache-first. +// This is what makes the page render offline. +// - API calls (/api/*, /auth/*): network-first. +// We never serve stale auth or stale notes from cache. If the +// network is down, the request fails and the app handles it. +// - Other static assets (icons, manifest): cache-first with +// versioned cache name so a deploy of a new SW evicts old. + +const VERSION = "v1"; +const CACHE = "librenotes-shell-" + VERSION; + +const PRECACHE = [ + "/", + "/index.html", + "/login.html", + "/verify.html", + "/app.html", + "/style.css", + "/auth-client.js", + "/login.js", + "/verify.js", + "/app.js", + "/manifest.webmanifest", + "/favicon.svg", +]; + +self.addEventListener("install", function (ev) { + ev.waitUntil( + caches.open(CACHE).then(function (cache) { + return cache.addAll(PRECACHE); + }) + ); + self.skipWaiting(); +}); + +self.addEventListener("activate", function (ev) { + ev.waitUntil( + caches.keys().then(function (keys) { + return Promise.all( + keys.filter(function (k) { return k !== CACHE; }) + .map(function (k) { return caches.delete(k); }) + ); + }).then(function () { return self.clients.claim(); }) + ); +}); + +self.addEventListener("fetch", function (ev) { + const req = ev.request; + if (req.method !== "GET") return; + + const url = new URL(req.url); + if (url.origin !== self.location.origin) return; + + // Network-first for API and auth endpoints. + if (url.pathname.startsWith("/api/") || url.pathname.startsWith("/auth/")) { + ev.respondWith( + fetch(req).catch(function () { + return new Response("offline", { status: 503, statusText: "offline" }); + }) + ); + return; + } + + // Cache-first for everything else (the app shell). + ev.respondWith( + caches.match(req).then(function (cached) { + if (cached) return cached; + return fetch(req).then(function (resp) { + if (resp && resp.status === 200 && resp.type === "basic") { + const copy = resp.clone(); + caches.open(CACHE).then(function (cache) { cache.put(req, copy); }); + } + return resp; + }); + }) + ); +}); diff --git a/cmd/librenotes/web/public/verify.html b/cmd/librenotes/web/public/verify.html index 832ffe7..1842aad 100644 --- a/cmd/librenotes/web/public/verify.html +++ b/cmd/librenotes/web/public/verify.html @@ -5,6 +5,8 @@ Signing in — librenotes + + @@ -24,5 +26,6 @@ +