feat: installable PWA (manifest, icons, minimal service worker)
- public/manifest.webmanifest with any + maskable icons (192/512) - generated inbox-glyph icons in app palette, apple-touch-icon - minimal no-cache service worker for installability; registered via client plugin - head: manifest/icon links, mobile-web-app-capable Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,4 +9,5 @@ node_modules/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
*.png
|
*.png
|
||||||
|
!public/icons/*.png
|
||||||
.claude/
|
.claude/
|
||||||
|
|||||||
6
app/plugins/pwa.client.ts
Normal file
6
app/plugins/pwa.client.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default defineNuxtPlugin(() => {
|
||||||
|
if (!("serviceWorker" in navigator)) return;
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
navigator.serviceWorker.register("/sw.js").catch(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,11 +23,15 @@ export default defineNuxtConfig({
|
|||||||
{ name: "color-scheme", content: "light dark" },
|
{ name: "color-scheme", content: "light dark" },
|
||||||
{ name: "theme-color", media: "(prefers-color-scheme: light)", content: "#f4f1ea" },
|
{ name: "theme-color", media: "(prefers-color-scheme: light)", content: "#f4f1ea" },
|
||||||
{ name: "theme-color", media: "(prefers-color-scheme: dark)", content: "#181410" },
|
{ name: "theme-color", media: "(prefers-color-scheme: dark)", content: "#181410" },
|
||||||
|
{ name: "mobile-web-app-capable", content: "yes" },
|
||||||
{ name: "apple-mobile-web-app-capable", content: "yes" },
|
{ name: "apple-mobile-web-app-capable", content: "yes" },
|
||||||
{ name: "apple-mobile-web-app-status-bar-style", content: "default" },
|
{ name: "apple-mobile-web-app-status-bar-style", content: "default" },
|
||||||
{ name: "apple-mobile-web-app-title", content: "ClaudeDo" },
|
{ name: "apple-mobile-web-app-title", content: "ClaudeDo" },
|
||||||
],
|
],
|
||||||
link: [
|
link: [
|
||||||
|
{ rel: "manifest", href: "/manifest.webmanifest" },
|
||||||
|
{ rel: "apple-touch-icon", href: "/icons/apple-touch-icon.png" },
|
||||||
|
{ rel: "icon", type: "image/png", sizes: "192x192", href: "/icons/icon-192.png" },
|
||||||
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
||||||
{ rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: "" },
|
{ rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: "" },
|
||||||
{
|
{
|
||||||
|
|||||||
BIN
public/icons/apple-touch-icon.png
Normal file
BIN
public/icons/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/icons/icon-192.png
Normal file
BIN
public/icons/icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/icons/icon-512.png
Normal file
BIN
public/icons/icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
public/icons/icon-maskable-192.png
Normal file
BIN
public/icons/icon-maskable-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/icons/icon-maskable-512.png
Normal file
BIN
public/icons/icon-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
17
public/manifest.webmanifest
Normal file
17
public/manifest.webmanifest
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"id": "/",
|
||||||
|
"name": "ClaudeDo Inbox",
|
||||||
|
"short_name": "ClaudeDo",
|
||||||
|
"description": "Task inbox for the ClaudeDo backlog",
|
||||||
|
"start_url": "/",
|
||||||
|
"scope": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#181410",
|
||||||
|
"theme_color": "#181410",
|
||||||
|
"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-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
|
||||||
|
{ "src": "/icons/icon-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
||||||
|
]
|
||||||
|
}
|
||||||
6
public/sw.js
Normal file
6
public/sw.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Minimal service worker: enables PWA installability across browsers.
|
||||||
|
// Intentionally no caching — the app is a private, auth-gated SPA and stale
|
||||||
|
// assets after a deploy are worse than requiring a connection.
|
||||||
|
self.addEventListener("install", () => self.skipWaiting());
|
||||||
|
self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
|
||||||
|
self.addEventListener("fetch", () => {});
|
||||||
Reference in New Issue
Block a user