diff --git a/js/register-flow.js b/js/register-flow.js index 58c42d5..28f4c40 100644 --- a/js/register-flow.js +++ b/js/register-flow.js @@ -89,6 +89,76 @@ const sats = (v) => Number(v).toLocaleString("en-US"); #sirius-register-modal .signin-tabs button.active{ color:var(--acid,#d6ff3d);border-bottom-color:var(--acid,#d6ff3d) } + /* Inline-sheet variant: same step content styling as the modal, but + rendered as a normal page section (no fixed positioning, no backdrop, + no shadow). Portal.html uses this so the tabbed sign-in IS the page. */ + .sirius-inline-sheet{ + background:var(--panel,#141a24);border:1px solid var(--line,rgba(255,255,255,.09)); + border-radius:16px;padding:22px 24px;color:var(--ink,#e7eaf1) + } + .sirius-inline-sheet h3{margin:0 0 .2rem;font-size:1.15rem} + .sirius-inline-sheet .sub{color:var(--mut,#8b98a9);font-size:14px;margin:0 0 1.2rem} + .sirius-inline-sheet label{display:block;font-size:13px;color:var(--mut,#8b98a9);margin:14px 0 5px} + .sirius-inline-sheet input[type=text], + .sirius-inline-sheet input[type=password], + .sirius-inline-sheet textarea, + .sirius-inline-sheet select{ + width:100%;padding:11px 13px;border-radius:10px;border:1px solid #ffffff22;background:#0e131b; + color:var(--ink,#e7eaf1);font-size:14px;font-family:inherit;outline:none + } + .sirius-inline-sheet textarea{min-height:76px;resize:vertical;font-family:ui-monospace,monospace;font-size:13px} + .sirius-inline-sheet input:focus,.sirius-inline-sheet textarea:focus{border-color:#4b7bec} + .sirius-inline-sheet .row{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px} + .sirius-inline-sheet .row.end{justify-content:flex-end} + .sirius-inline-sheet .phrase{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px} + .sirius-inline-sheet .phrase span{background:#0e131b;border:1px solid var(--line,rgba(255,255,255,.09)); + border-radius:8px;padding:8px 10px;font-family:ui-monospace,monospace;font-size:13px} + .sirius-inline-sheet .phrase span b{color:var(--dim,#5e6678);font-weight:400;margin-right:6px;font-size:11px} + .sirius-inline-sheet .addr{display:flex;gap:8px;align-items:center;margin-top:8px} + .sirius-inline-sheet .addr code{flex:1;word-break:break-all;background:#0e131b; + border:1px solid var(--line,rgba(255,255,255,.09));border-radius:8px;padding:9px 11px; + font-family:ui-monospace,monospace;font-size:12.5px} + .sirius-inline-sheet .steps-log{margin-top:14px;font-family:ui-monospace,monospace;font-size:12.5px; + color:var(--mut,#8b98a9);background:#0e131b;border:1px solid var(--line,rgba(255,255,255,.09)); + border-radius:10px;padding:12px 14px;max-height:180px;overflow-y:auto} + .sirius-inline-sheet .steps-log div::before{content:"› ";color:var(--acid,#d6ff3d)} + .sirius-inline-sheet .err{color:var(--taken,#f6768a);font-size:13.5px;margin-top:12px} + .sirius-inline-sheet .ok{color:var(--ok,#4fd1a5)} + .sirius-inline-sheet .note{background:var(--panel2,#18202c);border:1px solid var(--line,rgba(255,255,255,.09)); + border-left:3px solid var(--acid,#d6ff3d);border-radius:10px;padding:14px 18px; + color:var(--mut,#8b98a9);font-size:14px;margin-top:1.4rem} + .sirius-inline-sheet .note.warn{border-left-color:var(--warn,#ffc75f)} + .sirius-inline-sheet .note b{color:var(--ink,#e7eaf1)} + .sirius-inline-sheet .mono{background:#0e131b;border:1px solid var(--line,rgba(255,255,255,.09)); + border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:13px} + .sirius-inline-sheet .chk{display:flex;gap:9px;align-items:flex-start;margin-top:14px;font-size:13.5px;color:var(--mut,#8b98a9)} + .sirius-inline-sheet .chk input{margin-top:3px} + .sirius-inline-sheet .signin-tabs{ + display:flex;gap:2px;margin:-6px -8px 18px;padding:0 4px; + border-bottom:1px solid var(--line,rgba(255,255,255,.09));overflow-x:auto + } + .sirius-inline-sheet .signin-tabs button{ + background:none;border:none;color:var(--mut,#8b98a9);font-family:inherit;font-size:13px; + padding:10px 14px;cursor:pointer;border-bottom:2px solid transparent; + white-space:nowrap;letter-spacing:.2px;transition:color .1s,border-color .1s + } + .sirius-inline-sheet .signin-tabs button:hover{color:var(--ink,#e7eaf1)} + .sirius-inline-sheet .signin-tabs button.active{ + color:var(--acid,#d6ff3d);border-bottom-color:var(--acid,#d6ff3d) + } + .sirius-inline-sheet .btn{display:inline-block;text-decoration:none;padding:10px 18px;border-radius:10px; + background:#4b7bec;color:#fff;font-size:14px;border:none;cursor:pointer;font-family:inherit} + .sirius-inline-sheet .btn.ghost{background:transparent;border:1px solid var(--line,rgba(255,255,255,.09));color:var(--ink,#e7eaf1)} + .sirius-inline-sheet .btn.acid{background:var(--acid,#d6ff3d);color:#0b0e14;font-weight:600} + .sirius-inline-sheet .btn:hover{filter:brightness(1.12)} + .sirius-inline-sheet .btn:disabled{opacity:.45;cursor:not-allowed;filter:none} + .sirius-inline-sheet .wopt{display:flex;gap:14px;align-items:flex-start;background:var(--panel2,#18202c); + border:1px solid var(--line,rgba(255,255,255,.09));border-radius:12px;padding:14px 16px;cursor:pointer; + text-align:left;width:100%;color:inherit;font:inherit;margin-top:10px} + .sirius-inline-sheet .wopt:hover{border-color:#4b7bec} + .sirius-inline-sheet .wopt .ic{font-size:22px;line-height:1} + .sirius-inline-sheet .wopt b{display:block;font-size:14.5px} + .sirius-inline-sheet .wopt span{color:var(--mut,#8b98a9);font-size:13px} #sirius-register-modal .btn{display:inline-block;text-decoration:none;padding:10px 18px;border-radius:10px; background:#4b7bec;color:#fff;font-size:14px;border:none;cursor:pointer;font-family:inherit} #sirius-register-modal .btn.ghost{background:transparent;border:1px solid var(--line,rgba(255,255,255,.09));color:var(--ink,#e7eaf1)} @@ -121,18 +191,37 @@ const sats = (v) => Number(v).toLocaleString("en-US"); // signInOnly: when true, the flow is used for wallet onboarding from the nav // dropdown — no name to mint, so instead of walking through Fund/Confirm/ // Register we stop at 'wallet is ready', write siriusProfile, and close. -const state = { name: null, signInOnly: false, wallet: null, session: null, client: null, quote: null, result: null }; +// inlineTarget: when set, the flow renders into that page element instead +// of the modal sheet (portal.html uses this to embed the tabbed sign-in as +// the page's main content). The modal is left closed in inline mode. +const state = { name: null, signInOnly: false, inlineTarget: null, wallet: null, session: null, client: null, quote: null, result: null }; const modal = $("sirius-register-modal"); -const sheet = $("sirius-reg-sheet"); +const modalSheet = $("sirius-reg-sheet"); +// `sheet` is the element the step functions render into — the modal's sheet +// by default, or an inline container when siriusRenderSignInInline() is +// active. `let` so it can be reassigned per call. +let sheet = modalSheet; -function open() { modal.classList.add("open"); } +function open() { + // Inline mode never opens the modal — the sign-in UI lives on the page. + if (state.inlineTarget) return; + modal.classList.add("open"); +} function close() { - modal.classList.remove("open"); + // In inline mode we can't "close" — leave the content in place. State is + // still reset so the next call starts fresh. + if (!state.inlineTarget) modal.classList.remove("open"); if (state.client) { try { state.client.close(); } catch {} state.client = null; } // Keep the WC session alive when signing in — later record edits or TLD // mints will need it; only tear it down for the mint flow. if (state.session && !state.signInOnly) { try { state.session.disconnect(); } catch {} state.session = null; } state.signInOnly = false; + // Restore the modal sheet as the default render target so subsequent + // register/mint flows (which are modal-based) work. + if (state.inlineTarget) { + state.inlineTarget = null; + sheet = modalSheet; + } } // Persist wallet identity so profile-menu.js and any other tab see the @@ -171,6 +260,10 @@ function finishSignIn(w) { $("sirius-reg-close").onclick = close; modal.addEventListener("click", (e) => { if (e.target === modal) close(); }); +// Step functions render into `sheet`, which is reassigned per call by +// renderSignInInline() when the flow is mounted inline on a host page +// (portal.html). Modal by default. Direct write — no separate variable +// needed since `sheet` above is the single mutable target. function render(html) { sheet.innerHTML = html; } // Tab bar for sign-in mode — lets the user jump between the four wallet @@ -193,11 +286,12 @@ function renderTabs(active) { `; } -// Wire tab clicks — event delegation on the sheet so freshly-rendered -// tabs pick up the handler without rewiring per step. Switching away from -// a live WC session tears it down first so we don't leak connections. -sheet.addEventListener("click", async (e) => { - const t = e.target.closest("[data-tab]"); +// Wire tab clicks — document-level delegation so both the modal sheet and +// any inline container hosting the tabs work with one listener. Switching +// away from a live WC session tears it down first so we don't leak +// connections. Guarded to only match .signin-tabs buttons we render. +document.addEventListener("click", async (e) => { + const t = e.target.closest(".signin-tabs [data-tab]"); if (!t) return; const which = t.dataset.tab; if (which !== "wc" && state.session) { @@ -261,10 +355,32 @@ function startSignIn(mode) { else stepWallet(); } +// Sign-in rendered inline on the host page (not in a modal). Pass a target +// element and portal-style tabs + form get painted into it. Used by +// portal.html so the "sign up / sign in" experience IS the page rather than +// an overlay on top of a launcher card. +function renderSignInInline(container, mode = "import") { + if (!container) return; + state.name = "your wallet"; + state.tld = null; + state.signInOnly = true; + state.inlineTarget = container; + sheet = container; + // Give inline container the same visual bones as the modal sheet so the + // step content styling ports 1:1. Kept as a class so host CSS can override. + container.classList.add("sirius-inline-sheet"); + if (mode === "new") stepCreate(); + else if (mode === "import") stepImport(); + else if (mode === "wc") stepExternal(); + else if (mode === "unlock") stepUnlock(); + else stepWallet(); +} + // Public API window.siriusRegisterName = startFlow; window.siriusRegisterTld = startTldFlow; window.siriusSignInWallet = startSignIn; +window.siriusRenderSignInInline = renderSignInInline; // ---------- step 1: wallet choice ---------- function stepWallet() {