// Transforms the "🔑 Sign in" nav pill on every Sirius.X page into a wallet // dropdown. Reads siriusProfile from localStorage; when null shows the three // onboarding actions (New wallet / Import a phrase / WizardConnect), when // present shows the signed-in menu (address, My names, Admin, Sign out). // // Each onboarding action deep-links portal.html?mode=new|import|wc; portal.html // picks that up and immediately runs the matching flow — no extra click on // arrival. Signed-in state changes flip the button label without a reload: // the storage event covers cross-tab, a custom 'siriusProfileChanged' event // covers same-tab (portal.html and tld.html both dispatch it on write/clear). (() => { const anchor = document.querySelector(".topnav a.portal"); if (!anchor) return; // Base URL for local links — the nav's brand link is already set with the // right relative path per page (./ at root, ../ in subdirs). Reuse it so // absolute /sirius-x/... paths (which break under the BCNR route) never // slip in. const PORTAL_URL = anchor.getAttribute("href") || "./portal.html"; const BASE = PORTAL_URL.replace(/portal\.html.*$/, ""); const ADMIN_URL = BASE + "admin/"; const readProfile = () => { try { return JSON.parse(localStorage.getItem("siriusProfile") || "null"); } catch { return null; } }; // Build wrapper + button + (empty) menu around the existing pill. const wrap = document.createElement("div"); wrap.className = "profile-wrap"; const btn = document.createElement("button"); btn.type = "button"; btn.className = anchor.className; // reuse .portal (and .here if present) btn.setAttribute("aria-haspopup", "menu"); btn.setAttribute("aria-expanded", "false"); const menu = document.createElement("div"); menu.className = "profile-menu"; menu.setAttribute("role", "menu"); menu.hidden = true; // ---------- render ---------- // Re-renders the button label AND the menu innerHTML from the current // profile in localStorage. Called at load, on every open(), and whenever // another tab or this tab updates the storage key. function render() { const p = readProfile(); if (p) { const dot = ``; const label = shortAddr(p.address); const sourceBadge = p.source === "wc" ? `WC` : `seed`; btn.innerHTML = `${dot}${escapeAttr(label)}${sourceBadge}`; btn.setAttribute("aria-label", `Wallet ${label}, signed in via ${p.source || "seed"}`); menu.innerHTML = `
Signed in via ${escapeAttr(p.source === "wc" ? "WizardConnect" : "seed phrase")} ${escapeAttr(p.address)}
📋 My namesrecords & holdings 🛠 Admin paneloperator tools
🚪 Sign outclear this browser `; } else { const dot = ``; btn.innerHTML = `${dot}Wallet`; btn.setAttribute("aria-label", "Wallet — not signed in"); // Each item deep-links to portal.html?mode=X — portal auto-runs the // matching flow the moment it loads. No extra clicks on arrival. menu.innerHTML = `
No wallet yet Sign in to see your names
🆕 New walletgenerate a fresh 12-word phrase 📥 Import a phraseseed you already have 🔗 WizardConnectCashonize / Paytaca via QR `; } } render(); // ---------- open/close ---------- const open = () => { render(); menu.hidden = false; btn.setAttribute("aria-expanded", "true"); }; const close = () => { menu.hidden = true; btn.setAttribute("aria-expanded", "false"); }; btn.addEventListener("click", (e) => { e.stopPropagation(); menu.hidden ? open() : close(); }); document.addEventListener("click", (e) => { if (!wrap.contains(e.target)) close(); }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") close(); }); // Cross-tab (storage event fires only in other tabs) + same-tab (portal.html // dispatches this after writing/clearing) — either wakes render(). window.addEventListener("storage", (e) => { if (e.key === "siriusProfile") render(); }); window.addEventListener("siriusProfileChanged", render); // ---------- sign-out ---------- menu.addEventListener("click", (e) => { const t = e.target.closest("[data-action]"); if (t?.dataset.action === "signout") { e.preventDefault(); try { localStorage.removeItem("siriusProfile"); } catch {} window.dispatchEvent(new Event("siriusProfileChanged")); // Reload so any signed-in section on the current page (portal, tld) also resets. location.reload(); } }); wrap.appendChild(btn); wrap.appendChild(menu); anchor.replaceWith(wrap); // ---------- inline CSS ---------- if (!document.getElementById("profile-menu-css")) { const s = document.createElement("style"); s.id = "profile-menu-css"; s.textContent = ` .topnav .profile-wrap{position:relative;margin-left:auto} .topnav .profile-wrap button.portal{ display:inline-flex;align-items:center;gap:8px; cursor:pointer;font-family:inherit;font-size:13.5px;font-weight:500; padding:6px 12px 6px 10px;border-radius:999px; background:rgba(214,255,61,.10);color:var(--acid); border:1px solid rgba(214,255,61,.22);transition:background .1s,border-color .1s } .topnav .profile-wrap button.portal:hover{background:rgba(214,255,61,.16);border-color:rgba(214,255,61,.35)} .topnav .profile-wrap button.portal[aria-expanded="true"]{background:rgba(214,255,61,.20)} .topnav .profile-wrap .wallet-dot{ width:7px;height:7px;border-radius:50%;background:rgba(139,152,169,.45); box-shadow:0 0 0 2px rgba(139,152,169,.10) } .topnav .profile-wrap .wallet-dot.ok{ background:#4fd1a5;box-shadow:0 0 0 2px rgba(79,209,165,.20) } .topnav .profile-wrap .wallet-label{font-family:ui-monospace,monospace;font-size:12.5px;letter-spacing:.2px} .topnav .profile-wrap .wallet-src{ font-size:9.5px;font-weight:700;letter-spacing:.6px;text-transform:uppercase; padding:2px 6px;border-radius:4px;background:rgba(214,255,61,.15);color:var(--acid); margin-left:2px } .topnav .profile-wrap .wallet-caret{opacity:.6;font-size:11px;margin-left:2px} .topnav .profile-menu{ position:absolute;right:0;top:calc(100% + 8px); min-width:280px;z-index:30; background:rgba(18,24,34,.98);backdrop-filter:blur(12px); border:1px solid rgba(255,255,255,.12);border-radius:14px; padding:8px;display:flex;flex-direction:column;gap:2px; box-shadow:0 12px 40px rgba(0,0,0,.55),0 0 0 1px rgba(0,0,0,.4) } .topnav .profile-menu[hidden]{display:none} .topnav .profile-menu > a{ display:grid;grid-template-columns:24px 1fr;gap:12px;align-items:center; padding:9px 11px;border-radius:9px; color:#e7eaf1;text-decoration:none;transition:background .08s } .topnav .profile-menu > a:hover{background:rgba(214,255,61,.10)} .topnav .profile-menu > a:hover .mi-ic{filter:brightness(1.2)} .topnav .profile-menu .mi-ic{font-size:17px;line-height:1;text-align:center} .topnav .profile-menu .mi-body{display:flex;flex-direction:column;gap:1px;font-size:13.5px;font-weight:600;color:#e7eaf1} .topnav .profile-menu .mi-hint{font-weight:400;font-size:11.5px;color:#8b98a9;letter-spacing:.1px} .topnav .profile-menu hr{border:0;border-top:1px solid rgba(255,255,255,.08);margin:4px 2px} .topnav .profile-menu .profile-header{ padding:8px 11px 12px;display:flex;flex-direction:column;gap:4px; border-bottom:1px solid rgba(255,255,255,.08);margin-bottom:4px } .topnav .profile-menu .profile-hint{ color:#8b98a9;font-size:11px;text-transform:uppercase;letter-spacing:.4px;font-weight:600 } .topnav .profile-menu .profile-sub{color:#5e6678;font-size:12px} .topnav .profile-menu code{ font-family:ui-monospace,monospace;font-size:11.5px; color:#e7eaf1;word-break:break-all;background:transparent;padding:0;border:0 } `; document.head.appendChild(s); } // ---------- helpers ---------- function shortAddr(a) { if (!a) return "wallet"; const i = a.indexOf(":"); const body = i > 0 ? a.slice(i + 1) : a; return body.slice(0, 6) + "…" + body.slice(-4); } function escapeAttr(s) { return String(s).replace(/[&<>"']/g, (c) => ({"&":"&","<":"<",">":">","\"":""","'":"'"}[c])); } })();