Files
bitvid/components/login-modal.html
T
google-labs-jules[bot] 6541421928 Fix NIP-46 QR code styling to use tokenized colors and utility classes
Updated `js/ui/loginModalController.js` to resolve QR code colors from CSS variables (`--color-white`, `--color-black`) instead of hardcoding hex values, ensuring compatibility with the design system.
Updated `components/login-modal.html` to use Tailwind utility classes (`bg-white`, `text-black`, `p-6`) instead of inline styles, improving maintainability and readability.
This ensures the QR code remains scannable (high contrast) while respecting the codebase's tokenized styling approach.
2026-01-23 14:49:28 +00:00

421 lines
15 KiB
HTML

<div
id="loginModal"
class="bv-modal hidden p-0 sm:p-0 lg:p-8 lg:items-start lg:justify-center overflow-hidden"
role="dialog"
aria-modal="true"
aria-labelledby="loginModalTitle"
aria-describedby="loginModalDescription"
data-ds="new"
>
<div class="bv-modal-backdrop" data-dismiss></div>
<div
class="modal-sheet w-full h-full max-w-none rounded-none border-0 lg:max-h-modal-shell lg:max-w-5xl lg:rounded-modal-xl lg:border lg:h-auto flex min-h-0 flex-col overflow-hidden"
tabindex="-1"
>
<!-- Header with the special exit button (unchanged) -->
<div class="modal-header">
<h2 id="loginModalTitle" class="text-xl font-bold text-text">
Login Options
</h2>
<button
id="closeLoginModal"
class="modal-close"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<!-- Body -->
<div
id="loginModalDescription"
class="modal-body flex-1 space-y-6 overflow-y-auto"
>
<div class="space-y-2 text-left">
<p class="text-sm text-text-muted">
Choose how you'd like to sign in. Connect a browser extension, link a
remote signer, or work directly with your keys when you need to.
</p>
</div>
<section
class="space-y-5 rounded-3xl border border-border bg-overlay-panel-soft/90 p-4 shadow-lg backdrop-blur-sm sm:p-5"
>
<div class="space-y-1">
<h3 class="text-base font-semibold text-text">Available methods</h3>
<p class="text-sm text-text-muted">
Pick the option that matches how you manage your Nostr identity.
</p>
</div>
<!-- Login provider buttons are rendered dynamically -->
<div
data-login-providers
class="grid auto-rows-fr gap-4 sm:grid-cols-2 xl:grid-cols-3"
></div>
</section>
<div class="space-y-3">
<div class="space-y-1 text-left">
<h3 class="text-sm font-semibold uppercase tracking-wide text-text-muted">
Need an invite?
</h3>
<p class="text-sm text-text-muted">
Submit an application and we'll send you updates when new slots open.
</p>
</div>
<button
id="openApplicationModal"
class="btn w-full"
type="button"
>
Application Form
</button>
</div>
<template data-login-provider-template>
<button
class="login-option"
type="button"
data-provider-button
>
<span class="login-option__header">
<span class="login-option__copy">
<span
data-provider-eyebrow
class="login-option__eyebrow hidden"
></span>
<span data-provider-label class="login-option__label"></span>
<span
data-provider-description
class="login-option__description"
></span>
</span>
<span aria-hidden="true" class="login-option__chevron">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
class="h-5 w-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5l7 7-7 7"
/>
</svg>
</span>
</span>
<div data-provider-status-row class="login-option__status hidden">
<span data-provider-status class="truncate"></span>
<button
type="button"
class="btn-link text-sm hidden"
data-provider-disconnect
>
Disconnect
</button>
</div>
<span
data-provider-capabilities
class="login-option__capabilities hidden"
></span>
</button>
</template>
<template data-login-nsec-dialog>
<form
data-nsec-form
class="space-y-4 rounded-xl border border-border bg-overlay-panel-soft px-5 py-4"
>
<div class="space-y-2">
<h3 class="text-lg font-semibold text-text">Direct key login</h3>
<p class="text-sm text-text-muted" data-nsec-warning>
"Unsafe by default" — imported keys stay decrypted only for this session
unless you protect them with a passphrase.
</p>
</div>
<div
data-nsec-error
class="hidden rounded-lg border border-danger/60 bg-danger/10 px-4 py-2 text-sm text-danger"
role="alert"
></div>
<fieldset data-nsec-unlock-section class="space-y-3 hidden">
<legend class="text-sm font-semibold text-text">Unlock saved key</legend>
<label class="inline-flex items-center gap-2 text-sm text-text">
<input
type="radio"
name="nsec-mode"
value="unlock"
class="radio"
data-nsec-mode="unlock"
/>
<span>Use the encrypted key stored on this device</span>
</label>
<div class="space-y-2 pl-6" data-nsec-unlock-fields>
<label class="block text-sm font-medium text-text" for="nsecUnlockPassphrase">
Passphrase
</label>
<input
id="nsecUnlockPassphrase"
type="password"
class="input"
autocomplete="current-password"
data-nsec-unlock-passphrase
required
/>
</div>
</fieldset>
<fieldset data-nsec-import-section class="space-y-3">
<legend class="text-sm font-semibold text-text">Import a new secret</legend>
<label class="inline-flex items-center gap-2 text-sm text-text">
<input
type="radio"
name="nsec-mode"
value="import"
class="radio"
data-nsec-mode="import"
checked
/>
<span>Paste an nsec, hex key, or mnemonic seed</span>
</label>
<div class="space-y-3 pl-6" data-nsec-import-fields>
<label class="block text-sm font-medium text-text" for="nsecSecretInput">
Secret
</label>
<textarea
id="nsecSecretInput"
class="input"
rows="3"
spellcheck="false"
autocomplete="off"
data-nsec-secret
></textarea>
<label class="inline-flex items-center gap-2 text-sm text-text">
<input type="checkbox" class="checkbox" data-nsec-remember />
<span>Remember this key on this device</span>
</label>
<div class="space-y-2" data-nsec-passphrase-fields hidden>
<label class="block text-sm font-medium text-text" for="nsecPassphraseInput">
Passphrase
</label>
<input
id="nsecPassphraseInput"
type="password"
class="input"
autocomplete="new-password"
data-nsec-passphrase
/>
<label class="block text-sm font-medium text-text" for="nsecPassphraseConfirm">
Confirm passphrase
</label>
<input
id="nsecPassphraseConfirm"
type="password"
class="input"
autocomplete="new-password"
data-nsec-passphrase-confirm
/>
</div>
</div>
</fieldset>
<div class="flex justify-end gap-2">
<button type="button" class="btn-ghost" data-nsec-cancel>Cancel</button>
<button type="submit" class="btn" data-nsec-submit>Continue</button>
</div>
</form>
</template>
<template data-login-generate-dialog>
<div
data-generate-view
class="space-y-4 rounded-xl border border-border bg-overlay-panel-soft px-5 py-4"
>
<div class="space-y-2">
<h3 class="text-lg font-semibold text-text">Create a new Nostr key</h3>
<p class="text-sm text-text-muted">
Save your keys somewhere safe. We'll only enable login after you
confirm you've backed them up.
</p>
</div>
<div class="space-y-3">
<div class="space-y-2">
<label class="block text-sm font-medium text-text">
Public key (npub)
</label>
<div class="space-y-2 sm:flex sm:items-start sm:gap-2 sm:space-y-0">
<div
data-generate-npub
class="min-w-0 flex-1 break-all rounded-lg border border-border bg-overlay-panel px-3 py-2 text-sm text-text"
></div>
<button
type="button"
class="btn-ghost text-sm"
data-generate-copy-npub
>
Copy npub
</button>
</div>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium text-text" for="generatedNsec">
Secret key (nsec)
</label>
<div class="space-y-2 sm:flex sm:items-start sm:gap-2 sm:space-y-0">
<input
id="generatedNsec"
type="password"
class="input min-w-0 flex-1"
readonly
data-generate-nsec
/>
<div class="flex flex-wrap items-center gap-2">
<button
type="button"
class="btn-ghost text-sm"
data-generate-reveal-nsec
>
Reveal
</button>
<button
type="button"
class="btn-ghost text-sm"
data-generate-copy-nsec
>
Copy nsec
</button>
</div>
</div>
</div>
<div>
<button
type="button"
class="btn-link text-sm"
data-generate-download
>
Download backup
</button>
</div>
<label class="inline-flex items-center gap-2 text-sm text-text">
<input type="checkbox" class="checkbox" data-generate-confirm />
<span>I saved these keys and understand they're private.</span>
</label>
</div>
<div class="flex justify-end gap-2">
<button type="button" class="btn-ghost" data-generate-cancel>
Cancel
</button>
<button
type="button"
class="btn"
data-generate-login
disabled
>
Continue
</button>
</div>
</div>
</template>
<template data-login-nip46-dialog>
<form
data-nip46-form
class="space-y-4 rounded-xl border border-border bg-overlay-panel-soft px-5 py-4"
>
<div class="space-y-2">
<h3 class="text-lg font-semibold text-text">Pair a remote signer</h3>
<p class="text-sm text-text-muted">
Scan the QR code with your signer (like Amber or NsecBunker) to login.
</p>
</div>
<div
data-nip46-error
class="hidden rounded-lg border border-danger/60 bg-danger/10 px-4 py-2 text-sm text-danger"
role="alert"
></div>
<div data-nip46-handshake-panel class="space-y-6">
<div class="flex flex-col items-center gap-6">
<div
class="flex aspect-square w-full max-w-xs items-center justify-center rounded-2xl border border-border-strong bg-white text-black p-6 shadow-sm"
data-nip46-qr
aria-hidden="true"
>
<div class="w-full text-center text-sm text-text-muted animate-pulse">
Generating code...
</div>
</div>
<div class="w-full space-y-4 text-center">
<!-- Hidden input for copy functionality -->
<input
type="text"
class="sr-only"
data-nip46-handshake-uri
readonly
aria-hidden="true"
>
<button
type="button"
class="btn w-full sm:max-w-xs"
data-nip46-copy-uri
disabled
>
Copy Connect Link
</button>
<details class="text-sm text-text-muted">
<summary class="cursor-pointer hover:text-text hover:underline">Trouble scanning?</summary>
<div class="mt-2 p-2 bg-overlay-panel border border-border rounded-lg break-all text-xs font-mono text-left select-all" data-nip46-debug-uri>
<!-- Raw URI injected here for debugging/manual copy -->
</div>
</details>
</div>
</div>
</div>
<div
data-nip46-status
class="hidden rounded-lg border border-info/40 bg-info/10 px-4 py-3 text-sm text-info font-medium text-center"
role="status"
></div>
<div
data-nip46-auth
class="hidden rounded-lg border border-warning/50 bg-warning/10 px-4 py-2 text-sm text-warning"
role="alert"
>
<p data-nip46-auth-message class="mb-2"></p>
<button type="button" class="btn-link text-sm" data-nip46-auth-open>
Open signer challenge
</button>
</div>
<div class="flex justify-between items-center pt-2">
<button
type="button"
class="btn-link text-sm hidden"
data-nip46-reuse
>
Reconnect saved
</button>
<button type="button" class="btn-ghost" data-nip46-cancel>Cancel</button>
</div>
<!-- Hidden submit to satisfy form semantics if needed, though we trigger via logic -->
<button type="submit" class="hidden" data-nip46-submit></button>
</form>
</template>
</div>
</div>
</div>