From f962bae98306ea9264967b78b803397f4821f9b0 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Wed, 4 Mar 2026 15:59:55 -0600 Subject: [PATCH] feat: improve XLSX preview + add code syntax highlighting XLSX QoL: - Custom table renderer (excelToTable.ts) with column letters, row numbers, right-aligned numbers, empty cell handling - Monospace font, sticky headers + row nums, cell cursor - Sheet tabs moved to bottom bar (like PPTX navigation) - Unified styles between FileNav and FileItemModal Code highlighting: - Shiki-based syntax highlighting for code files in FileNav - Line numbers, dark/light theme support - Source/Preview toggle for code files --- src/lib/components/chat/FileNav.svelte | 21 ++- .../chat/FileNav/FilePreview.svelte | 146 ++++++++++++++++-- .../components/common/FileItemModal.svelte | 19 +-- src/lib/utils/codeHighlight.ts | 95 ++++++++++++ src/lib/utils/excelToTable.ts | 86 +++++++++++ 5 files changed, 326 insertions(+), 41 deletions(-) create mode 100644 src/lib/utils/codeHighlight.ts create mode 100644 src/lib/utils/excelToTable.ts diff --git a/src/lib/components/chat/FileNav.svelte b/src/lib/components/chat/FileNav.svelte index 9daf03592..dfeb9064c 100644 --- a/src/lib/components/chat/FileNav.svelte +++ b/src/lib/components/chat/FileNav.svelte @@ -26,6 +26,7 @@ setCwd, type FileEntry } from '$lib/apis/terminal'; + import { isCodeFile } from '$lib/utils/codeHighlight'; import Folder from '../icons/Folder.svelte'; import Document from '../icons/Document.svelte'; import PenAlt from '../icons/PenAlt.svelte'; @@ -116,6 +117,7 @@ $: isMarkdown = MD_EXTS.has(getFileExt(selectedFile)); $: isCsv = CSV_EXTS.has(getFileExt(selectedFile)); $: isHtml = HTML_EXTS.has(getFileExt(selectedFile)); + $: isCode = isCodeFile(selectedFile); $: isOfficeFile = OFFICE_EXTS.has(getFileExt(selectedFile)); $: isTextFile = fileContent !== null && fileImageUrl === null && filePdfData === null && !isOfficeFile; @@ -281,11 +283,9 @@ excelSheetNames = wb.SheetNames; if (excelSheetNames.length > 0) { selectedExcelSheet = excelSheetNames[0]; - const ws = wb.Sheets[selectedExcelSheet]; - const DOMPurify = (await import('dompurify')).default; - fileOfficeHtml = DOMPurify.sanitize( - XLSX.utils.sheet_to_html(ws, { id: 'excel-table', editable: false, header: '' }) - ); + const { excelToTable } = await import('$lib/utils/excelToTable'); + const result = await excelToTable(wb.Sheets[selectedExcelSheet]); + fileOfficeHtml = result.html; } } else if (ext === 'pptx') { const { pptxToImages } = await import('$lib/utils/pptxToHtml'); @@ -612,7 +612,7 @@ {/if} - {#if (isMarkdown || isCsv || isHtml) && fileContent !== null && !editing} + {#if (isMarkdown || isCsv || isHtml || isCode) && fileContent !== null && !editing}