From fc8c3d5ad47821a6d4b1bae4ba520526faac4185 Mon Sep 17 00:00:00 2001 From: highperfocused Date: Sun, 6 Sep 2026 13:37:01 +0200 Subject: [PATCH] feat: local draft notes with a blank "new note" entry point Writing was tied to publishing: the Feed composer either sits empty or fires a note straight to relays, with nowhere to keep something you're not ready to publish yet. The Note app now supports a draft mode when opened without an id: a blank note kept in localStorage until you publish it or discard it, reachable via a new "New note" button in the Feed toolbar, the Go menu, or the command palette (all already open the Note app with no params). Closes #19 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01BYiUtZMQeA5RHggQw73wto --- docs/apps.md | 2 +- src/apps/feed/index.tsx | 13 ++++- src/apps/notes/Draft.tsx | 104 +++++++++++++++++++++++++++++++++++++++ src/apps/notes/index.tsx | 9 ++-- 4 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 src/apps/notes/Draft.tsx diff --git a/docs/apps.md b/docs/apps.md index 6cc09bf..677cbd4 100644 --- a/docs/apps.md +++ b/docs/apps.md @@ -95,7 +95,7 @@ export default function ExampleApp({ setTitle }: AppProps) { |---|---|---|---| | Feed | `feed` | — | kind 1 timeline, Following/Global, composer (⌘↵ publishes) | | Profile | `profile` | `pubkey`, `relays?` | kind 0 metadata, the author's notes, follow/unfollow | -| Note | `notes` | `id`, `relays?` | One note and its replies. **Not** a singleton | +| Note | `notes` | `id`, `relays?` | One note and its replies, or a blank local draft when `id` is absent. **Not** a singleton | | Reader | `articles` | `pubkey?`, `identifier?`, `kind?`, `relays?` | NIP-23 long-form, `react-markdown` | | Relays | `relays` | — | Connection state, subscription count, measured latency | | Settings | `settings` | — | Theme, relay list, Blossom servers, account, session | diff --git a/src/apps/feed/index.tsx b/src/apps/feed/index.tsx index dc25322..d3d61a9 100644 --- a/src/apps/feed/index.tsx +++ b/src/apps/feed/index.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState } from 'react'; import { useNostr } from '@nostrify/react'; import { useQuery } from '@tanstack/react-query'; -import { Globe, Loader2, Users } from 'lucide-react'; +import { FileText, Globe, Loader2, Users } from 'lucide-react'; import type { NostrEvent } from '@nostrify/nostrify'; import { AppBody, AppLayout, AppToolbar, EmptyState } from '@/components/os/AppChrome'; import { NoteCard } from '@/components/nostr/NoteCard'; @@ -11,6 +11,7 @@ import { Skeleton } from '@/components/ui/skeleton'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useMyFollows } from '@/hooks/useFollows'; import { cn } from '@/lib/utils'; +import { useWindowManager } from '@/os/useWindowManager'; import type { AppProps } from '@/os/types'; type Scope = 'following' | 'global'; @@ -51,6 +52,7 @@ function useFeed(scope: Scope, authors: string[] | undefined) { export default function FeedApp({ setTitle }: AppProps) { const { user } = useCurrentUser(); + const { openApp } = useWindowManager(); const { data: follows } = useMyFollows(); const [requestedScope, setScope] = useState('following'); @@ -85,6 +87,15 @@ export default function FeedApp({ setTitle }: AppProps) { />
{query.isFetching && } + + )} + {user && ( + + )} +
+ + + +