From 34b58b863758895d97eeadc82ddaa90ae7d93b42 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Tue, 1 Sep 2026 23:20:31 +0200 Subject: [PATCH] refactor(hephaestus): wallet picker is an accordion, not a page swap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking Create / Import / WizardConnect now expands the flow *inside* that option (native
/) instead of hiding the picker and rendering a separate view. Opening one option auto-closes the others. Chevron flips and border turns accent-orange on the open card. "Back" buttons removed โ€” closing is a click on the same summary. - wallet.js: renderTabs() emits three
; the per-option flow content is populated lazily on first `toggle` and lives inside `.wallet-flow` (no more global #panel). Accordion behavior is enforced by closing sibling
on toggle. - login.css: .wallet-opt reworked as details-summary card; chevron rotates on [open]; .wallet-flow is the divider-topped body inside each card. --- auth-proxy/public/login.css | 45 +++++------ auth-proxy/public/wallet.js | 144 +++++++++++++++++------------------- 2 files changed, 92 insertions(+), 97 deletions(-) diff --git a/auth-proxy/public/login.css b/auth-proxy/public/login.css index 73ced3c..6ca10f2 100644 --- a/auth-proxy/public/login.css +++ b/auth-proxy/public/login.css @@ -36,44 +36,45 @@ h2 { font-size: 17px; margin: 0 0 6px; } p.lede { color: var(--muted); margin: 0 0 20px; font-size: 14px; } p.sub { color: var(--muted); margin: 0 0 12px; font-size: 13.5px; } -/* --- Wallet picker (three big options โ€” Create / Import / Connect) --- */ +/* --- Wallet picker: accordion of three options (Create / Import / Connect) --- */ .wallet-picker { display: grid; gap: 10px; margin: 8px 0 18px; } -.wallet-opt { - display: grid; grid-template-columns: 40px 1fr; gap: 14px; align-items: start; - padding: 14px 16px; background: var(--bg); border: 1px solid var(--border); - border-radius: 10px; cursor: pointer; text-align: left; font: inherit; color: var(--text); - transition: border-color .1s, background .1s; +details.wallet-opt { + background: var(--bg); border: 1px solid var(--border); border-radius: 10px; + overflow: hidden; transition: border-color .1s, background .1s; } -.wallet-opt:hover { border-color: var(--accent); background: var(--card); } +details.wallet-opt:hover { border-color: var(--accent); } +details.wallet-opt[open] { border-color: var(--accent); background: var(--card); } +details.wallet-opt > summary { + display: grid; grid-template-columns: 40px 1fr auto; gap: 14px; align-items: start; + padding: 14px 16px; cursor: pointer; list-style: none; user-select: none; +} +details.wallet-opt > summary::-webkit-details-marker { display: none; } +details.wallet-opt > summary::marker { content: ""; } .wallet-opt .ico { font-size: 24px; line-height: 1; padding-top: 2px; } -.wallet-opt .body { display: flex; flex-direction: column; gap: 4px; } +.wallet-opt .body { display: flex; flex-direction: column; gap: 4px; min-width: 0; } .wallet-opt b { color: var(--text); font-size: 14.5px; font-weight: 600; - display: inline-flex; align-items: center; gap: 8px; } + display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; } .wallet-opt .sub { color: var(--muted); font-size: 13px; line-height: 1.5; } .wallet-opt .pill { display: inline-block; font-size: 10.5px; padding: 1px 8px; border-radius: 999px; background: rgba(255,140,0,.14); color: var(--accent); font-weight: 500; letter-spacing: 0.02em; text-transform: lowercase; } +.wallet-opt .chev { + color: var(--muted); font-size: 14px; padding-top: 4px; + transition: transform .15s ease; +} +details.wallet-opt[open] > summary .chev { transform: rotate(180deg); color: var(--accent); } p.fine { color: var(--muted); font-size: 12.5px; margin: 4px 0 0; text-align: center; } p.fine a { color: var(--muted); } p.fine a:hover { color: var(--text); } -/* --- Selected flow panel (Create/Import/Connect) --- */ -.flow { display: flex; flex-direction: column; gap: 4px; } -.flow > label { margin-top: 12px; } -.flow .row { - display: flex; gap: 10px; margin-top: 18px; align-items: center; -} -.flow .row .primary { flex: 1; margin-top: 0; } -.flow .row .ghost { - background: transparent; border: 1px solid var(--border); color: var(--muted); - padding: 10px 14px; border-radius: 8px; font: inherit; font-size: 13.5px; - cursor: pointer; -} -.flow .row .ghost:hover { color: var(--text); border-color: var(--muted); } +/* --- Expanded flow inside a wallet-opt --- */ +.wallet-flow { padding: 0 16px 16px 16px; border-top: 1px solid var(--border); } +.wallet-flow .flow { display: flex; flex-direction: column; gap: 4px; padding-top: 12px; } +.wallet-flow .flow > label { margin-top: 12px; } /* --- WizardConnect coming-soon panel --- */ .wc-supported { display: grid; gap: 8px; margin: 8px 0 14px; } diff --git a/auth-proxy/public/wallet.js b/auth-proxy/public/wallet.js index d8a2919..c516d66 100644 --- a/auth-proxy/public/wallet.js +++ b/auth-proxy/public/wallet.js @@ -159,115 +159,109 @@ function renderTabs() {

Sign in with your Bitcoin Cash wallet

No email. No password reset. Your wallet is your identity.

- - - +
+ + โœจ + + Create a new walleteasiest + Made here in your browser. You get a recovery phrase to write down โ€” it is the only key. + + + +
+
+
+ + ๐Ÿ”‘ + + Import / add a wallet + Restore a wallet you already have from its 12- or 24-word recovery phrase. + + + +
+
+
+ + ๐Ÿช„ + + Connect a wallet โ€” WizardConnectmost private + Cashonize 0.9+ or Paytaca. Your keys never leave your wallet. + + + +
+

Prefer old-school? Sign in with username & password โ†’

-
`)); - app.querySelectorAll(".wallet-opt").forEach((b) => { - b.addEventListener("click", () => { - // Hide the picker while a specific panel is open - app.querySelector("#picker").classList.add("hidden"); - app.querySelector(".fine")?.classList.add("hidden"); - renderPanel(b.dataset.choice); + app.querySelectorAll("details.wallet-opt").forEach((d) => { + d.addEventListener("toggle", () => { + if (!d.open) return; + // Accordion: close siblings + app.querySelectorAll("details.wallet-opt").forEach((other) => { + if (other !== d) other.open = false; + }); + // Lazily populate this option's flow content the first time it opens + const flow = d.querySelector(".wallet-flow"); + if (flow && !flow.dataset.ready) { + populateFlow(d.dataset.choice, flow); + flow.dataset.ready = "1"; + } }); }); } -function backToPicker() { - app.querySelector("#picker")?.classList.remove("hidden"); - app.querySelector(".fine")?.classList.remove("hidden"); - const panel = document.getElementById("panel"); - if (panel) panel.innerHTML = ""; -} - -function renderPanel(kind) { - const panel = document.getElementById("panel"); - panel.innerHTML = ""; +function populateFlow(kind, flow) { if (kind === "create") { const mnemonic = generateBip39Mnemonic(); - panel.appendChild(el(` + flow.appendChild(el(`
-

Your new recovery phrase

-

Write it down. This is the only way to recover your account โ€” we can never help you reset it.

+

Your new recovery phrase. Write it down. This is the only way to recover your account โ€” we can never help you reset it.

${mnemonic}
- +

The passphrase never leaves your device. Lose both phrase and passphrase = account is gone.

-
- - -
- + +
`)); - panel.querySelector("#back").addEventListener("click", backToPicker); - panel.querySelector("#go").addEventListener("click", async () => { - const pw = panel.querySelector("#pw").value; - if (pw.length < 8) return showErr(panel, "passphrase must be at least 8 chars"); - await onboardAndLogin(mnemonic, pw, panel); + flow.querySelector(".go").addEventListener("click", async () => { + const pw = flow.querySelector(".pw").value; + if (pw.length < 8) return showErr(flow, "passphrase must be at least 8 chars"); + await onboardAndLogin(mnemonic, pw, flow); }); } else if (kind === "import") { - panel.appendChild(el(` + flow.appendChild(el(`
-

Import a wallet

Paste your BIP-39 recovery phrase (12 or 24 words). Same phrase = same account.

- + - -
- - -
- + + +
`)); - panel.querySelector("#back").addEventListener("click", backToPicker); - panel.querySelector("#go").addEventListener("click", async () => { - const mn = panel.querySelector("#mn").value.trim().replace(/\s+/g, " "); - const pw = panel.querySelector("#pw").value; - if (pw.length < 8) return showErr(panel, "passphrase must be at least 8 chars"); + flow.querySelector(".go").addEventListener("click", async () => { + const mn = flow.querySelector(".mn").value.trim().replace(/\s+/g, " "); + const pw = flow.querySelector(".pw").value; + if (pw.length < 8) return showErr(flow, "passphrase must be at least 8 chars"); try { await keypairFromMnemonic(mn); } - catch { return showErr(panel, "invalid recovery phrase"); } - await onboardAndLogin(mn, pw, panel); + catch { return showErr(flow, "invalid recovery phrase"); } + await onboardAndLogin(mn, pw, flow); }); } else if (kind === "connect") { - panel.appendChild(el(` + flow.appendChild(el(`
-

Connect a wallet

Sign the challenge with an external BCH wallet โ€” your keys never leave it. Encrypted end-to-end over Nostr; the relay only sees ciphertext.

Cashonizebrowser extension ยท v0.9+install โ†’
Paytacamobile ยท iOS + Androidinstall โ†’
-

Coming soon. WizardConnect for message-signing is being wired in โ€” for now, use Create or Import above (or the button below to jump back to the picker).

-
- -
+

Coming soon. WizardConnect for message-signing is being wired in โ€” for now, use Create or Import above.

`)); - panel.querySelector("#back").addEventListener("click", backToPicker); } }