diff --git a/src/components/PostViewer.tsx b/src/components/PostViewer.tsx index db80e7b..d507ed8 100644 --- a/src/components/PostViewer.tsx +++ b/src/components/PostViewer.tsx @@ -300,27 +300,50 @@ export function PostViewer({ windowId }: PostViewerProps = {}) { setDraftEventJson(draftEvent); }, [pubkey, settings.includeClientTag]); - // Debounced draft save (save every 2 seconds of inactivity) - useEffect(() => { - const timer = setInterval(() => { + // Debounced handlers for editor changes + const draftSaveTimeoutRef = useRef | null>( + null, + ); + const jsonUpdateTimeoutRef = useRef | null>( + null, + ); + + const handleEditorChange = useCallback(() => { + // Update empty state immediately + if (editorRef.current) { + setIsEditorEmpty(editorRef.current.isEmpty()); + } + + // Debounce draft save (2 seconds) + if (draftSaveTimeoutRef.current) { + clearTimeout(draftSaveTimeoutRef.current); + } + draftSaveTimeoutRef.current = setTimeout(() => { saveDraft(); - // Update empty state - if (editorRef.current) { - setIsEditorEmpty(editorRef.current.isEmpty()); - } }, 2000); - return () => clearInterval(timer); - }, [saveDraft]); - // Update JSON preview more frequently for responsive UI + // Debounce JSON update (200ms for responsive feel) + if (settings.showEventJson) { + if (jsonUpdateTimeoutRef.current) { + clearTimeout(jsonUpdateTimeoutRef.current); + } + jsonUpdateTimeoutRef.current = setTimeout(() => { + generateDraftEventJson(); + }, 200); + } + }, [saveDraft, settings.showEventJson, generateDraftEventJson]); + + // Cleanup timeouts on unmount useEffect(() => { - if (!settings.showEventJson) return; - - const timer = setInterval(() => { - generateDraftEventJson(); - }, 200); - return () => clearInterval(timer); - }, [settings.showEventJson, generateDraftEventJson]); + return () => { + if (draftSaveTimeoutRef.current) { + clearTimeout(draftSaveTimeoutRef.current); + } + if (jsonUpdateTimeoutRef.current) { + clearTimeout(jsonUpdateTimeoutRef.current); + } + }; + }, []); // Blossom upload for attachments const { open: openUpload, dialog: uploadDialog } = useBlossomUpload({ @@ -679,6 +702,7 @@ export function PostViewer({ windowId }: PostViewerProps = {}) { ref={editorRef} placeholder="What's on your mind?" onSubmit={handlePublish} + onChange={handleEditorChange} searchProfiles={searchProfiles} searchEmojis={searchEmojis} onFilePaste={handleFilePaste} @@ -897,17 +921,31 @@ export function PostViewer({ windowId }: PostViewerProps = {}) { {/* Event JSON Preview */} - {!showPublishedPreview && settings.showEventJson && draftEventJson && ( -
-
- Event JSON (Draft - Unsigned) -
-
- -
-
+ {settings.showEventJson && ( + <> + {showPublishedPreview && lastPublishedEvent ? ( +
+
+ +
+
+ ) : ( + draftEventJson && ( +
+
+ +
+
+ ) + )} + )} {/* Upload dialog */} diff --git a/src/components/editor/RichEditor.tsx b/src/components/editor/RichEditor.tsx index 359f415..f577a72 100644 --- a/src/components/editor/RichEditor.tsx +++ b/src/components/editor/RichEditor.tsx @@ -45,6 +45,7 @@ export interface RichEditorProps { eventRefs: string[], addressRefs: Array<{ kind: number; pubkey: string; identifier: string }>, ) => void; + onChange?: () => void; searchProfiles: (query: string) => Promise; searchEmojis?: (query: string) => Promise; onFilePaste?: (files: File[]) => void; @@ -230,6 +231,7 @@ export const RichEditor = forwardRef( { placeholder = "Write your note...", onSubmit, + onChange, searchProfiles, searchEmojis, onFilePaste, @@ -521,6 +523,9 @@ export const RichEditor = forwardRef( }, }, autofocus: autoFocus, + onUpdate: () => { + onChange?.(); + }, }); // Expose editor methods