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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user