/* ── Shared notification dropdown module ──────────────────────────── */ (function() { let _notifOpen = false; let _sse = null; function renderNotifDrop(data) { const drop = document.getElementById('notif-drop'); const badge = document.getElementById('notif-badge'); if (!drop || !badge) return; if (data.unread > 0) { badge.textContent = data.unread > 9 ? '9+' : data.unread; badge.style.display = ''; } else badge.style.display = 'none'; drop.innerHTML = `
Уведомления ${data.unread > 0 ? `` : ''}
${data.notifications.length ? data.notifications.map(n => `
${LS.esc(n.message)}
${LS.fmtRelTime(n.created_at)}
`).join('') : '
Уведомлений нет
'}`; } async function load() { try { renderNotifDrop(await LS.getNotifications()); } catch {} } function toggle() { const drop = document.getElementById('notif-drop'); if (!drop) return; _notifOpen = !_notifOpen; if (_notifOpen) { const btn = document.getElementById('notif-btn'); if (btn) { const r = btn.getBoundingClientRect(); const vh = window.innerHeight; // Anchor bottom of dropdown to button bottom, but don't go above viewport const bottom = vh - r.bottom; drop.style.top = 'auto'; drop.style.bottom = Math.max(8, bottom) + 'px'; drop.style.left = (r.right + 8) + 'px'; } drop.style.display = 'block'; load(); } else { drop.style.display = 'none'; } } async function clickNotif(e, id, link) { e.preventDefault(); await LS.markNotifRead(id).catch(() => {}); await load(); if (link && link !== '#') window.location.href = link; } async function markAllRead() { await LS.markAllNotifsRead().catch(() => {}); await load(); } let _inited = false; function init() { if (_inited) return; _inited = true; // Note: button already has onclick="LS.notif.toggle()" in HTML // Close on outside click document.addEventListener('click', e => { const drop = document.getElementById('notif-drop'); if (!drop || !_notifOpen) return; if (!e.target.closest('#notif-drop') && !e.target.closest('#notif-btn')) { _notifOpen = false; drop.style.display = 'none'; } }); // SSE real-time _sse = LS.connectSSE(ev => { if (ev.type) load(); }); // Initial load load(); } // Expose as LS.notif window.LS = window.LS || {}; LS.notif = { init, toggle, load, click: clickNotif, markAllRead }; })();