Feature/protocol handlers

* Added account selection for protocol links when multiple connected accounts are available, including mailto: links
* Added support for handling mailto: links in an already-open PWA/session instead of always opening a new tab
* Added webcal: protocol handling for calendar links
* Added account selection for webcal: links when multiple calendar-capable accounts are connected
* Added an import-or-subscribe choice for detected webcal calendars
* Added protocol handler settings for registering mail and calendar handlers and choosing the open mode
* Added service worker/session coordination for passing protocol requests between browser/PWA contexts
* Added tests and translations for the new protocol handler flows
This commit is contained in:
Lucas Gaitzsch
2026-05-12 20:49:05 +02:00
committed by Linus Rath
parent 8b0e2052cf
commit 3f444a8912
40 changed files with 2514 additions and 55 deletions
+21 -1
View File
@@ -2,13 +2,26 @@ import type { MetadataRoute } from "next";
export const dynamic = "force-dynamic";
type WebAppProtocolHandler = {
protocol: string;
url: string;
};
type ExtendedManifest = MetadataRoute.Manifest & {
protocol_handlers?: WebAppProtocolHandler[];
launch_handler?: {
client_mode?: "navigate-existing" | "auto" | "focus-existing" | "navigate-new"
| Array<"navigate-existing" | "auto" | "focus-existing" | "navigate-new">;
};
};
// Manifest paths must include the deployment subpath - browsers resolve them
// against the document origin, not the manifest's location, and Next.js does
// not auto-prefix string literals inside MetadataRoute payloads.
const BASE_PATH = (process.env.NEXT_PUBLIC_BASE_PATH ?? "").replace(/\/+$/, "");
const withBase = (p: string) => `${BASE_PATH}${p}`;
export default function manifest(): MetadataRoute.Manifest {
export default function manifest(): ExtendedManifest {
const appName =
process.env.APP_NAME ||
process.env.NEXT_PUBLIC_APP_NAME ||
@@ -57,5 +70,12 @@ export default function manifest(): MetadataRoute.Manifest {
{ src: withBase("/screenshot-540x720.png"), sizes: "540x720", type: "image/png" },
{ src: withBase("/screenshot-1280x720.png"), sizes: "1280x720", type: "image/png" },
],
protocol_handlers: [
{ protocol: "mailto", url: withBase("/protocol/mailto?url=%s") },
{ protocol: "webcal", url: withBase("/protocol/webcal?url=%s") },
],
launch_handler: {
client_mode: ["focus-existing", "navigate-new"],
},
};
}