feat(web): improve comment editing and mention rendering

This commit is contained in:
CREDO23 2026-01-19 14:37:45 +02:00
parent f008acecfc
commit 0b675dfc3b
4 changed files with 29 additions and 21 deletions

View file

@ -205,11 +205,11 @@ export function CommentComposer({
// Pre-populate insertedMentions from initialValue when members are loaded // Pre-populate insertedMentions from initialValue when members are loaded
useEffect(() => { useEffect(() => {
if (mentionsInitialized || !initialValue || members.length === 0) return; if (mentionsInitialized || !initialValue || members.length === 0) return;
const mentionPattern = /@([^\s@]+(?:\s+[^\s@]+)*?)(?=\s|$|[.,!?;:]|@)/g; const mentionPattern = /@([^\s@]+(?:\s+[^\s@]+)*?)(?=\s|$|[.,!?;:]|@)/g;
const foundMentions: InsertedMention[] = []; const foundMentions: InsertedMention[] = [];
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
while ((match = mentionPattern.exec(initialValue)) !== null) { while ((match = mentionPattern.exec(initialValue)) !== null) {
const displayName = match[1]; const displayName = match[1];
const member = members.find( const member = members.find(
@ -222,7 +222,7 @@ export function CommentComposer({
} }
} }
} }
if (foundMentions.length > 0) { if (foundMentions.length > 0) {
setInsertedMentions(foundMentions); setInsertedMentions(foundMentions);
} }
@ -239,7 +239,11 @@ export function CommentComposer({
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Popover open={mentionState.isActive} onOpenChange={(open) => !open && closeMentionPicker()} modal={false}> <Popover
open={mentionState.isActive}
onOpenChange={(open) => !open && closeMentionPicker()}
modal={false}
>
<PopoverAnchor asChild> <PopoverAnchor asChild>
<Textarea <Textarea
ref={textareaRef} ref={textareaRef}

View file

@ -116,7 +116,7 @@ export function CommentItem({
membersLoading = false, membersLoading = false,
}: CommentItemProps) { }: CommentItemProps) {
const [{ data: currentUser }] = useAtom(currentUserAtom); const [{ data: currentUser }] = useAtom(currentUserAtom);
const isCurrentUser = currentUser?.id === comment.author?.id; const isCurrentUser = currentUser?.id === comment.author?.id;
const displayName = isCurrentUser const displayName = isCurrentUser
? "Me" ? "Me"

View file

@ -27,7 +27,12 @@ export interface CommentItemProps {
isReply?: boolean; isReply?: boolean;
isEditing?: boolean; isEditing?: boolean;
isSubmitting?: boolean; isSubmitting?: boolean;
members?: Array<{ id: string; displayName: string | null; email: string; avatarUrl?: string | null }>; members?: Array<{
id: string;
displayName: string | null;
email: string;
avatarUrl?: string | null;
}>;
membersLoading?: boolean; membersLoading?: boolean;
} }

View file

@ -126,31 +126,30 @@ export function CommentThread({
)} )}
{/* Reply composer or button */} {/* Reply composer or button */}
{isReplyComposerOpen ? ( {isReplyComposerOpen ? (
<> <>
<div className="pt-3"> <div className="pt-3">
<CommentComposer <CommentComposer
members={members} members={members}
membersLoading={membersLoading} membersLoading={membersLoading}
placeholder="Write a reply..." placeholder="Write a reply..."
submitLabel="Reply" submitLabel="Reply"
isSubmitting={isSubmitting} isSubmitting={isSubmitting}
onSubmit={handleReplySubmit} onSubmit={handleReplySubmit}
onCancel={handleReplyCancel} onCancel={handleReplyCancel}
autoFocus autoFocus
/> />
</div> </div>
</> </>
) : ( ) : (
<Button variant="ghost" size="sm" className="h-7 px-2 text-xs" onClick={handleReply}> <Button variant="ghost" size="sm" className="h-7 px-2 text-xs" onClick={handleReply}>
<MessageSquare className="mr-1.5 size-3" /> <MessageSquare className="mr-1.5 size-3" />
Reply Reply
</Button> </Button>
)} )}
</div>
</div> </div>
</div>
)} )}
{/* Reply button when no replies yet */} {/* Reply button when no replies yet */}