diff --git a/src/apps/chat/components/composer/llmattachments/LLMAttachmentMenu.tsx b/src/apps/chat/components/composer/llmattachments/LLMAttachmentMenu.tsx
index 995c05bdb..e72518191 100644
--- a/src/apps/chat/components/composer/llmattachments/LLMAttachmentMenu.tsx
+++ b/src/apps/chat/components/composer/llmattachments/LLMAttachmentMenu.tsx
@@ -15,10 +15,8 @@ import ReadMoreIcon from '@mui/icons-material/ReadMore';
import VerticalAlignBottomIcon from '@mui/icons-material/VerticalAlignBottom';
import VisibilityIcon from '@mui/icons-material/Visibility';
-import { showImageDataRefInNewTab } from '~/modules/blocks/image/RenderImageRefDBlob';
-
import { CloseableMenu } from '~/common/components/CloseableMenu';
-import { DMessageAttachmentFragment, DMessageDataRef, isDocPart, isImageRefPart } from '~/common/stores/chat/chat.fragments';
+import { DMessageAttachmentFragment, DMessageImageRefPart, isDocPart, isImageRefPart } from '~/common/stores/chat/chat.fragments';
import { LiveFileIcon } from '~/common/livefile/liveFile.icons';
import { copyToClipboard } from '~/common/util/clipboardUtils';
import { showImageDataURLInNewTab } from '~/common/util/imageUtils';
@@ -50,8 +48,9 @@ export function LLMAttachmentMenu(props: {
menuAnchor: HTMLAnchorElement,
isPositionFirst: boolean,
isPositionLast: boolean,
- onDraftAction: (attachmentDraftId: AttachmentDraftId, actionId: LLMAttachmentDraftsAction) => void,
onClose: () => void,
+ onDraftAction: (attachmentDraftId: AttachmentDraftId, actionId: LLMAttachmentDraftsAction) => void,
+ onViewImageRefPart: (imageRefPart: DMessageImageRefPart) => void
}) {
// state
@@ -97,7 +96,7 @@ export function LLMAttachmentMenu(props: {
// operations
- const { attachmentDraftsStoreApi, onDraftAction, onClose } = props;
+ const { attachmentDraftsStoreApi, onClose, onDraftAction, onViewImageRefPart } = props;
const handleMoveUp = React.useCallback(() => {
attachmentDraftsStoreApi.getState().moveAttachmentDraft(draftId, -1);
@@ -128,11 +127,11 @@ export function LLMAttachmentMenu(props: {
copyToClipboard(text, 'Attachment Text');
}, []);
- const handleViewMessageDataRef = React.useCallback((event: React.MouseEvent, dataRef: DMessageDataRef) => {
+ const handleViewImageRefPart = React.useCallback((event: React.MouseEvent, imageRefPart: DMessageImageRefPart) => {
event.preventDefault();
event.stopPropagation();
- void showImageDataRefInNewTab(dataRef); // fire/forget
- }, []);
+ onViewImageRefPart(imageRefPart);
+ }, [onViewImageRefPart]);
const canHaveDetails = !!draftInput && !isConverting;
@@ -327,7 +326,7 @@ export function LLMAttachmentMenu(props: {
return (
}>
{mime /*.replace('image/', 'img: ')*/} · {resolution} · {part.dataRef.reftype === 'dblob' ? (part.dataRef.bytesSize?.toLocaleString() || 'no size') : '(remote)'} ·
- } onClick={(event) => handleViewMessageDataRef(event, part.dataRef)}>
+ } onClick={(event) => handleViewImageRefPart(event, part)}>
see
{isOutputMultiple && } onClick={(event) => handleDeleteOutputFragment(event, index)}>
diff --git a/src/apps/chat/components/composer/llmattachments/LLMAttachmentsList.tsx b/src/apps/chat/components/composer/llmattachments/LLMAttachmentsList.tsx
index cb0c0c128..9ff0fd4f7 100644
--- a/src/apps/chat/components/composer/llmattachments/LLMAttachmentsList.tsx
+++ b/src/apps/chat/components/composer/llmattachments/LLMAttachmentsList.tsx
@@ -15,6 +15,9 @@ import { useOverlayComponents } from '~/common/layout/overlays/useOverlayCompone
import type { AttachmentDraftId } from '~/common/attachment-drafts/attachment.types';
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-attachment-drafts-slice';
+import type { DMessageImageRefPart } from '~/common/stores/chat/chat.fragments';
+
+import { ImageRefPartModal } from '../../message/fragments-content/ImageRefPartModal';
import type { LLMAttachmentDraft } from './useLLMAttachmentDrafts';
import { LLMAttachmentButtonMemo } from './LLMAttachmentButton';
@@ -40,6 +43,7 @@ export function LLMAttachmentsList(props: {
const { showPromisedOverlay } = useOverlayComponents();
const [draftMenu, setDraftMenu] = React.useState<{ anchor: HTMLAnchorElement, attachmentDraftId: AttachmentDraftId } | null>(null);
const [overallMenuAnchor, setOverallMenuAnchor] = React.useState(null);
+ const [viewerImageRefPart, setViewerImageRefPart] = React.useState(null);
// derived state
@@ -106,6 +110,14 @@ export function LLMAttachmentsList(props: {
onAttachmentDraftsAction(attachmentDraftId, actionId);
}, [handleDraftMenuHide, onAttachmentDraftsAction]);
+ const handleViewImageRefPart = React.useCallback((imageRefPart: DMessageImageRefPart) => {
+ setViewerImageRefPart(imageRefPart);
+ }, []);
+
+ const handleCloseImageViewer = React.useCallback(() => {
+ setViewerImageRefPart(null);
+ }, []);
+
// no components without attachments
if (!hasAttachments)
@@ -153,7 +165,10 @@ export function LLMAttachmentsList(props: {
- {/* LLM Attachment Draft Menu */}
+ {/* Optional Modal to view the Image */}
+ {viewerImageRefPart && }
+
+ {/* Single LLM Attachment Draft Menu */}
{!!itemMenuAnchor && !!itemMenuAttachmentDraft && !!props.attachmentDraftsStoreApi && (
)}
diff --git a/src/apps/chat/components/message/fragments-content/BlockPartImageRef.tsx b/src/apps/chat/components/message/fragments-content/BlockPartImageRef.tsx
index 438a307fe..539577bee 100644
--- a/src/apps/chat/components/message/fragments-content/BlockPartImageRef.tsx
+++ b/src/apps/chat/components/message/fragments-content/BlockPartImageRef.tsx
@@ -13,7 +13,7 @@ import { ContentScaling, themeScalingMap } from '~/common/app.theme';
export function BlockPartImageRef(props: {
imageRefPart: DMessageImageRefPart,
- fragmentId: DMessageFragmentId,
+ fragmentId?: DMessageFragmentId,
contentScaling: ContentScaling,
onFragmentDelete?: (fragmentId: DMessageFragmentId) => void,
onFragmentReplace?: (fragmentId: DMessageFragmentId, newFragment: DMessageContentFragment) => void,
@@ -25,11 +25,13 @@ export function BlockPartImageRef(props: {
// event handlers
const handleDeleteFragment = React.useCallback(() => {
- onFragmentDelete?.(fragmentId);
+ if (fragmentId && onFragmentDelete)
+ onFragmentDelete(fragmentId);
}, [fragmentId, onFragmentDelete]);
const handleReplaceFragment = React.useCallback((newImageFragment: DMessageContentFragment) => {
- onFragmentReplace?.(fragmentId, newImageFragment);
+ if (fragmentId && onFragmentReplace)
+ onFragmentReplace(fragmentId, newImageFragment);
}, [fragmentId, onFragmentReplace]);
const handleOpenInNewTab = React.useCallback(() => {
diff --git a/src/apps/chat/components/message/fragments-content/ImageRefPartModal.tsx b/src/apps/chat/components/message/fragments-content/ImageRefPartModal.tsx
new file mode 100644
index 000000000..4f006c9c8
--- /dev/null
+++ b/src/apps/chat/components/message/fragments-content/ImageRefPartModal.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react';
+
+import type { SxProps } from '@mui/joy/styles/types';
+import { Box } from '@mui/joy';
+
+import type { DMessageImageRefPart } from '~/common/stores/chat/chat.fragments';
+import { GoodModal } from '~/common/components/modals/GoodModal';
+
+import { BlockPartImageRef } from './BlockPartImageRef';
+
+
+const imageViewerModalSx: SxProps = {
+ maxWidth: '90vw',
+};
+
+const imageViewerContainerSx: SxProps = {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ maxHeight: '80vh',
+ overflow: 'auto',
+};
+
+
+export function ImageRefPartModal(props: { imageRefPart: DMessageImageRefPart, onClose: () => void }) {
+ return (
+
+
+
+
+
+ );
+}
\ No newline at end of file