Commit Graph

47 Commits

Author SHA1 Message Date
Jure
b3e7ff7029 Add live feed subscription, timeouts on all relay fetches
Global feed now uses a persistent live subscription (closeOnEose: false)
so new notes stream in real-time instead of requiring manual refresh.
Inspired by Wisp's streaming architecture.

Every fetchEvents call across the entire codebase now uses
fetchWithTimeout with groupable: false — prevents NDK from
batching/reusing stale subscriptions. This fixes Articles, DMs,
Notifications, Zaps, and Trending hanging indefinitely.

Also adds since filters on global (2h) and follow (24h) feeds
to ensure relay freshness, and fixes ArticleFeed re-fetch bug
where follows changes wiped latest tab results.
2026-03-22 11:35:28 +01:00
Jure
2e03c6ce11 Fix relay connectivity: remove aggressive liveness probe, add fetch timeouts
The liveness probe in ensureConnected was causing a death spiral —
it force-disconnected working relays when a 3s probe timed out,
then resetNDK killed new connections before they could establish.

Now ensureConnected trusts relay.connected and only reconnects when
zero relays are connected. All fetchEvents calls have timeouts
(5-10s) so nothing hangs. resetNDK kept as background-only recovery
in the connection monitor after 30s of continuous failure.

Also adds feed diagnostics (feedDiagnostics.ts) for tracking fetch
timing, event freshness, and relay states via console helpers.
2026-03-22 10:42:27 +01:00
Jure
acb0d531c0 Add nested thread trees, recursive reply fetching, multi-level back navigation
Overhauls the thread view from flat single-level replies to proper nested
conversation trees. Fixes NIP-10 tagging (root + reply markers), adds
2-round-trip recursive thread fetch, ancestor chain display, reply-to-any-note
targeting, view stack navigation (up to 20 levels), and loading shimmer.
2026-03-21 15:21:46 +01:00
Jure
04180cf186 Add podcast playback, Fountain.fm cards, V4V streaming, fix notifications
Podcast feature:
- Podcast discovery via Podcast Index API (trending + search)
- Persistent player bar with play/pause, seek, speed (1x/1.5x/2x), volume
- Audio persists across view navigation, resumes from saved position
- Fountain.fm URL detection in feed with rich playable cards
- "Play in Wrystr" button on inline audio blocks
- V4V streaming sats via NWC (LNURL-pay, 5min accumulation, split payments)
- Share what you're listening to (publish note with confirm)
- Space key toggles play/pause globally

Notification fixes:
- Per-notification read tracking (click to mark read) instead of mark-all-on-open
- Read notifications persist at 50% opacity, unread get accent border
- Always fetches last 7 days, keeps 15 most recent
- Filter out own replies from notifications
- Sidebar badge shows only unread count
2026-03-21 12:53:05 +01:00
Jure
80838fb204 Refactor: split overgrown files into focused modules
Split client.ts (1036 lines) into 11 domain modules under lib/nostr/ —
core, notes, social, articles, engagement, dms, bookmarks, muting,
search, relays, trending. Barrel index.ts re-exports all; zero consumer
import changes.

Extract ProfileView sub-components (ImageField, Nip05Field,
EditProfileForm, ProfileMediaGallery), NoteContent renderers
(TextSegments, MediaCards), and NoteCard actions (NoteActions,
InlineReplyBox). All component files now ≤270 lines, all lib files ≤300.
2026-03-20 16:32:50 +01:00
Jure
0bcbba6e8f Bump to v0.8.3 — trending feed, NIP-46 remote signer, media feed, profile media gallery 2026-03-20 12:45:58 +01:00
Jure
57630227e1 Add NIP-05 badges, hashtag pages, keyword muting, suggestion dismissal, notification poller
- Article cover: aspect-video replaces max-h-72 for consistent 16:9
- NIP-05 verification badge on note cards with 1-hour TTL cache
- Dedicated hashtag feed pages (clicking #tag opens live feed, not search)
- Keyword muting: word-boundary matching, applied across all feed views
- Follow suggestion dismissal: persistent "don't suggest again" per person
- Background notification poller (60s): mentions, zaps, new followers
- All notification types independently toggleable in settings
- Centralized notification firing (removed inline store notifications)
2026-03-20 12:09:11 +01:00
Jure
989ed01dfc Add syntax highlighting in code blocks and OS push notifications
Syntax highlighting: shared markdown renderer with highlight.js
(atom-one-dark theme), 12 language grammars registered (JS, TS,
Python, Rust, Go, Bash, JSON, YAML, SQL, CSS, HTML, Markdown).
Applied to both article reader and editor preview.

OS notifications: Tauri notification plugin for mentions, DMs, and
zaps. Per-type toggles in Settings with custom toggle switches.
Fires on new unread mentions/DMs; requests OS permission on first
enable. Notification utility at src/lib/notifications.ts.
2026-03-20 11:11:53 +01:00
Jure
93ca13cc51 Add zen writing mode and auto-save indicator with relay confirmation
Zen mode: fullscreen distraction-free writing via F11 or "zen" button;
hides all chrome, centers content in serif font at 17px, shows only
title + content + word count. Esc/F11 to exit, exits on unmount.

Auto-save indicator: shows "saved Xs ago" in editor header, updates
every 10s. After publishing, shows "published to N relays" confirmation
in green, or warning if zero relays confirmed.
2026-03-20 11:05:05 +01:00
Jure
7ed478eb0e Bump to v0.8.1 — banner height fix, search timeout
Fix profile banner cropping square images (h-36 → h-44 with top-biased
focal point). Fix search hanging forever when no relay supports NIP-50
(8s timeout on fetchEvents in advancedSearch).
2026-03-20 08:46:17 +01:00
Jure
d993ae1131 Bump to v0.8.0 — polish, portability, discovery
Profile banner polish (hero height, click-to-lightbox, avatar overlap),
data export (bookmarks/follows/relays as JSON), relay recommendations
(discover from follows' NIP-65 lists), reading list tracking (read/unread
on bookmarked articles with sidebar badge), trending hashtags (clickable
pills on search idle screen). Updated CLAUDE.md and release notes.
2026-03-19 19:54:14 +01:00
Jure
d257075023 Bump to v0.7.1 — relay health checker, advanced search 2026-03-19 19:23:39 +01:00
Jure
092553ab9b Bump to v0.7.0 — writer tools, NIP-98 uploads, multi-draft, article bookmarks
- NIP-98 HTTP Auth for image uploads with fallback services (void.cat, nostrimg.com)
- Markdown toolbar (bold, italic, heading, link, image, quote, code, list) + Ctrl+B/I/K
- Multi-draft management with draft list, resume, delete, auto-migrate
- Cover image file picker in article meta panel
- Article bookmarks via NIP-51 'a' tags; Notes/Articles tabs in BookmarkView
- Removed Rust upload_file command; dropped reqwest/mime_guess deps
- Upload spinner, draft count badge, empty states
2026-03-18 18:36:08 +01:00
Jure
fbf05e8f90 Bump to v0.6.1 — native file upload, mention names, connection stability
- Native file picker (+) in compose box uploads via Rust backend (reqwest)
- Pasting a local file path auto-uploads instead of inserting text
- @mentions resolve to profile display names via useProfile hook
- Connection indicator uses 15s grace period before showing offline
- Upload uses correct nostr.build v2 API; Rust-side multipart for native picks
- Content parser extracted to src/lib/parsing.ts
2026-03-18 14:55:29 +01:00
Jure
ef189932e6 Bump to v0.6.0 — article discovery, search, profile tab, reader polish
Article discovery feed with Latest/Following tabs, article search
(NIP-50 + hashtag for kind 30023), Notes/Articles tab on profiles,
reading time + bookmark + like buttons on article reader. Event
passed directly from card to reader to avoid relay re-fetch failures.
2026-03-17 21:47:24 +01:00
Jure
8ce1d43d2d Bump to v0.5.0 — note sharing, reply counts 2026-03-15 21:49:52 +01:00
Jure
5b4f6381da Add NIP-17 gift-wrapped DMs, follow-from-menu, fix new conversation crash
DMs now send via NIP-17 (kind 1059 gift-wrap) with self-copy for sent
messages. Receive supports both NIP-17 and legacy NIP-04 for backward
compat. Protocol indicator shown in conversation list and compose footer.

Note card context menu (⋯) now includes follow/unfollow option so users
can follow authors directly from the feed without visiting their profile.

Fix crash (black screen) when starting a new DM conversation — empty
event array caused undefined access on lastEvent.
2026-03-15 21:30:54 +01:00
Jure
c8d2b05440 Bump to v0.4.0 — Phase 3: image lightbox, bookmarks, discover, language filter, UI polish 2026-03-14 18:00:28 +01:00
Jure
3ca73a8b01 Bump to v0.3.0 — instant post/reply feedback
Published notes now appear in the feed immediately. Thread replies
show up without waiting for the relay round-trip. Includes all
v0.2.9 fixes (image paste, sent zaps, reply-to clickable, feed
refresh on login).
2026-03-13 19:40:14 +01:00
Jure
7c10423b4a Show published note in feed immediately after posting 2026-03-13 18:08:40 +01:00
Jure
17304a2432 Fix image upload: use Tauri HTTP plugin to bypass WebView fetch restrictions 2026-03-13 15:44:44 +01:00
Jure
93963de28d Fix sent zaps: query kind 9735 receipts with #P tag instead of ephemeral kind 9734 2026-03-13 11:17:45 +01:00
Jure
3a196cb9a0 Bump to v0.2.0 — Phase 2: Engagement & Reach
Four features shipped in this release:

- Feed reply context: replies show "↩ replying to @name" above the
  note content; clicking fetches and opens the parent thread

- NIP-65 outbox model: fetchUserRelayList + publishRelayList +
  fetchUserNotesNIP65 in client.ts; profile notes fetched via the
  author's write relays; "Publish relay list to Nostr" button in
  Settings (kind 10002)

- Notifications: new store (notifications.ts) + NotificationsView;
  🔔 sidebar nav item with unread badge; DM nav item also shows
  unread conversation count; badges clear on open/select

- Keyboard shortcuts: useKeyboardShortcuts hook + HelpModal;
  n=compose, /=search, j/k=feed nav with ring highlight,
  Esc=back, ?=help overlay

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 20:39:30 +01:00
Jure
fdb7aab9d1 Bump version to v0.1.9 — fix account switch read-only bug (root cause)
Root cause: switchAccount fetched the nsec from the OS keychain on every
switch. Any keychain failure (timeout, Windows Credential Manager quirk,
no entry yet) silently fell through to loginWithPubkey → read-only mode.

Fix: cache each NDKPrivateKeySigner in-memory (_signerCache map) the
moment loginWithNsec succeeds. switchAccount checks the cache first;
the OS keychain is now only consulted at startup (restoreSession). Signers
are pure crypto objects with no session state — safe to reuse indefinitely.

Verified with a 9-switch stress test across 3 accounts (A1→A2→A3→A1→
A2→A1→A3→A2→A1): hasSigner=true and correct pubkey on every switch.

Also adds dev tooling:
- src/lib/tauri-dev-mock.ts: localStorage-backed keychain + SQLite stubs
  so the frontend can run in a plain browser for Playwright testing
- src/main.tsx: import mock first in DEV mode (no-op in production)
- test/gen-accounts.mjs: generates 3 deterministic test keypairs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:11:03 +01:00
Jure
4cde2fe4c7 Add quoted note inline preview (Phase 1 #3)
- fetchNoteById(eventId): fetches a single event by ID
- NoteContent: note1 and nevent1 (kind 1) references now parsed as
  "quote" segment type instead of plain mention text
- QuotePreview component: lazily fetches the referenced note, renders
  a bordered card with author avatar + name + truncated content;
  click navigates to the thread view
- Quote cards rendered as a block below the note text, consistent with
  how images/videos are handled
- naddr1 (kind 30023) and other nevent kinds still open via the
  existing article/njump.me handler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:46:08 +01:00
Jure
af5e04f963 Add zap counts on notes (Phase 1 #2)
- fetchZapCount(eventId): fetches kind 9735 receipts for an event,
  parses millisat amounts from embedded zap request description tags,
  returns { count, totalSats }
- useZapCount hook: session-cached, same pattern as useReactionCount
- NoteCard: zap button shows " N sats" when total > 0, falls back
  to " zap" when no zaps yet; stats row shown for logged-out users
  displaying ♥ and  counts when non-zero

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:43:54 +01:00
Jure
ab7af96c45 Add long-form article reader (Phase 1 #1, NIP-23)
- fetchArticle(naddr): fetches kind 30023 by d-tag + author pubkey
- fetchAuthorArticles(pubkey): for future profile articles tab
- ArticleView: cover image, title, italic summary, author row (avatar +
  name + date), tag pills, full markdown body (DOMPurify sanitized),
  zap author button in header and footer, copy nostr: link, njump.me
  fallback on fetch error
- prose-article CSS: reader-optimised typography (15px base, 1.8 line
  height, h2 border, styled blockquote/code/pre/links/images)
- NoteContent: naddr1 clicks for kind 30023 now open ArticleView
  instead of falling through to njump.me
- openArticle(naddr) added to UI store with previousView tracking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:42:13 +01:00
Jure
6464ba2a79 Add Direct Messages — NIP-04 encrypted DMs (roadmap #13)
Nostr layer:
- fetchDMConversations: fetches all kind-4 events to/from the user
  (both directions in parallel), deduplicates, newest-first
- fetchDMThread: fetches both directions for a specific conversation,
  sorted oldest-first for display
- sendDM: NIP-04 encrypts content via NDK signer, publishes kind 4
- decryptDM: decrypts regardless of direction (ECDH shared secret is
  symmetric — always pass the other party to signer.decrypt)

UI (DMView):
- Two-panel layout: conversation list (w-56) + active thread
- ConvRow: avatar, name, time; shows "🔒 encrypted" preview to avoid
  decrypting the whole inbox on load
- MessageBubble: decrypts lazily on mount; mine right-aligned,
  theirs left-aligned; shows "Could not decrypt" on failure
- ThreadPanel: loads full thread, auto-scrolls to bottom, re-fetches
  after send; Ctrl+Enter to send
- NewConvInput: start a new conversation by pasting an npub1 or hex
  pubkey; validates and resolves before opening thread
- Read-only (npub) accounts see a clear "nsec required" message

Navigation:
- ✉ messages added to sidebar nav
- openDM(pubkey) in UI store → navigates to dm view with pending pubkey
- ProfileView: "✉ message" button in action row opens DM thread

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:29:05 +01:00
Jure
d72dfe56d8 Search improvements — NIP-50 relay detection + smarter zero-results (roadmap #12)
- relayInfo.ts: checkNip50Support fetches NIP-11 relay info (Accept:
  application/nostr+json) and checks supported_nips for 50; results
  cached per session with 4s timeout; getNip50Relays checks all relays
  in parallel

- SearchView: relay NIP-50 support checked on mount in the background
  and shown as context in the idle state ("N of M relays support
  full-text search") and in zero-results states

- Zero results for full-text search now shows:
  - relay NIP-50 count (or "none of your relays support full-text")
  - prominent "Search #<query>" one-click button to retry as hashtag

- Tabs (notes / people) now always rendered after any search, not only
  when both result types are non-empty — makes the UI consistent

- Per-tab zero-results explanations: people tab explains NIP-50
  requirement when no relay supports it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:21:22 +01:00
Jure
abd38a4edd Add profile helpers for newcomers (roadmap #11)
Image upload (ImageField):
- "upload" button next to profile picture and banner URL fields
- Opens native file picker (accept="image/*"), uploads to nostr.build
  free hosting via their v2 API, auto-fills the URL on success
- Shows inline error if upload fails; URL field still editable manually

NIP-05 verification (Nip05Field):
- Replaces the plain nip05 text field
- Debounced live check (900ms): fetches /.well-known/nostr.json?name=...
  and compares the returned pubkey against the logged-in user's pubkey
- Status badges: checking… / ✓ verified / ✗ pubkey mismatch / ✗ not found
- "How to get verified ↗" link to nostr.how guide

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:18:18 +01:00
Jure
16446573c4 Add zap history view (roadmap #9)
- fetchZapsReceived: kind 9735 filtered by #p tag (receipts)
- fetchZapsSent: kind 9734 filtered by authors (zap requests)
- ZapHistoryView: Received / Sent tabs with row count; header shows
  total sats in/out; each row: avatar, amount, counterpart name
  (clickable → profile), comment, time ago
- Receipt parsing: amount from embedded zap request in "description"
  tag (millisats → sats); sender from uppercase "P" tag with fallback
  to zap request pubkey
- Request parsing: amount from "amount" tag, recipient from "p" tag
-  zaps nav item added to sidebar between search and relays
- Logged-out fallback state with prompt to log in

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 19:32:44 +01:00
Jure
0f998eac92 Add Quote / Repost (NIP-18, roadmap #6)
- publishRepost: kind 6 event with stringified original event as content
  and ["e", id, "", "mention"] + ["p", pubkey] tags
- publishQuote: kind 1 note with user's text + appended nostr:nevent1...
  reference and ["q", id] + ["p", pubkey] tags
- QuoteModal: compose modal with live quoted-note preview (avatar, name,
  truncated content); Ctrl+Enter to post, Escape to close
- NoteCard: "repost" (one-click, shows "reposted ✓") and "quote" (opens
  QuoteModal) added to the actions row alongside reply/like/zap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 18:28:59 +01:00
Jure
42fe32f584 Add mute/ignore user + anti-spam (roadmap #5, NIP-51)
- fetchMuteList / publishMuteList in nostr client (kind 10000)
- mute store: mutedPubkeys persisted to localStorage + synced to relay;
  mute/unmute publish kind 10000 best-effort; fetchMuteList merges relay
  list with local mutes on login
- fetchMuteList called after every login (nsec + pubkey)
- Feed: muted pubkeys filtered from both Global and Following tabs
- NoteCard: ⋯ context menu (appears on hover, hidden for own notes)
  with mute / unmute action; backdrop click closes menu
- ProfileView: mute / unmute button in the action row (next to follow)
- SettingsView: MuteSection lists muted accounts with name + avatar;
  hover to reveal unmute button; hidden when mute list is empty

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 18:23:30 +01:00
Jure
e3ba3dbcee Add SQLite note and profile cache (roadmap #3)
- 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>
2026-03-10 17:53:00 +01:00
Jure
8fcabac450 Add zaps: NWC wallet connect + NIP-57 zap flow
- NWC client (nwc.ts): parse URI, encrypt/send kind 23194, await kind 23195 response
- Lightning store: persist NWC URI to localStorage, zap() via NDKZapper + lnPay callback
- ZapModal: amount presets (21/100/500/1000/5000 sats), custom amount, optional comment,
  paying/success/error states, prompts to Settings if no wallet connected
-  zap button on NoteCard (action row) and ProfileView (header, next to follow)
- Settings > Lightning Wallet section: paste NWC URI, connect/disconnect

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 17:45:39 +01:00
Jure
2370fc21f9 Add search view (NIP-50 + hashtag + people)
- 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>
2026-03-09 17:38:54 +01:00
Jure
0a0a00a1b3 Build out Settings view: relay management + identity
- 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>
2026-03-09 17:33:27 +01:00
Jure
d52cfa5f75 Add network reaction counts to note cards
- 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>
2026-03-09 17:31:42 +01:00
Jure
2960e7b279 Add follow/unfollow (NIP-02) from profile view
- 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>
2026-03-09 17:25:34 +01:00
Jure
b465ad03a3 Add editable own profile + navigation fixes
- 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>
2026-03-08 19:19:24 +01:00
Jure
bf1d68bb93 Add long-form article editor (NIP-23)
- ArticleEditor with title, markdown body, summary, cover image, tags
- write/preview toggle with markdown rendering via marked
- Auto-save draft to localStorage
- Publish as kind 30023 with NIP-23 tags (d, title, published_at, etc.)
- 'write article' button in sidebar when logged in
- Article preview prose styles in CSS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:04:43 +01:00
Jure
366731f9d7 Add thread view with replies
- 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>
2026-03-08 18:55:57 +01:00
Jure
30b5bb8d42 Add following feed + persist likes to localStorage
- 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>
2026-03-08 18:52:26 +01:00
Jure
5879a640df Add profile view with clickable names/avatars
- 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>
2026-03-08 18:48:05 +01:00
Jure
5e20e5a128 Compose, reactions, replies + feed filtering
- Add ComposeBox with Ctrl+Enter shortcut and char limit
- Add reply/like actions to NoteCard with inline reply box
- Add publishNote, publishReaction, publishReply to nostr lib
- Filter bot JSON blobs from feed (content starting with { or [)
- Fix sidebar login button always visible (shrink-0 + nav overflow)
- Restore pubkey sessions from localStorage on startup
- Add CLAUDE.md with project guidance
- Add thread view and onboarding notes to AGENTS.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 18:44:04 +01:00
Jure
0b70d25712 Note rendering + login system
- Rich note content parser: clickable links, inline images, videos
- URL shortening for display, trailing punctuation cleanup
- nostr: mention parsing (npub, note, nevent, nprofile)
- Hashtag highlighting
- NIP-05 display on note cards
- Login modal with nsec (full access) and npub (read-only) modes
- User store with Zustand, NDK signer integration
- Sidebar shows logged-in user avatar/name + logout
- Login state persisted via localStorage (pubkey only, never nsec)
2026-03-08 16:53:14 +01:00
Jure
b75ccb7f46 Working feed: NDK + relay connection + live notes from Nostr
- 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
2026-03-08 14:54:04 +01:00