PWA foundation: manifest, service worker, install prompt - #16
Merged
Conversation
Sets up Parachute Lens as an installable Progressive Web App: - manifest.json with sage-palette theme + background colors, standalone display, 192/512/maskable icons generated from a single icon.svg via @vite-pwa/assets-generator - Service worker via vite-plugin-pwa (Workbox): precaches the app shell, falls back to /index.html for SPA navigations, and denies that fallback for /api/, /oauth/, /.well-known/ so vault + OAuth requests error cleanly offline. Google Fonts use StaleWhileRevalidate - registerType "prompt": subtle UpdateBanner lets the user choose when to reload instead of force-reloading - InstallPrompt captures beforeinstallprompt, shows an Install button in the header when available, and falls back to an iOS Add to Home Screen hint dialog for Safari - Icons: clean sage rounded-square with a lens-aperture glyph (circle in circle), no font dependency, readable at 64px - README: Install Parachute Lens section at the top with desktop, Android, and iOS instructions plus iOS storage-quota caveats Out of scope for this PR (coming in v0.2): offline data, voice capture, Scribe integration. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First PR of the v0.2 offline-capable PWA arc. Makes Parachute Lens installable and sets up the service worker foundation that later PRs build on.
id,name,short_name,description,theme_color(#4a7c59),background_color(#faf8f4),display: standalone,start_url: /,scope: /public/icon.svg(sage rounded-square + lens-aperture glyph) rasterized via@vite-pwa/assets-generatorinto 64/192/512, apple-touch-icon-180, maskable 512, favicon. Maskable padding 0.2 + sage fill so Android adaptive crops don't eat the glyphvite-plugin-pwawith Workbox.registerType: "prompt"so users choose when to reload.navigateFallback: /index.htmlgives the SPA an offline shell.navigateFallbackDenylist: [/^\/api\//, /^\/oauth\//, /^\/\.well-known\//]keeps vault + OAuth + discovery requests passing through cleanly so they error loudly offline rather than getting a stale HTML fallback. Google Fonts useStaleWhileRevalidate<output role="status">with Later / Reload when a new SW is waiting; also checks for updates hourly while openbeforeinstallprompt, shows an Install app button in the header when the browser offers installability; hidden once installed. iOS fallback:<dialog>with Share → Add to Home Screen instructionsiOS quirks named in this PR
beforeinstallpromptevent on iOS — install is manual via the Share sheet, so Lens surfaces instructions instead of a buttonOut of scope (later in v0.2)
Gates
bun run lint— biome cleanbun run typecheck— tsc cleanbun run test— 189 passed (30 files)bun run build—dist/sw.js,dist/workbox-*.js, manifest.webmanifest, 21 precache entries (1411 KiB)New test surface:
src/lib/pwa.test.ts— isIOS (iPhone, iPad, iPadOS-on-Mac-UA, desktop Chrome, Android); isStandalone (display-mode media, navigator.standalone, regular tab)src/components/InstallPrompt.test.tsx— hidden when standalone; hidden before event; shows button + callsprompt(); iOS dialog fallbacksrc/components/UpdateBanner.test.tsx— smoke test for the default needRefresh=false pathsrc/pwa-manifest.test.ts— required installability fields; 192/512 icons; maskable present; JSON-serializableTo keep the manifest testable, it's extracted to
src/pwa-manifest.tsand imported by bothvite.config.tsand the test. The virtualvirtual:pwa-register/reactmodule is aliased to a vitest stub so components using it can render under jsdom.Surprises / Calls
ontouchendon document, so a naive "Mac UA + has touch" check flagged desktop Chrome as iOS.isIOSnow takes an explicithasTouchparameter (defaulting tonavigator.maxTouchPoints > 1), which is both easier to test and more accurate than theontouchendprobe/api/,/oauth/, and/.well-known/from the nav fallback and omitted runtimeCaching for them. Workbox's default passthrough is NetworkOnly, so this yields the same behavior with less configTest plan
dist/, visit in desktop Chrome, confirm Install button appears and installs the app🤖 Generated with Claude Code