Make the app an installable PWA with phone layout and Web Push

Add a generated manifest, icon set, offline page and service worker that never caches authenticated HTML, plus install and update UI. Turn the rail into a drawer below md with container-query internals, dvh and safe-area handling, and reconnect the socket after visibility/network changes. Add Web Push subscriptions, presence-aware delivery, notification settings and tests.
This commit is contained in:
2026-10-19 17:12:16 +01:00
parent 61098a114c
commit dbfe48796b
100 changed files with 3573 additions and 117 deletions
+77
View File
@@ -0,0 +1,77 @@
import { SiteData } from "./site-data";
/**
* What makes the app installable, shared by the pages that advertise it,
* the server that serves it and the script that generates it.
*/
export const PwaStartPath = "/admin/bots";
export const PwaScope = "/";
export const PwaManifestPath = "/manifest.webmanifest";
export const PwaServiceWorkerPath = "/sw.js";
export const PwaOfflinePath = "/offline.html";
export type PwaIcon = {
src: string;
sizes: string;
type: string;
purpose: "any" | "maskable";
};
/**
* Generated from `public/logos/logo.svg` by `bun run gen:favicon`.
*/
export const PwaIcons: PwaIcon[] = [
{
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/maskable-192.png",
sizes: "192x192",
type: "image/png",
purpose: "maskable",
},
{
src: "/icons/maskable-512.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
];
export type PwaShortcut = {
name: string;
url: string;
icons: { src: string; sizes: string; type: string }[];
};
export const PwaShortcuts: PwaShortcut[] = [
{
name: "Routines",
url: "/admin/routines",
icons: [{ src: "/icons/icon-192.png", sizes: "192x192", type: "image/png" }],
},
{
name: "Help",
url: "/admin/help",
icons: [{ src: "/icons/icon-192.png", sizes: "192x192", type: "image/png" }],
},
];
export const PwaIconPath = (name: `icon` | `maskable`, size: number) =>
`/icons/${name}-${size}.png`;
/**
* The app's install name: `SiteName` is lowercase, `PwaShortName` fits
* under an icon.
*/
export const PwaManifestName = SiteData["SiteName"];
export const PwaShortName = SiteData["SiteName"];