mirror of
https://github.com/block/buzz.git
synced 2026-11-04 08:21:48 +00:00
Add Slack-style thread summaries and drilldown navigation for channel replies, and scope typing indicators to the active thread so deeper conversations stay isolated from the main timeline. Made-with: Cursor
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
import { MessageSquareText } from "lucide-react";
|
|
|
|
import type {
|
|
TimelineThreadSummary,
|
|
TimelineThreadSummaryParticipant,
|
|
} from "@/features/messages/lib/threadPanel";
|
|
import type { TimelineMessage } from "@/features/messages/types";
|
|
import { UserAvatar } from "@/shared/ui/UserAvatar";
|
|
|
|
function ParticipantAvatar({
|
|
participant,
|
|
index,
|
|
}: {
|
|
participant: TimelineThreadSummaryParticipant;
|
|
index: number;
|
|
}) {
|
|
return (
|
|
<div
|
|
className={index > 0 ? "-ml-2" : ""}
|
|
style={{ zIndex: 10 - index }}
|
|
>
|
|
<UserAvatar
|
|
avatarUrl={participant.avatarUrl}
|
|
className="rounded-full border-2 border-background"
|
|
displayName={participant.author}
|
|
size="xs"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function MessageThreadSummaryRow({
|
|
message,
|
|
onOpenThread,
|
|
summary,
|
|
}: {
|
|
message: TimelineMessage;
|
|
onOpenThread: (message: TimelineMessage) => void;
|
|
summary: TimelineThreadSummary;
|
|
}) {
|
|
return (
|
|
<button
|
|
className="ml-8 flex w-fit max-w-full items-center gap-3 rounded-xl px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
|
|
data-thread-head-id={message.id}
|
|
data-testid="message-thread-summary"
|
|
onClick={() => onOpenThread(message)}
|
|
type="button"
|
|
>
|
|
<div className="flex shrink-0 items-center">
|
|
{summary.participants.map((participant, index) => (
|
|
<ParticipantAvatar
|
|
index={index}
|
|
key={participant.id}
|
|
participant={participant}
|
|
/>
|
|
))}
|
|
</div>
|
|
<div className="min-w-0">
|
|
<div className="flex items-center gap-1.5 font-medium">
|
|
<MessageSquareText className="h-3.5 w-3.5" />
|
|
<span>
|
|
{summary.replyCount}{" "}
|
|
{summary.replyCount === 1 ? "reply" : "replies"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|