From b9750b375944c3df8121d3e4c873def13fe92f16 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 21 Jun 2025 14:33:00 -0500 Subject: [PATCH 01/18] Update "Vibe with MKStack" link --- CONTEXT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTEXT.md b/CONTEXT.md index 06be660..a2f734e 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -102,7 +102,7 @@ The AI assistant's behavior and knowledge is defined by the CONTEXT.md file, whi ## "Vibed with MKStack" -When building the site for the first time, include "Vibed with MKStack" somewhere in the UI, linked to this URL: https://soapbox.pub/tools/mkstack/ +When building the site for the first time, include "Vibed with MKStack" somewhere in the UI, linked to this URL: https://soapbox.pub/mkstack ## Nostr Protocol Integration From b7ff219e6eca5f7f97dbd816639dbf5933e7ed2c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 23 Jun 2025 22:49:53 -0500 Subject: [PATCH 02/18] avatar: object-cover --- src/components/ui/avatar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx index 991f56e..2a948cb 100644 --- a/src/components/ui/avatar.tsx +++ b/src/components/ui/avatar.tsx @@ -24,7 +24,7 @@ const AvatarImage = React.forwardRef< >(({ className, ...props }, ref) => ( )) From 508fa84466016d06a90c3b9b8eb5255d0b5f79be Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 24 Jun 2025 20:38:59 -0500 Subject: [PATCH 03/18] Default to Primal relay --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 2300f58..7cab833 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -32,7 +32,7 @@ const queryClient = new QueryClient({ const defaultConfig: AppConfig = { theme: "light", - relayUrl: "wss://relay.nostr.band", + relayUrl: "wss://relay.primal.net", }; const presetRelays = [ From 15dbc6df85431102c91d8660b3018efa3583478c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 26 Jun 2025 10:35:59 -0500 Subject: [PATCH 04/18] AccountSwitcher: modal={false} --- src/components/auth/AccountSwitcher.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/auth/AccountSwitcher.tsx b/src/components/auth/AccountSwitcher.tsx index d3ebf5e..4f4518b 100644 --- a/src/components/auth/AccountSwitcher.tsx +++ b/src/components/auth/AccountSwitcher.tsx @@ -28,7 +28,7 @@ export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) { } return ( - + + + {hasReplies && ( + + + + + + )} + + + {/* Comment menu */} + + + + + + + + + + + {/* Reply Form */} + {showReplyForm && ( +
+ setShowReplyForm(false)} + placeholder="Write a reply..." + compact + /> +
+ )} + + {/* Replies */} + {hasReplies && ( + + + {replies.map((reply) => ( + + ))} + + + )} + + ); +} \ No newline at end of file diff --git a/src/components/comments/CommentForm.tsx b/src/components/comments/CommentForm.tsx new file mode 100644 index 0000000..7c973f2 --- /dev/null +++ b/src/components/comments/CommentForm.tsx @@ -0,0 +1,90 @@ +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { Textarea } from '@/components/ui/textarea'; +import { Card, CardContent } from '@/components/ui/card'; +import { useCurrentUser } from '@/hooks/useCurrentUser'; +import { usePostComment } from '@/hooks/usePostComment'; +import { LoginArea } from '@/components/auth/LoginArea'; +import { NostrEvent } from '@nostrify/nostrify'; +import { MessageSquare, Send } from 'lucide-react'; + +interface CommentFormProps { + root: NostrEvent | URL; + reply?: NostrEvent | URL; + onSuccess?: () => void; + placeholder?: string; + compact?: boolean; +} + +export function CommentForm({ + root, + reply, + onSuccess, + placeholder = "Write a comment...", + compact = false +}: CommentFormProps) { + const [content, setContent] = useState(''); + const { user } = useCurrentUser(); + const { mutate: postComment, isPending } = usePostComment(); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (!content.trim() || !user) return; + + postComment( + { content: content.trim(), root, reply }, + { + onSuccess: () => { + setContent(''); + onSuccess?.(); + }, + } + ); + }; + + if (!user) { + return ( + + +
+
+ + Sign in to {reply ? 'reply' : 'comment'} +
+ +
+
+
+ ); + } + + return ( + + +
+