From 14d993d11a95c5c40a67b553f12f6cc66dd45a49 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Tue, 4 Aug 2026 10:50:58 -0400 Subject: [PATCH] Screen headers with icon back buttons; tidy the sign-in screen Every pre-auth screen (sign in, create, import, recover, extension and bunker flows) opens with a chevron back button beside its title instead of ending with a dangling 'Back' link after the form. The sign-in screen's 'Forgot password? Recover with phrase' shrinks to a right-aligned 'Forgot password?' under the password field -- the recovery screen itself explains the phrase. Back buttons are 36px icon targets with aria-label; the rollback screen's 'Cancel' keeps its explicit wording. Verified in the browser. Co-Authored-By: Claude Fable 5 --- packages/widget/src/element.ts | 38 ++++++++++++++++++++-------------- packages/widget/src/styles.ts | 35 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/packages/widget/src/element.ts b/packages/widget/src/element.ts index 4c0c075..b177d22 100644 --- a/packages/widget/src/element.ts +++ b/packages/widget/src/element.ts @@ -58,6 +58,8 @@ const OPTION_ICONS = { const CHEVRON_DOWN = ``; +const CHEVRON_LEFT = ``; + export class BitLoginAuthElement extends HTMLElement { private root: ShadowRoot; private worker: WorkerClient; @@ -1381,6 +1383,17 @@ export class BitLoginAuthElement extends HTMLElement { }, 1100); } + /** Screen header with an icon back button, replacing the dangling "Back" + * link every pre-auth screen used to end with -- back navigation belongs + * where the eye starts, not after the form. */ + private renderScreenHead(title: string, backAction = "goto-welcome"): string { + return ` +
+ +

${title}

+
`; + } + private renderError(): string { return this.errorMessage ? `
${escapeHtml(this.errorMessage)}
` : ""; } @@ -1439,13 +1452,12 @@ export class BitLoginAuthElement extends HTMLElement { case "extension-confirm": return ` -

Sign in with your extension

+ ${this.renderScreenHead("Sign in with your extension")}

Your Nostr signer extension reports this identity:

${escapeHtml(this.extensionPreviewNpub)}

Check this is the profile you expect — extensions can hold more than one. BitLogin never sees this identity's private key; your extension signs on its behalf. This session lasts until you log out or leave the page, and BitLogin account features (wallet connections, password rotation, recovery) stay with BitLogin accounts.

${this.renderError()} - `; case "bunker-connect": { @@ -1461,7 +1473,7 @@ export class BitLoginAuthElement extends HTMLElement { ? `` : `

Preparing connection code…

`; return ` -

Use a remote signer

+ ${this.renderScreenHead("Use a remote signer")}

Scan with a signer app on your phone (Amber, nsec.app, …). Your key stays in the signer; BitLogin only requests signatures.

${this.renderError()} ${authNotice} @@ -1474,25 +1486,23 @@ export class BitLoginAuthElement extends HTMLElement { ${this.busy ? 'Contacting your signer…' : "Connect"} - `; } case "bunker-confirm": return ` -

Remote signer connected

+ ${this.renderScreenHead("Remote signer connected")}

Your signer reports this identity:

${escapeHtml(this.pendingBunker?.npub ?? "")}

Check this is the profile you expect. Your private key stays in your signer — each signature is requested over relays, and your signer can require approval or be disconnected at any time. This session lasts until you log out or leave the page; BitLogin account features (wallet connections, password rotation, recovery) stay with BitLogin accounts.

${this.renderError()} - `; case "import-key": { const previewed = !!this.importPreviewNpub; return ` -

Import an existing Nostr key

+ ${this.renderScreenHead("Import an existing Nostr key")}

Wrap a Nostr identity you already control in a BitLogin login name and password. Your key never changes — you just get a friendlier way in.

Pasting a private key into any web page is risky. Only do this on a BitLogin build you trust, and clear your clipboard afterward. BitLogin can't secure copies of this key that already exist elsewhere.
${this.renderError()} @@ -1510,13 +1520,12 @@ export class BitLoginAuthElement extends HTMLElement { ` : "" } - `; } case "create-name": return ` -

${this.importKey ? "Set up your login" : "Create your BitLogin"}

+ ${this.renderScreenHead(this.importKey ? "Set up your login" : "Create your BitLogin")}

${ this.importKey ? "Choose a login name for your imported identity. It's a convenience, not a secret." @@ -1528,7 +1537,6 @@ export class BitLoginAuthElement extends HTMLElement { - `; case "create-credential": { @@ -1592,24 +1600,25 @@ export class BitLoginAuthElement extends HTMLElement { case "login": return ` -

Sign in

+ ${this.renderScreenHead("Sign in")} ${this.renderError()}
+
+ +
- - `; case "recover-phrase": return ` -

Recover with phrase

+ ${this.renderScreenHead("Recover with phrase")}

Enter your 12-word BitLogin recovery phrase.

Do not enter a Bitcoin or other cryptocurrency-wallet recovery phrase into BitLogin.

${this.renderError()} @@ -1628,7 +1637,6 @@ export class BitLoginAuthElement extends HTMLElement { ${this.busy ? 'Recovering…' : "Continue"} - `; case "recover-new-credentials": { diff --git a/packages/widget/src/styles.ts b/packages/widget/src/styles.ts index 6c603a8..eb4fab1 100644 --- a/packages/widget/src/styles.ts +++ b/packages/widget/src/styles.ts @@ -205,6 +205,41 @@ button.link { font-size: 13px; } button:focus-visible { outline: 2px solid var(--bl-accent); outline-offset: 2px; } +.screen-head { + display: flex; + align-items: center; + gap: 8px; + margin: 0 0 4px -8px; /* negative left margin optically aligns the chevron with the content edge */ +} +.screen-head h2 { margin: 0; } +.icon-back { + flex: none; + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + margin: 0; + padding: 0; + border: none; + border-radius: 9px; + background: none; + color: var(--bl-muted); +} +.icon-back:hover { background: var(--bl-input-bg); color: var(--bl-fg); } +.icon-back svg { width: 20px; height: 20px; } +/* Right-aligned helper link under an input (e.g. "Forgot password?"). */ +.field-hint { display: flex; justify-content: flex-end; margin-top: 8px; } +.field-hint .link-inline { + width: auto; + margin: 0; + padding: 4px 0; + border: none; + background: none; + color: var(--bl-accent); + font-size: 12.5px; + font-weight: 500; +} /* Collapsed disclosure for every non-primary sign-in path (§LM9.1: the password flow stays the visual headline; alternatives are one tap away). Rows are full-bleed buttons with generous minimum height so the menu works