diff --git a/apps/desktop/src/pages/ConversationPage.tsx b/apps/desktop/src/pages/ConversationPage.tsx index d3a00bb..ade950d 100644 --- a/apps/desktop/src/pages/ConversationPage.tsx +++ b/apps/desktop/src/pages/ConversationPage.tsx @@ -16,6 +16,7 @@ import { ChevronDownIcon, ChevronUpIcon, EyeOffIcon, + PencilIcon, PlusIcon, PollIcon, ReplyIcon, @@ -25,6 +26,7 @@ import { SpinnerIcon, XIcon, } from '../components/icons'; +import { ImageAnnotator } from '../components/ImageAnnotator'; import { InCallPanel } from '../components/InCallPanel'; import { IncomingCallPanel } from '../components/IncomingCallPanel'; import { CallPreviewPanel } from '../components/CallPreviewPanel'; @@ -154,6 +156,7 @@ export function ConversationPage() { const [sendError, setSendError] = useState(null); const [stickToBottom, setStickToBottom] = useState(true); const [attachments, setAttachments] = useState([]); + const [annotatingIndex, setAnnotatingIndex] = useState(null); const [infoPanelOpen, setInfoPanelOpen] = useState(false); const [mediaDrawerOpen, setMediaDrawerOpen] = useState(false); const [pollDialogOpen, setPollDialogOpen] = useState(false); @@ -917,6 +920,9 @@ export function ConversationPage() { key={idx} file={file} onRemove={() => setAttachments((prev) => prev.filter((_, i) => i !== idx))} + {...(file.type.startsWith('image/') + ? { onEdit: () => setAnnotatingIndex(idx) } + : {})} /> ))} @@ -1163,6 +1169,17 @@ export function ConversationPage() { }} onUnpin={(messageId) => void handleTogglePin(messageId)} /> + + {annotatingIndex !== null && attachments[annotatingIndex] && ( + setAnnotatingIndex(null)} + onSave={(next) => { + setAttachments((prev) => prev.map((f, i) => (i === annotatingIndex ? next : f))); + setAnnotatingIndex(null); + }} + /> + )} ); } @@ -1390,7 +1407,15 @@ function Banner({ children }: { children: React.ReactNode }) { ); } -function AttachmentPreview({ file, onRemove }: { file: File; onRemove: () => void }) { +function AttachmentPreview({ + file, + onRemove, + onEdit, +}: { + file: File; + onRemove: () => void; + onEdit?: () => void; +}) { const isImage = file.type.startsWith('image/'); const [url, setUrl] = useState(null); useEffect(() => { @@ -1400,7 +1425,7 @@ function AttachmentPreview({ file, onRemove }: { file: File; onRemove: () => voi return () => URL.revokeObjectURL(u); }, [file, isImage]); return ( -
+
{isImage && url ? ( {file.name} ) : ( @@ -1412,6 +1437,17 @@ function AttachmentPreview({ file, onRemove }: { file: File; onRemove: () => voi {(file.size / 1024).toFixed(0)} KB
)} + {isImage && onEdit && ( + + )}