feat(issues): add collapsible toggle for comment replies
Wrap the replies section in a Collapsible component so users can collapse/expand replies on a comment thread. The parent comment and reply input remain always visible. A chevron trigger shows the reply count (e.g. "3 replies") and rotates on open. Default state is expanded to preserve existing behavior.
This commit is contained in:
parent
a472a0e8e0
commit
ef4e2d94a0
1 changed files with 33 additions and 13 deletions
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Copy, MoreHorizontal, Pencil, Trash2 } from "lucide-react";
|
||||
import { Copy, MoreHorizontal, Pencil, Trash2, ChevronRight } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -13,9 +13,11 @@ import {
|
|||
DropdownMenuSeparator,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";
|
||||
import { ActorAvatar } from "@/components/common/actor-avatar";
|
||||
import { ReactionBar } from "@/components/common/reaction-bar";
|
||||
import { Markdown } from "@/components/markdown";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useActorName } from "@/features/workspace";
|
||||
import { timeAgo } from "@/shared/utils";
|
||||
import { ReplyInput } from "./reply-input";
|
||||
|
|
@ -189,6 +191,8 @@ function CommentCard({
|
|||
onDelete,
|
||||
onToggleReaction,
|
||||
}: CommentCardProps) {
|
||||
const [repliesOpen, setRepliesOpen] = useState(true);
|
||||
|
||||
// Collect all nested replies recursively into a flat list
|
||||
const allNestedReplies: TimelineEntry[] = [];
|
||||
const collectReplies = (parentId: string) => {
|
||||
|
|
@ -200,6 +204,8 @@ function CommentCard({
|
|||
};
|
||||
collectReplies(entry.id);
|
||||
|
||||
const replyCount = allNestedReplies.length;
|
||||
|
||||
return (
|
||||
<Card className={`!py-0 !gap-0 overflow-hidden${entry.id.startsWith("temp-") ? " opacity-60" : ""}`}>
|
||||
{/* Parent comment */}
|
||||
|
|
@ -213,18 +219,32 @@ function CommentCard({
|
|||
/>
|
||||
</div>
|
||||
|
||||
{/* Replies — flat, separated by border */}
|
||||
{allNestedReplies.map((reply) => (
|
||||
<div key={reply.id} className="border-t border-border/50 px-4">
|
||||
<CommentRow
|
||||
entry={reply}
|
||||
currentUserId={currentUserId}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
onToggleReaction={onToggleReaction}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{/* Replies — collapsible when there are replies */}
|
||||
{replyCount > 0 && (
|
||||
<Collapsible open={repliesOpen} onOpenChange={setRepliesOpen}>
|
||||
<div className="border-t border-border/50 px-4">
|
||||
<CollapsibleTrigger className="flex w-full items-center gap-1.5 py-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors">
|
||||
<ChevronRight className={cn("h-3 w-3 transition-transform", repliesOpen && "rotate-90")} />
|
||||
<span>
|
||||
{replyCount} {replyCount === 1 ? "reply" : "replies"}
|
||||
</span>
|
||||
</CollapsibleTrigger>
|
||||
</div>
|
||||
<CollapsibleContent>
|
||||
{allNestedReplies.map((reply) => (
|
||||
<div key={reply.id} className="border-t border-border/50 px-4">
|
||||
<CommentRow
|
||||
entry={reply}
|
||||
currentUserId={currentUserId}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
onToggleReaction={onToggleReaction}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)}
|
||||
|
||||
{/* Reply input — always visible at bottom */}
|
||||
<div className="border-t border-border/50 px-4 py-2.5">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue