feat(phase 3j pwa): manifest + service worker + icons → installable PWA
- web/static/manifest.webmanifest: name/short_name/start_url=/dashboard/ display=standalone/theme_color/background_color + three icons (192, 512, 512-maskable with ~12% safe-zone padding) - web/static/sw.js: minimal SW — install caches /static/* shell assets, fetch is network-first with cache fallback on GETs only, skips /mcp/ and non-GETs entirely. CACHE_NAME versioned for clean activate-time prune. - cmd/icongen: stdlib-only generator that produces the three PNG icons from a stylised "p" monogram. Run once at brand-change, commit output. - web.init() registers .webmanifest → application/manifest+json with mime.AddExtensionType so Chrome accepts the manifest at all - layout.tmpl + login.tmpl: manifest link, apple-touch-icon, theme-color, apple-mobile-web-app-* metas, inline SW-register on load (silent on failure — older browsers still work) - design.md gets §"PWA install (Phase 3j)"; CLAUDE.md "Out of scope" drops the Phase-3j line and adds push/background-sync as the remaining Otto-PWA territory - 4 new tests cover manifest MIME, sw.js delivery, all 3 icons, layout meta tags
This commit is contained in:
@@ -442,11 +442,40 @@ Pure CSS + minimal template tweaks make every projax page legible and tappable o
|
||||
|
||||
**Out of scope:**
|
||||
|
||||
- Native PWA install (manifest.json + service worker) — Phase 3j candidate.
|
||||
- Push notifications (Otto-PWA's domain).
|
||||
- Dark mode toggle.
|
||||
- Right-to-left layout.
|
||||
|
||||
## PWA install (Phase 3j)
|
||||
|
||||
projax is now installable as a real PWA — iOS Safari "Add to Home Screen" produces a standalone-launching icon and Android Chrome offers the same install flow. Scope is "install affordance," NOT full offline mode.
|
||||
|
||||
**Manifest** (`/static/manifest.webmanifest`, served with `application/manifest+json` via `mime.AddExtensionType` in `web.init`):
|
||||
|
||||
- `name` / `short_name`: "projax"
|
||||
- `start_url`: `/dashboard` (the daily-driver surface m wants on tap)
|
||||
- `scope`: `/`
|
||||
- `display`: `standalone`
|
||||
- `theme_color` / `background_color`: `#1a1a1a` (matches login-page palette)
|
||||
- `icons`: 192×192, 512×512, and a 512×512 maskable variant with ~12% safe-zone padding
|
||||
|
||||
**Icons** (`/static/icon-{192,512,maskable}.png`): stdlib-only generation via `cmd/icongen` — `go run ./cmd/icongen` rewrites them from the source design. Stylised "p" monogram on a dark ground with an accent stripe. Re-run when the brand or palette changes; the PNGs are checked in.
|
||||
|
||||
**Service worker** (`/static/sw.js`):
|
||||
|
||||
- On `install`: pre-cache `/static/style.css` + manifest + icons.
|
||||
- On `activate`: prune stale caches from earlier `CACHE_NAME` versions.
|
||||
- On `fetch` (GET only): network-first with cache fallback on failure. Successful GETs are stashed for the next offline render.
|
||||
- Explicitly skipped: any non-GET request, anything under `/mcp/`.
|
||||
|
||||
This is deliberately the smallest correct service worker. Mutations (CalDAV/Gitea writeback, MCP) require the network; m airplane-modes → he sees the last cached read view but can't change anything until reconnected.
|
||||
|
||||
**Layout meta**: `theme-color`, `apple-mobile-web-app-capable=yes` (iOS treats as standalone), `apple-mobile-web-app-status-bar-style=black-translucent`, `apple-mobile-web-app-title=projax`, plus the `<link rel="manifest">` + `<link rel="apple-touch-icon">` chain. Login template carries the same set so a first-time install from `/login` works the same as from `/dashboard`.
|
||||
|
||||
**Tests**: `TestManifestServedWithCorrectMIME`, `TestServiceWorkerServed`, `TestIconsServed`, `TestLayoutHasManifestAndAppleTouchIcon`.
|
||||
|
||||
**Out of scope for 3j**: push notifications, background sync, full offline write mode, splash-screen tuning.
|
||||
|
||||
## 9. Phase-1 deliverable checklist
|
||||
|
||||
- [ ] `projax.items` + `projax.item_links` migrations in `db/migrations/`
|
||||
|
||||
Reference in New Issue
Block a user