feat: add QR scanner, improve UX, and simplify navigation

- Add live camera QR scanner for nsec/ncryptsec login
- Replace browser prompt() with proper password dialog for ncryptsec
- Add missing /notes/:id route for thread view navigation
- Remove explore section entirely (button, page, routes)
- Remove profile button from bottom nav, avatar now opens profile
- Remove "Notes" tab from feed, default to showing all posts/replies
- Add PasswordPromptProvider for secure password input
- Add SidebarDrawer for mobile navigation
- Add domain layer with value objects and adapters
- Various UI and navigation improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mleku
2025-12-28 04:00:16 +02:00
parent 6a7bfe0a3e
commit 2aa0a8c460
187 changed files with 42378 additions and 1454 deletions

View File

@@ -1,66 +0,0 @@
import { ISigner, TDraftEvent } from '@/types'
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
import { generateSecretKey } from 'nostr-tools'
import { BunkerSigner as NBunkerSigner, parseBunkerInput } from 'nostr-tools/nip46'
export class BunkerSigner implements ISigner {
signer: NBunkerSigner | null = null
private clientSecretKey: Uint8Array
private pubkey: string | null = null
constructor(clientSecretKey?: string) {
this.clientSecretKey = clientSecretKey ? hexToBytes(clientSecretKey) : generateSecretKey()
}
async login(bunker: string, isInitialConnection = true): Promise<string> {
const bunkerPointer = await parseBunkerInput(bunker)
if (!bunkerPointer) {
throw new Error('Invalid bunker')
}
this.signer = NBunkerSigner.fromBunker(this.clientSecretKey, bunkerPointer, {
onauth: (url) => {
window.open(url, '_blank')
}
})
if (isInitialConnection) {
await this.signer.connect()
}
return await this.signer.getPublicKey()
}
async getPublicKey() {
if (!this.signer) {
throw new Error('Not logged in')
}
if (!this.pubkey) {
this.pubkey = await this.signer.getPublicKey()
}
return this.pubkey
}
async signEvent(draftEvent: TDraftEvent) {
if (!this.signer) {
throw new Error('Not logged in')
}
return this.signer.signEvent(draftEvent)
}
async nip04Encrypt(pubkey: string, plainText: string) {
if (!this.signer) {
throw new Error('Not logged in')
}
return await this.signer.nip04Encrypt(pubkey, plainText)
}
async nip04Decrypt(pubkey: string, cipherText: string) {
if (!this.signer) {
throw new Error('Not logged in')
}
return await this.signer.nip04Decrypt(pubkey, cipherText)
}
getClientSecretKey() {
return bytesToHex(this.clientSecretKey)
}
}