diff --git a/ui/colony/src/App.tsx b/ui/colony/src/App.tsx index b93dd99..44767c9 100644 --- a/ui/colony/src/App.tsx +++ b/ui/colony/src/App.tsx @@ -43,7 +43,7 @@ export default function App() { const [activeChannelId, setActiveChannelId] = useState(null); const [messages, setMessages] = useState([]); const [loading, setLoading] = useState(false); - const [replyTo, setReplyTo] = useState<{ id: string; username: string; content: string } | null>(null); + const [selectedMessages, setSelectedMessages] = useState<{ id: string; username: string; content: string }[]>([]); const [sheetOpen, setSheetOpen] = useState(false); const [showScrollDown, setShowScrollDown] = useState(false); const scrollRef = useRef(null); @@ -93,7 +93,7 @@ export default function App() { useEffect(() => { setMessages([]); - setReplyTo(null); + setSelectedMessages([]); prevMsgCountRef.current = 0; loadMessages(); }, [activeChannelId, loadMessages]); @@ -212,11 +212,15 @@ export default function App() { message={msg} replyTarget={msg.reply_to ? messagesById.get(msg.reply_to) : undefined} currentUsername={getCurrentUsername()} - onReply={(id) => { - const target = messagesById.get(id); - if (target) { - setReplyTo({ id, username: target.user.display_name, content: target.content }); - } + selected={selectedMessages.some((s) => s.id === msg.id)} + onSelect={(id) => { + setSelectedMessages((prev) => { + const exists = prev.find((s) => s.id === id); + if (exists) return prev.filter((s) => s.id !== id); + const target = messagesById.get(id); + if (!target) return prev; + return [...prev, { id, username: target.user.display_name, content: target.content }]; + }); }} onDelete={async (chId, msgId) => { try { @@ -248,9 +252,11 @@ export default function App() { setReplyTo(null)} + replyTo={selectedMessages.length > 0 ? selectedMessages[0] : null} + selectedMessages={selectedMessages} + onClearReply={() => setSelectedMessages([])} onMessageSent={() => { + setSelectedMessages([]); loadMessages(); setTimeout(() => scrollToBottom(), 100); }} diff --git a/ui/colony/src/components/ComposeBox.tsx b/ui/colony/src/components/ComposeBox.tsx index f7155d4..acbf9ed 100644 --- a/ui/colony/src/components/ComposeBox.tsx +++ b/ui/colony/src/components/ComposeBox.tsx @@ -1,7 +1,7 @@ import { useState, useRef, useEffect, useCallback } from "react"; import type { MessageType } from "@/types/MessageType"; import type { User } from "@/types/User"; -import { postMessage, getUsers, getCurrentUsername } from "@/api"; +import { postMessage, getUsers, getCurrentUsername, createChannel } from "@/api"; import { cn } from "@/lib/utils"; interface ReplyContext { @@ -13,6 +13,7 @@ interface ReplyContext { interface Props { channelId: string; replyTo: ReplyContext | null; + selectedMessages: ReplyContext[]; onClearReply: () => void; onMessageSent: () => void; } @@ -28,6 +29,7 @@ const TYPE_META: Record - {/* Reply chip */} - {replyTo && ( -
-
- {replyTo.username} - - {replyTo.content} + {/* Selected messages for reply */} + {selectedMessages.length > 0 && ( +
+
+ + replying to {selectedMessages.length} {selectedMessages.length === 1 ? "message" : "messages"} +
- + {selectedMessages.map((msg) => ( +
+ {msg.username} + {msg.content} +
+ ))} +
)} diff --git a/ui/colony/src/components/MessageItem.tsx b/ui/colony/src/components/MessageItem.tsx index 9c20b81..83d4dc9 100644 --- a/ui/colony/src/components/MessageItem.tsx +++ b/ui/colony/src/components/MessageItem.tsx @@ -8,9 +8,10 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp interface Props { message: Message; replyTarget?: Message; - onReply: (id: string) => void; + onSelect: (id: string) => void; onDelete: (channelId: string, msgId: string) => void; currentUsername: string; + selected: boolean; } const TYPE_CONFIG: Record = { @@ -55,7 +56,7 @@ function userHue(username: string): number { return Math.abs(hash) % 360; } -export function MessageItem({ message, replyTarget, onReply, onDelete, currentUsername }: Props) { +export function MessageItem({ message, replyTarget, onSelect, onDelete, currentUsername, selected }: Props) { const [metaOpen, setMetaOpen] = useState(false); const isAgent = message.user.role === "agent"; const isDeleted = !!message.deleted_at; @@ -74,10 +75,11 @@ export function MessageItem({ message, replyTarget, onReply, onDelete, currentUs return (
onSelect(message.id)} className={cn( - "group border-b border-border/50 border-l-4 transition-all duration-300", + "group relative border-b border-border/50 border-l-4 transition-all duration-300 cursor-pointer", cfg.border, - isAgent ? "bg-card" : "bg-background", + selected ? "!border-l-primary bg-primary/5" : isAgent ? "bg-card" : "bg-background", "hover:bg-muted/30", )} > @@ -155,16 +157,19 @@ export function MessageItem({ message, replyTarget, onReply, onDelete, currentUs
{!isDeleted && message.user.username === currentUsername && (