diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx
index 01437cd..0fd7fbe 100644
--- a/frontend/src/pages/Login.tsx
+++ b/frontend/src/pages/Login.tsx
@@ -1,14 +1,18 @@
-import { Show, createSignal, onCleanup, onMount } from "solid-js"
+import { Show, createSignal, onCleanup } from "solid-js"
import { useNavigate } from "@solidjs/router"
import { ExtensionAccount, NostrConnectAccount, PasswordAccount, PrivateKeyAccount } from "applesauce-accounts/accounts"
import { PasswordSigner } from "applesauce-signers"
import QrScanner from "qr-scanner"
+import QRCode from "qrcode"
import { activateAccount } from "../lib/nostr"
import { PLATFORM_NAME } from "../lib/nostr"
const NIP46_RELAYS = ['wss://bucket.coracle.social', 'wss://ephemeral.snowflare.cc']
type Tab = "nip07" | "nip46" | "key"
+type Screen = "tabs" | "nip46" | "key"
+type SignerTab = "qr" | "paste"
+type KeyTab = "plaintext" | "encrypted"
function normalizeBunkerUrl(value: string): string {
const trimmed = value.trim()
@@ -37,8 +41,12 @@ export default function Login() {
const [tab, setTab] = createSignal(window.nostr ? "nip07" : "nip46")
const [loading, setLoading] = createSignal(false)
const [error, setError] = createSignal("")
+ const [screen, setScreen] = createSignal("tabs")
+ const [signerTab, setSignerTab] = createSignal("qr")
+ const [keyTab, setKeyTab] = createSignal("plaintext")
const [nostrConnectUri, setNostrConnectUri] = createSignal("")
+ const [qrDataUrl, setQrDataUrl] = createSignal("")
const [showScanner, setShowScanner] = createSignal(false)
const [bunkerUrl, setBunkerUrl] = createSignal("")
const [nsecValue, setNsecValue] = createSignal("")
@@ -79,6 +87,7 @@ export default function Login() {
url: window.location.origin,
})
setNostrConnectUri(uri)
+ setQrDataUrl(await QRCode.toDataURL(uri, { width: 256, margin: 2 }))
abortController = new AbortController()
const timeout = window.setTimeout(() => abortController?.abort(), 60_000)
@@ -141,24 +150,25 @@ export default function Login() {
}
}
- async function toggleScanner() {
- const next = !showScanner()
- setShowScanner(next)
- if (!next) {
- scanner?.destroy()
- scanner = undefined
- return
- }
+ function closeScanner() {
+ setShowScanner(false)
+ scanner?.destroy()
+ scanner = undefined
+ }
+ async function openScanner() {
setError("")
+ setShowScanner(true)
+
+ // Wait a tick for the modal video element to mount
+ await new Promise(r => setTimeout(r, 0))
if (!scannerVideo) return
+
scanner = new QrScanner(
scannerVideo,
(result) => {
setBunkerUrl(result.data)
- setShowScanner(false)
- scanner?.destroy()
- scanner = undefined
+ closeScanner()
},
{ returnDetailedScanResult: true },
)
@@ -166,12 +176,21 @@ export default function Login() {
await scanner.start()
} catch (e) {
setError(e instanceof Error ? e.message : "Unable to access camera")
- setShowScanner(false)
- scanner?.destroy()
- scanner = undefined
+ closeScanner()
}
}
+ function enterSignerScreen() {
+ setError("")
+ setScreen("nip46")
+ setSignerTab("qr")
+ if (!nostrConnectUri()) void startNostrConnect()
+ }
+
+ function copyUri() {
+ void navigator.clipboard.writeText(nostrConnectUri())
+ }
+
onCleanup(() => {
abortController?.abort()
scanner?.destroy()
@@ -204,111 +223,187 @@ export default function Login() {
-
Fast access to your relays and invoices.
+
Get fast access to your relays.