From a92893e596652c5280e90ac03cfda6586cfd98ea Mon Sep 17 00:00:00 2001 From: Automation Date: Sun, 24 May 2026 20:39:56 +0200 Subject: [PATCH] feat(pwa): enhanced manifest + push notification support - Enhanced PWA manifest with screenshots, categories, standalone display - Service worker push notification support with VAPID-compatible events - Notification click handling: focus existing tab or open new one - Better mobile experience with proper display mode --- public/sw.js | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/app/manifest.ts | 31 ++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/public/sw.js b/public/sw.js index 2d3e2261d16..d24f9c6ec66 100644 --- a/public/sw.js +++ b/public/sw.js @@ -89,3 +89,55 @@ self.addEventListener("fetch", (event) => { })() ); }); + +// ── Push Notifications ─────────────────────────────────────────────────────── + +self.addEventListener("push", (event) => { + let data; + try { + data = event.data ? event.data.json() : {}; + } catch { + data = { title: "OmniRoute", body: event.data?.text() || "New notification" }; + } + + const title = data.title || "OmniRoute"; + const options = { + body: data.body || "", + icon: data.icon || "/icon-512.png", + badge: data.badge || "/icon-192.png", + tag: data.tag || "omniroute-default", + data: { + url: data.url || "/dashboard", + timestamp: Date.now(), + }, + vibrate: [200, 100, 200], + requireInteraction: true, + }; + + event.waitUntil(self.registration.showNotification(title, options)); +}); + +// ── Notification Click ─────────────────────────────────────────────────────── + +self.addEventListener("notificationclick", (event) => { + event.notification.close(); + + const urlToOpen = event.notification.data?.url || "/dashboard"; + + event.waitUntil( + clients.matchAll({ type: "window", includeUncontrolled: true }).then((clientsList) => { + for (const client of clientsList) { + if (client.url.includes(self.location.origin) && "focus" in client) { + client.focus(); + if ("navigate" in client) { + client.navigate(urlToOpen); + } + return; + } + } + if (clients.openWindow) { + return clients.openWindow(urlToOpen); + } + }), + ); +}); diff --git a/src/app/manifest.ts b/src/app/manifest.ts index 66c767a6a4e..48f0578a010 100644 --- a/src/app/manifest.ts +++ b/src/app/manifest.ts @@ -2,28 +2,53 @@ import type { MetadataRoute } from "next"; export default function manifest(): MetadataRoute.Manifest { return { - name: "OmniRoute", + name: "OmniRoute AI Gateway", short_name: "OmniRoute", description: "OmniRoute is an AI gateway for multi-provider LLMs. One endpoint for all your AI providers.", - start_url: "/", + start_url: "/dashboard", scope: "/", - display: "fullscreen", + display: "standalone", orientation: "any", background_color: "#0b0f1a", theme_color: "#0b0f1a", + categories: ["developer-tools", "productivity", "utilities"], + lang: "en", + dir: "ltr", + prefer_related_applications: false, icons: [ + { + src: "/icon-192.png", + sizes: "192x192", + type: "image/png", + purpose: "any", + }, { src: "/icon-512.png", sizes: "512x512", type: "image/png", purpose: "any maskable", }, + { + src: "/icon-512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, { src: "/apple-touch-icon.png", sizes: "180x180", type: "image/png", }, ], + screenshots: [ + { + src: "/screenshots/dashboard.png", + sizes: "1280x720", + type: "image/png", + form_factor: "wide", + label: "OmniRoute Dashboard", + }, + ], }; }