From c26e8110af269d869b240ca76be811593df94e65 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 16 Feb 2026 01:23:56 -0600 Subject: [PATCH] enh: renderMarkdownInPreviews --- .../Messages/Citations/CitationModal.svelte | 48 +++++++++++++----- .../components/chat/Settings/Interface.svelte | 21 ++++++++ .../components/common/FileItemModal.svelte | 49 ++++++++++++++++--- src/lib/stores/index.ts | 1 + 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/lib/components/chat/Messages/Citations/CitationModal.svelte b/src/lib/components/chat/Messages/Citations/CitationModal.svelte index a90abd259..5c1839935 100644 --- a/src/lib/components/chat/Messages/Citations/CitationModal.svelte +++ b/src/lib/components/chat/Messages/Citations/CitationModal.svelte @@ -2,6 +2,7 @@ import { getContext, onMount, tick } from 'svelte'; import Modal from '$lib/components/common/Modal.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; + import Markdown from '$lib/components/chat/Messages/Markdown.svelte'; import { WEBUI_API_BASE_URL } from '$lib/constants'; import { settings } from '$lib/stores'; @@ -10,6 +11,9 @@ const i18n = getContext('i18n'); + const CONTENT_PREVIEW_LIMIT = 10000; + let expandedDocs: Set = new Set(); + export let show = false; export let citation; export let showPercentage = false; @@ -35,6 +39,7 @@ } $: if (citation) { + expandedDocs = new Set(); mergedDocuments = citation.document?.map((c, i) => { return { source: citation.source, @@ -206,20 +211,37 @@ {#if document.metadata?.html} - - {:else} -
{document.document
-										.trim()
-										.replace(/\n\n+/g, '\n\n')}
+ + {:else} + {@const rawContent = document.document.trim().replace(/\n\n+/g, '\n\n')} + {@const isTruncated = ($settings?.renderMarkdownInPreviews ?? true) && rawContent.length > CONTENT_PREVIEW_LIMIT && !expandedDocs.has(documentIdx)} + {#if $settings?.renderMarkdownInPreviews ?? true} +
+ +
+ {#if isTruncated} + {/if} + {:else} +
{rawContent}
+ {/if} + {/if} {/each} diff --git a/src/lib/components/chat/Settings/Interface.svelte b/src/lib/components/chat/Settings/Interface.svelte index 5af1ae8c3..ee242fb73 100644 --- a/src/lib/components/chat/Settings/Interface.svelte +++ b/src/lib/components/chat/Settings/Interface.svelte @@ -70,6 +70,7 @@ let chatFadeStreamingText = true; let collapseCodeBlocks = false; let expandDetails = false; + let renderMarkdownInPreviews = true; let showChatTitleInTab = true; let showFloatingActionButtons = true; @@ -232,6 +233,7 @@ collapseCodeBlocks = $settings?.collapseCodeBlocks ?? false; expandDetails = $settings?.expandDetails ?? false; + renderMarkdownInPreviews = $settings?.renderMarkdownInPreviews ?? true; landingPageMode = $settings?.landingPageMode ?? ''; chatBubble = $settings?.chatBubble ?? true; @@ -964,6 +966,25 @@ +
+
+
+ {$i18n.t('Render Markdown in Previews')} +
+ +
+ { + saveSettings({ renderMarkdownInPreviews }); + }} + /> +
+
+
+
diff --git a/src/lib/components/common/FileItemModal.svelte b/src/lib/components/common/FileItemModal.svelte index dd8896c28..ba0408961 100644 --- a/src/lib/components/common/FileItemModal.svelte +++ b/src/lib/components/common/FileItemModal.svelte @@ -6,6 +6,7 @@ import { formatFileSize, getLineCount } from '$lib/utils'; import { WEBUI_API_BASE_URL } from '$lib/constants'; + import { settings } from '$lib/stores'; import { getKnowledgeById } from '$lib/apis/knowledge'; import { getFileById, getFileContentById } from '$lib/apis/files'; @@ -14,6 +15,9 @@ const i18n = getContext('i18n'); + const CONTENT_PREVIEW_LIMIT = 10000; + let expandedContent = false; + import Modal from './Modal.svelte'; import XMark from '../icons/XMark.svelte'; import Switch from './Switch.svelte'; @@ -147,6 +151,7 @@ const loadContent = async () => { selectedTab = ''; + expandedContent = false; if (item?.type === 'collection') { loading = true; @@ -365,13 +370,45 @@
{:else if selectedTab === ''} {#if item?.file?.data} -
- {(item?.file?.data?.content ?? '').trim() || 'No content'} -
+ {@const rawContent = (item?.file?.data?.content ?? '').trim() || 'No content'} + {@const isTruncated = ($settings?.renderMarkdownInPreviews ?? true) && rawContent.length > CONTENT_PREVIEW_LIMIT && !expandedContent} + {#if $settings?.renderMarkdownInPreviews ?? true} +
+ +
+ {#if isTruncated} + + {/if} + {:else} +
+ {rawContent} +
+ {/if} {:else if item?.content} -
- {(item?.content ?? '').trim() || 'No content'} -
+ {@const rawContent = (item?.content ?? '').trim() || 'No content'} + {@const isTruncated = ($settings?.renderMarkdownInPreviews ?? true) && rawContent.length > CONTENT_PREVIEW_LIMIT && !expandedContent} + {#if $settings?.renderMarkdownInPreviews ?? true} +
+ +
+ {#if isTruncated} + + {/if} + {:else} +
+ {rawContent} +
+ {/if} {/if} {:else if selectedTab === 'preview'} {#if isAudio} diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index 7a77fc0f6..5bde46b4a 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -205,6 +205,7 @@ type Settings = { splitLargeDeltas?: boolean; chatDirection?: 'LTR' | 'RTL' | 'auto'; ctrlEnterToSend?: boolean; + renderMarkdownInPreviews?: boolean; system?: string; seed?: number;