mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-03 08:15:38 +00:00
Adds useAppBadge alongside the existing useFaviconBadge, mounted from the same FaviconBadge component and gated by the same faviconUnreadBadge setting. Targets the separate icon Chrome/Edge/WebKit show for an installed PWA (taskbar/dock/Home Screen/pinned-app-shortcut), which does not react to favicon changes at all - a merely pinned browser tab is unaffected, only an actually installed app. No unmount cleanup: the badge is scoped to the installed app/origin, not to this component or window, so clearing on every unmount would blank another still-open window's accurate badge. A count of zero or the setting being off already clears it through the main effect.
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { useEmailStore } from "@/stores/email-store";
|
|
import { useSettingsStore } from "@/stores/settings-store";
|
|
import { useFaviconBadge } from "@/hooks/use-favicon-badge";
|
|
import { useAppBadge } from "@/hooks/use-app-badge";
|
|
|
|
/**
|
|
* Badges the browser-tab favicon, and — where supported — the installed PWA's
|
|
* app icon, with the inbox unread count, so new mail is visible without
|
|
* focusing the tab. See issue #560.
|
|
*
|
|
* Two independent mechanisms share the one unread count: `useFaviconBadge`
|
|
* repaints the in-tab favicon (works everywhere); `useAppBadge` calls the
|
|
* Badging API for the separate icon Chrome/Edge pin next to the address bar
|
|
* once the app is installed — Chromium supports it there, WebKit supports it
|
|
* for an iOS/iPadOS Home Screen web app; a silent no-op anywhere else.
|
|
*
|
|
* Both opt out via the single `faviconUnreadBadge` setting (Settings ->
|
|
* Appearance); on by default.
|
|
*
|
|
* Mounted in the root layout rather than on the mail route: the badge belongs
|
|
* to the tab/app, not to a page. Mounting it on the mail page unmounted it —
|
|
* and so cleared the badge, and flickered the icon — on every hop to
|
|
* /settings, /calendar or /contacts.
|
|
*
|
|
* Renders nothing.
|
|
*/
|
|
export function FaviconBadge() {
|
|
// The store's canonical inbox selector. `role === 'inbox'` alone is not
|
|
// enough: shared and group inboxes ship in the same `mailboxes` array, so on
|
|
// a delegated setup the first match can be somebody else's inbox.
|
|
const inboxUnread = useEmailStore(
|
|
(s) => s.mailboxes.find((m) => m.role === "inbox" && !m.isShared)?.unreadEmails ?? 0,
|
|
);
|
|
const enabled = useSettingsStore((s) => s.faviconUnreadBadge);
|
|
|
|
useFaviconBadge(inboxUnread, enabled);
|
|
useAppBadge(inboxUnread, enabled);
|
|
|
|
return null;
|
|
}
|