// Browser notifications for contact messaging (docs/messages.md): the // visitor is notified of admin replies, the admin of new visitor // messages. Permission is requested at one entry point only — right // after the first message of a fresh thread (the Notification API // requires a user gesture). A denied permission is permanent in the // browser, so we never re-ask; a dismissed prompt stays "default" and is // asked again on the next fresh thread. export function askNotifyPermission() { if (!('Notification' in window) || Notification.permission !== 'default') return Notification.requestPermission() } // Fire a notification (a no-op without a granted permission). Clicking // it focuses the site tab and runs onclick (opening the thread/inbox // view), so the user reliably lands on what was new. export function notifyMessage(title, body, onclick) { if (!('Notification' in window) || Notification.permission !== 'granted') return const n = new Notification(title, { body, icon: '/favicon.ico' }) n.onclick = () => { window.focus() onclick?.() n.close() } } // The visible text of a server-rendered strict-markdown message (safe to // parse: the stored html is markdown-it output, never user markup). export function messageText(html) { const div = document.createElement('div') div.innerHTML = html return (div.textContent || '').trim() }