- 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>
- Rust: store_nsec / load_nsec / delete_nsec Tauri commands via keyring crate
(macOS Keychain, Windows Credential Manager, Linux Secret Service)
- On nsec login: key is stored in OS keychain keyed by hex pubkey
- On startup: restoreSession() auto-loads nsec from keychain and re-establishes
the NDK signer — no manual re-login required after restart
- On logout: keychain entry is deleted
- Graceful degradation: if keychain is unavailable (e.g. Linux without a Secret
Service daemon), the app starts logged-out — same UX as before, no crash
Also updates ROADMAP.md with 4 new items from the Windows playtest (multi-account
switcher, NWC wizard, system tray, zap history view) and reorders the list.
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>
- 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>
- 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>
- 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>
- 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