diff --git a/desktop/src/features/messages/ui/MessageThreadPanel.tsx b/desktop/src/features/messages/ui/MessageThreadPanel.tsx
index d3b1394829b..8797bec7a0e 100644
--- a/desktop/src/features/messages/ui/MessageThreadPanel.tsx
+++ b/desktop/src/features/messages/ui/MessageThreadPanel.tsx
@@ -510,8 +510,12 @@ export function MessageThreadPanel({
tabIndex={-1}
ref={threadBodyRef}
>
+ {/* The gallery is intentionally DOM-scoped: only media currently rendered
+ in this open thread participates. Collapsed or unloaded descendants
+ join only after the thread UI renders them. */}
{
+ toast.success("Copied to clipboard");
+ })
+ .catch((err: unknown) => {
+ const msg = err instanceof Error ? err.message : "Copy failed";
+ toast.error(msg);
+ });
+}
+
+function downloadImage(src: string | undefined) {
+ if (!src) return;
+ invokeTauri("download_image", { url: src }).catch((err: unknown) => {
+ const msg = err instanceof Error ? err.message : "Download failed";
+ toast.error(msg);
+ });
+}
+
function ImageZoomOverlay({
alt,
galleryIndex = 0,
galleryItems,
- onCopy,
- onDownload,
onClose,
resolvedSrc,
sourceBox,
@@ -161,8 +180,6 @@ function ImageZoomOverlay({
alt: string | undefined;
galleryIndex?: number;
galleryItems?: ImageGalleryItem[];
- onCopy: (src: string | undefined) => void;
- onDownload: (src: string | undefined) => void;
onClose: () => void;
resolvedSrc: string;
sourceBox: ImageLightboxBox;
@@ -718,13 +735,13 @@ function ImageZoomOverlay({
const handleMenuCopy = React.useCallback(() => {
setMenu(null);
markControlGesture();
- onCopy(currentItem.src);
- }, [currentItem.src, markControlGesture, onCopy]);
+ copyImageToClipboard(currentItem.src);
+ }, [currentItem.src, markControlGesture]);
const handleMenuDownload = React.useCallback(() => {
setMenu(null);
markControlGesture();
- onDownload(currentItem.src);
- }, [currentItem.src, markControlGesture, onDownload]);
+ downloadImage(currentItem.src);
+ }, [currentItem.src, markControlGesture]);
return createPortal(
{
event.stopPropagation();
- onDownload(currentItem.src);
+ downloadImage(currentItem.src);
}}
>
@@ -952,6 +969,7 @@ function ImageZoomOverlay({
updateZoom={updateZoom}
zoom={zoom}
/>
+
{menu && canActOnCurrentImage ? (
@@ -1000,7 +1018,6 @@ function ImageBlock({ alt, dim, resolvedSrc, src, thumbSrc }: ImageBlockProps) {
const triggerRef = React.useRef