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>
This commit is contained in:
Jure
2026-03-11 20:39:30 +01:00
parent 181233796b
commit 3a196cb9a0
22 changed files with 479 additions and 63 deletions

View File

@@ -8,9 +8,11 @@ interface FeedState {
loading: boolean;
connected: boolean;
error: string | null;
focusedNoteIndex: number;
connect: () => Promise<void>;
loadCachedFeed: () => Promise<void>;
loadFeed: () => Promise<void>;
setFocusedNoteIndex: (n: number) => void;
}
export const useFeedStore = create<FeedState>((set, get) => ({
@@ -18,6 +20,8 @@ export const useFeedStore = create<FeedState>((set, get) => ({
loading: false,
connected: false,
error: null,
focusedNoteIndex: -1,
setFocusedNoteIndex: (n: number) => set({ focusedNoteIndex: n }),
connect: async () => {
try {
@@ -55,7 +59,7 @@ export const useFeedStore = create<FeedState>((set, get) => ({
.sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0))
.slice(0, 200);
set({ notes: merged, loading: false });
set({ notes: merged, loading: false, focusedNoteIndex: -1 });
// Persist fresh notes to SQLite (fire-and-forget)
dbSaveNotes(fresh.map((e) => JSON.stringify(e.rawEvent())));