async function loadLayout() { let me = null; try { me = await GET("/auth/me"); } catch { me = null; } if (!me) { if (!location.pathname.startsWith("/login")) location.href = "/login"; return null; } const sb = el("aside", { class: "sidebar", id: "sidebar" }); sb.append(el("div", { class: "brand" }, el("span", { class: "brand-badge", html: 'Ravan Mailer' }), el("span", { class: "brand-name" }, "Ravan Mailer"))); const nav = el("nav", {}); for (const item of NAV) { if (item.section) { nav.append(el("div", { class: "nav-section" }, item.section)); continue; } const active = location.pathname === item.href || (item.href !== "/" && location.pathname.startsWith(item.href)); nav.append(el("a", { class: "nav-link" + (active ? " active" : ""), href: item.href }, el("span", { class: "ico" }, item.ico), item.label)); } sb.append(nav); const foot = el("div", { class: "foot" }, el("div", { class: "user-line" }, "👤 ", me.email || "user"), el("button", { class: "btn sm secondary block mt-1", onclick: doLogout }, "Sign out")); sb.append(foot); const old = $("#sidebar"); if (old) old.remove(); document.body.prepend(sb); // scrim for mobile let scrim = $("#scrim"); if (!scrim) { scrim = el("div", { id: "scrim", onclick: () => { $("#sidebar").classList.remove("open"); scrim.classList.remove("show"); } }); document.body.append(scrim); } const mb = $("#menuBtn"); if (mb) mb.addEventListener("click", () => { $("#sidebar").classList.toggle("open"); scrim.classList.toggle("show"); }); // page-specific boot if (window.pageBoot) window.pageBoot(me); return me; } async function doLogout() { try { await POST("/auth/logout"); } catch {} location.href = "/login"; } document.addEventListener("DOMContentLoaded", loadLayout);