diff --git a/src/lib/components/chat/FileNav.svelte b/src/lib/components/chat/FileNav.svelte index 29ec88501..e92ceba1d 100644 --- a/src/lib/components/chat/FileNav.svelte +++ b/src/lib/components/chat/FileNav.svelte @@ -28,6 +28,12 @@ import Tooltip from '../common/Tooltip.svelte'; import PDFViewer from '../common/PDFViewer.svelte'; import ConfirmDialog from '../common/ConfirmDialog.svelte'; + import Reset from '../icons/Reset.svelte'; + + import panzoom, { type PanZoom } from 'panzoom'; + + let pzInstance: PanZoom | null = null; + let imageSceneElement: HTMLElement | null = null; const i18n = getContext('i18n'); @@ -86,6 +92,10 @@ const clearFilePreview = () => { fileContent = null; + if (pzInstance) { + pzInstance.dispose(); + pzInstance = null; + } if (fileImageUrl) { URL.revokeObjectURL(fileImageUrl); fileImageUrl = null; @@ -93,6 +103,22 @@ filePdfData = null; }; + const initImagePanzoom = (node: HTMLElement) => { + imageSceneElement = node; + pzInstance = panzoom(node, { + bounds: true, + boundsPadding: 0.1, + zoomSpeed: 0.065 + }); + }; + + const resetImageView = () => { + if (pzInstance) { + pzInstance.moveTo(0, 0); + pzInstance.zoomAbs(0, 0, 1); + } + }; + const loadDir = async (path: string) => { if (!configured) return; loading = true; @@ -253,6 +279,7 @@ }); onDestroy(() => { + pzInstance?.dispose(); if (fileImageUrl) URL.revokeObjectURL(fileImageUrl); }); @@ -334,7 +361,7 @@ / {selectedFile.split('/').pop()} @@ -413,38 +440,54 @@ -
+
{#if selectedFile !== null} - - + + {/if} + + + + + +
{#if fileLoading}
{:else if fileImageUrl !== null} - {selectedFile?.split('/').pop()} +
+ {selectedFile?.split('/').pop()} +
{:else if filePdfData !== null} {:else if fileContent !== null} diff --git a/src/lib/components/common/FileItemModal.svelte b/src/lib/components/common/FileItemModal.svelte index d9eca93db..8b4b782fc 100644 --- a/src/lib/components/common/FileItemModal.svelte +++ b/src/lib/components/common/FileItemModal.svelte @@ -25,6 +25,9 @@ import dayjs from 'dayjs'; import Spinner from './Spinner.svelte'; import PDFViewer from './PDFViewer.svelte'; + import Reset from '../icons/Reset.svelte'; + + import panzoom, { type PanZoom } from 'panzoom'; export let item; export let show = false; @@ -46,6 +49,23 @@ let excelError = ''; let rowCount = 0; + let pzInstance: PanZoom | null = null; + + const initImagePanzoom = (node: HTMLElement) => { + pzInstance = panzoom(node, { + bounds: true, + boundsPadding: 0.1, + zoomSpeed: 0.065 + }); + }; + + const resetImageView = () => { + if (pzInstance) { + pzInstance.moveTo(0, 0); + pzInstance.zoomAbs(0, 0, 1); + } + }; + $: isPDF = item?.meta?.content_type === 'application/pdf' || (item?.name && item?.name.toLowerCase().endsWith('.pdf')); @@ -197,6 +217,10 @@ if (item?.context === 'full') { enableFullContent = true; } + + return () => { + pzInstance?.dispose(); + }; }); @@ -361,14 +385,27 @@ {/if} {#if isImage} -
+
+
+ + + +
+
{item?.name
+
{:else if selectedTab === ''} {#if item?.file?.data} {@const rawContent = (item?.file?.data?.content ?? '').trim() || 'No content'} diff --git a/src/lib/components/common/PDFViewer.svelte b/src/lib/components/common/PDFViewer.svelte index 09d07f5a6..e7a25f308 100644 --- a/src/lib/components/common/PDFViewer.svelte +++ b/src/lib/components/common/PDFViewer.svelte @@ -1,29 +1,56 @@ -
- {#if loading} -
- -
- {/if} +
+
+ {#if loading} +
+ +
+ {/if} - {#if error} -
- {error} + {#if error} +
+ {error} +
+ {/if} +
+ + {#if !loading && !error && pdfDoc} +
+ + +
{/if}