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

@@ -52,7 +52,7 @@ import { useTheme } from '@/providers/ThemeProvider'
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
import { useZap } from '@/providers/ZapProvider'
import storage from '@/services/local-storage.service'
import storage, { dispatchSettingsChanged } from '@/services/local-storage.service'
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
import { disconnect, launchModal } from '@getalby/bitcoin-connect-react'
import {
@@ -77,7 +77,7 @@ import {
Wallet
} from 'lucide-react'
import { kinds } from 'nostr-tools'
import { forwardRef, HTMLProps, useCallback, useRef, useState } from 'react'
import { forwardRef, HTMLProps, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
type TEmojiTab = 'my-packs' | 'explore'
@@ -106,7 +106,6 @@ export default function Settings() {
const [copiedNsec, setCopiedNsec] = useState(false)
const [copiedNcryptsec, setCopiedNcryptsec] = useState(false)
const [openSection, setOpenSection] = useState<string>('')
const accordionRef = useRef<HTMLDivElement>(null)
// General settings
const [language, setLanguage] = useState<TLanguage>(i18n.language as TLanguage)
@@ -162,29 +161,16 @@ export default function Settings() {
}
const handleAccordionChange = useCallback((value: string) => {
// Prevent auto-scroll when opening accordion sections
const scrollY = window.scrollY
setOpenSection(value)
if (value) {
// Scroll the opened section into view
setTimeout(() => {
const item = accordionRef.current?.querySelector(`[data-state="open"]`)
if (item) {
const rect = item.getBoundingClientRect()
const scrollContainer = accordionRef.current?.closest('[data-radix-scroll-area-viewport]') || window
if (scrollContainer === window) {
const scrollTop = window.scrollY + rect.top - 16
window.scrollTo({ top: scrollTop, behavior: 'smooth' })
} else {
const containerRect = (scrollContainer as HTMLElement).getBoundingClientRect()
const scrollTop = (scrollContainer as HTMLElement).scrollTop + rect.top - containerRect.top - 16
;(scrollContainer as HTMLElement).scrollTo({ top: scrollTop, behavior: 'smooth' })
}
}
}, 50)
}
requestAnimationFrame(() => {
window.scrollTo(0, scrollY)
})
}, [])
return (
<div ref={accordionRef}>
<div>
<Accordion
type="single"
collapsible
@@ -573,6 +559,7 @@ export default function Settings() {
onCheckedChange={(checked) => {
storage.setFilterOutOnionRelays(checked)
setFilterOutOnionRelays(checked)
dispatchSettingsChanged()
}}
/>
</SettingItem>