- New 'about' view wired into sidebar nav (♥ support) and App.tsx
- Sections: in-app zap button (reuses ZapModal + NWC infra), Lightning
address QR + copy, Bitcoin address QR + copy, Ko-fi link, GitHub link,
version/tech credits footer
- QR codes rendered as SVG via react-qr-code (no canvas dependency)
- lightning: URI and bitcoin: URI formats for wallet-scannable QR codes
- Tasteful and non-nagging — lives in the nav, never pops up unprompted
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rust: rusqlite (bundled) with WAL mode; wrystr.db in app data dir
- db_save_notes: upsert batch of raw event JSON, prune to 500 kind-1 notes
- db_load_feed: return N most-recent kind-1 raws for instant startup display
- db_save_profile / db_load_profile: cache NDKUserProfile JSON by pubkey
- Falls back to in-memory SQLite if the on-disk open fails
- src/lib/db.ts: typed invoke wrappers; all errors silenced (cache is best-effort)
- feed store: loadCachedFeed() populates notes before relay connects;
loadFeed() merges fresh+cached (so relay returning fewer notes doesn't
erase cached ones), then saves fresh notes to SQLite
- useProfile: reads SQLite cache to show avatar/name instantly while
relay request is in-flight; saves result to SQLite after relay responds
- Feed: calls loadCachedFeed() first → notes visible before relay connects
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SavedAccount list persisted in localStorage (wrystr_accounts)
- loginWithNsec / loginWithPubkey now upsert into the accounts list
- fetchOwnProfile caches name + picture into the account entry
- switchAccount: loads nsec from OS keychain, falls back to read-only
- removeAccount: deletes keychain entry + removes from list; logs out
if it was the active account
- logout: clears active session only — keychain entries kept for instant
switch-back
- AccountSwitcher component in sidebar footer: shows current account,
expand (▼/▲) to list all saved accounts, click to switch instantly,
× to remove, "+ add account" opens LoginModal, sign-out / remove
account actions inline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Mention clicks (nostr:npub1, nostr:nprofile) open internal ProfileView
- njump.me links intercepted: npub/nprofile decoded and opened internally,
note/nevent/naddr fall through to browser (no reader yet)
- Hashtag clicks navigate to SearchView and auto-run the search
- openSearch(query) action added to UIStore; pendingSearch consumed on mount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ProfileView: own profile now reads from user store directly instead of
useProfile() hook, which only re-fetches on pubkey change — so the bio/
name/avatar updates immediately after saving without needing to navigate away
- ROADMAP: added items from playtest feedback:
- About/funding page (Bitcoin QR, Lightning, zap dev npub, Ko-fi/GitHub)
- Mute/ignore user + anti-spam settings + WOT brainstorm note
- Quote/repost (NIP-18)
- Sidebar auto-hide + clearer collapse affordance
- Profile helpers for newcomers (NIP-05, image upload)
- Search improvements (NIP-50 relay detection, people search fallback)
- UI/look & feel deferred until after Windows playtest
- Long-form reading experience as a brainstorm session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ArticleEditor: annotate map callback parameter as string
- ui.ts: prefix unused get parameter with _ to silence noUnusedLocals
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ComposeBox, action row (reply/like/zap), and write article button
all gated on getNDK().signer in addition to loggedIn
- Prevents read-only (npub-only) users from seeing actions they can't use
- Found during browser testing of the login path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- OnboardingFlow replaces app layout on first visit (no wrystr_pubkey in localStorage)
- Welcome screen: plain-language explanation of Nostr/keys, two paths
- Create path: NDKPrivateKeySigner.generate(), show npub with copy button
- Backup step: show nsec with danger styling, copy button, checkbox confirmation
required before proceeding — login happens only after user confirms backup
- Login path: existing nsec or read-only npub, back button to welcome
- On complete: normal app layout shown; pubkey in localStorage acts as the flag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- searchNotes: NIP-50 full-text for text queries, #t tag filter for #hashtags
- searchUsers: NIP-50 kind 0 search for people
- SearchView with tabbed notes/people results, follow/unfollow inline
- Hashtag queries skip people search and use universal #t filter
- Graceful empty state explains NIP-50 relay support caveat
- Search added to sidebar nav (⌕)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- addRelay / removeRelay in nostr lib; relay list persisted to localStorage
- getNDK() seeds from localStorage instead of hardcoded list
- Settings > Relays: list with status dots, remove on hover, add with validation
- Settings > Identity: npub display with one-click copy
- Removed local umbrel relay from defaults (was a dev artifact)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fetchReactionCount (kind 7 #e filter) in nostr lib
- useReactionCount hook with module-level cache to avoid refetching
- NoteCard shows count next to like button; increments optimistically on like
- Falls back to "like"/"liked" text when count is zero or still loading
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- publishContactList (kind 3) in nostr lib — replaces full follow list on each change
- follow() and unfollow() actions in user store with optimistic UI update
- Follow/Unfollow button in ProfileView header (visible when logged in, not own profile)
- Button shows "unfollow" in muted style with danger hover when already following
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Invalidate the in-memory profile cache for the user's pubkey after
publishing a new kind 0 event, so the updated profile reflects immediately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ProfileView shows edit form when viewing own profile
- publishProfile (kind 0) added to nostr lib
- Sidebar name/avatar opens own profile
- Back button in edit mode cancels form; outside edit mode navigates back
- goBack safeguard: falls back to feed if previousView === currentView
- Fix ThreadView crash when selectedNote is null
- Tighten feed filter for base64 blobs and protocol messages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Click note content to open thread view
- ThreadView shows root note, reply composer, and replies
- fetchReplies added to nostr lib (kind 1 #e filter)
- UI store gains openThread, goBack, previousView for navigation history
- Profile back button now returns to previous view correctly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Following tab in feed header (visible when logged in)
- Fetches kind 1 notes from followed pubkeys via NDK
- fetchFollows on login using NDK user.follows()
- fetchFollowFeed added to nostr lib
- Liked note IDs persisted in localStorage so likes survive refresh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ProfileView shows avatar, bio, nip05, website, recent notes
- Clicking any name or avatar navigates to their profile
- Add fetchUserNotes to nostr lib (kind 1 by author)
- Add openProfile action + selectedPubkey to UI store
- Back button returns to feed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Tailwind CSS + Zustand + NDK installed and configured
- Sidebar with feed/relays/settings navigation
- Global feed view with live notes from relays
- Profile fetching with caching and deduplication
- Relay connection with timeout handling
- Note cards with avatar, name, timestamp, content
- Dark theme, monospace, no-slop UI
- Devtools enabled for debugging