From 4391a658d3a57f99d7bce29bc0e6dc76c755bf1f Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Thu, 1 Jan 2026 20:47:52 +0100 Subject: [PATCH] feat(nostr-feed): Add inline reply forms for comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add inline reply form that appears below the comment being replied to - Pass replyingToId and isSubmittingReply props through comment tree - Add cancel-reply and submit-reply events for inline form handling - Top composer now only shows for new top-level comments - Better UX: no need to scroll to top to reply to nested comments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../components/SubmissionComment.vue | 73 ++++++++++++++++++- .../components/SubmissionDetail.vue | 52 ++++++++++--- 2 files changed, 109 insertions(+), 16 deletions(-) diff --git a/src/modules/nostr-feed/components/SubmissionComment.vue b/src/modules/nostr-feed/components/SubmissionComment.vue index b1e4b09..5914a0a 100644 --- a/src/modules/nostr-feed/components/SubmissionComment.vue +++ b/src/modules/nostr-feed/components/SubmissionComment.vue @@ -4,9 +4,9 @@ * Displays a single comment with vote controls and nested replies */ -import { computed } from 'vue' +import { computed, ref } from 'vue' import { formatDistanceToNow } from 'date-fns' -import { ChevronUp, ChevronDown, Reply, Flag, MoreHorizontal } from 'lucide-vue-next' +import { ChevronUp, ChevronDown, Reply, Flag, MoreHorizontal, Send, X } from 'lucide-vue-next' import VoteControls from './VoteControls.vue' import type { SubmissionComment as CommentType } from '../types/submission' @@ -17,18 +17,49 @@ interface Props { getDisplayName: (pubkey: string) => string isAuthenticated: boolean currentUserPubkey?: string | null + replyingToId?: string | null + isSubmittingReply?: boolean } interface Emits { (e: 'toggle-collapse', commentId: string): void (e: 'reply', comment: CommentType): void + (e: 'cancel-reply'): void + (e: 'submit-reply', commentId: string, text: string): void (e: 'upvote', comment: CommentType): void (e: 'downvote', comment: CommentType): void } -const props = defineProps() +const props = withDefaults(defineProps(), { + replyingToId: null, + isSubmittingReply: false +}) const emit = defineEmits() +// Local reply text +const replyText = ref('') + +// Is this comment being replied to +const isBeingRepliedTo = computed(() => props.replyingToId === props.comment.id) + +// Handle reply click +function onReplyClick() { + emit('reply', props.comment) +} + +// Submit the reply +function submitReply() { + if (!replyText.value.trim()) return + emit('submit-reply', props.comment.id, replyText.value.trim()) + replyText.value = '' +} + +// Cancel reply +function cancelReply() { + replyText.value = '' + emit('cancel-reply') +} + // Is this comment collapsed const isCollapsed = computed(() => props.collapsedComments.has(props.comment.id)) @@ -168,7 +199,8 @@ const isOwnComment = computed(() => + +
+
+