Skip to content

Commit 332e731

Browse files
committed
feat(files): zoom controls for inline mermaid and images in markdown, fit zoom upscaling
1 parent 31cfb74 commit 332e731

2 files changed

Lines changed: 25 additions & 9 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,16 @@ function resolveSimFileUrl(src: string | undefined): string | undefined {
462462
try {
463463
const parsed = new URL(src, 'http://placeholder')
464464
if (parsed.origin !== 'http://placeholder') return src
465-
const [, seg1, , seg3, fileId] = parsed.pathname.split('/')
465+
const parts = parsed.pathname.split('/')
466+
const [, seg1, , seg3, fileId] = parts
466467
if (seg1 === 'workspace' && seg3 === 'files' && fileId) {
467468
return `/api/files/view/${fileId}`
468469
}
470+
// files/by-id/{uuid}/content — canonical VFS path used by Mothership skills; treat as embed URL
471+
const [, s1, s2, byIdFileId, s4] = parts
472+
if (s1 === 'files' && s2 === 'by-id' && byIdFileId && s4 === 'content') {
473+
return `/api/files/view/${byIdFileId}`
474+
}
469475
} catch {
470476
// not a parseable URL
471477
}
@@ -476,7 +482,14 @@ const STATIC_MARKDOWN_COMPONENTS = {
476482
pre: ({ children }: { children?: React.ReactNode }) => <>{children}</>,
477483
'mermaid-diagram': ({ definition }: { definition?: string }) => {
478484
const isStreaming = useContext(MermaidStreamingCtx)
479-
return <MermaidDiagram definition={definition ?? ''} isStreaming={isStreaming} />
485+
return (
486+
<MermaidDiagram
487+
definition={definition ?? ''}
488+
isStreaming={isStreaming}
489+
zoomable
490+
zoomClassName='h-[420px] rounded-lg'
491+
/>
492+
)
480493
},
481494
p: ({ children }: { children?: React.ReactNode }) => (
482495
<p className='mb-3 break-words text-[14px] text-[var(--text-primary)] leading-[1.6] last:mb-0'>
@@ -613,12 +626,15 @@ const STATIC_MARKDOWN_COMPONENTS = {
613626
img: ({ src, alt }: React.ImgHTMLAttributes<HTMLImageElement>) => {
614627
const resolvedSrc = resolveSimFileUrl(typeof src === 'string' ? src : undefined)
615628
return (
616-
<img
617-
src={resolvedSrc}
618-
alt={alt ?? ''}
619-
className='my-3 max-w-full rounded-md'
620-
loading='lazy'
621-
/>
629+
<ZoomablePreview className='my-3 h-[360px] rounded-md' initialScale='fit'>
630+
<img
631+
src={resolvedSrc}
632+
alt={alt ?? ''}
633+
className='max-h-full max-w-full select-none object-contain'
634+
draggable={false}
635+
loading='lazy'
636+
/>
637+
</ZoomablePreview>
622638
)
623639
},
624640
table: ({ children }: { children?: React.ReactNode }) => (

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/zoomable-preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function getFitZoom(container: Size, content: Size): number {
4747

4848
const availableWidth = Math.max(1, container.width - FIT_PADDING)
4949
const availableHeight = Math.max(1, container.height - FIT_PADDING)
50-
return clampZoom(Math.min(1, availableWidth / content.width, availableHeight / content.height))
50+
return clampZoom(Math.min(availableWidth / content.width, availableHeight / content.height))
5151
}
5252

5353
function clampOffset(container: Size, content: Size, offset: Offset, zoom: number): Offset {

0 commit comments

Comments
 (0)