From c9a52208da9e8deeac6f2df7fcacbe519c2acb29 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 15 Oct 2026 23:02:47 +0400 Subject: [PATCH] refac --- .../chat/FileNav/FilePreview.svelte | 51 +------ .../chat/FileNav/MarkdownDocument.svelte | 133 ++++++++++++++++++ .../components/chat/Messages/CodeBlock.svelte | 11 +- .../Messages/Markdown/AlertRenderer.svelte | 7 +- .../chat/Messages/Markdown/HTMLToken.svelte | 5 +- .../Markdown/MarkdownInlineTokens.svelte | 23 ++- .../Messages/Markdown/MarkdownTokens.svelte | 19 ++- 7 files changed, 187 insertions(+), 62 deletions(-) create mode 100644 src/lib/components/chat/FileNav/MarkdownDocument.svelte diff --git a/src/lib/components/chat/FileNav/FilePreview.svelte b/src/lib/components/chat/FileNav/FilePreview.svelte index 11c00c6aa2..4dd9bb98ee 100644 --- a/src/lib/components/chat/FileNav/FilePreview.svelte +++ b/src/lib/components/chat/FileNav/FilePreview.svelte @@ -1,11 +1,10 @@ + + + +
+ +
+ + diff --git a/src/lib/components/chat/Messages/CodeBlock.svelte b/src/lib/components/chat/Messages/CodeBlock.svelte index 56831ebaf7..41eb74f85c 100644 --- a/src/lib/components/chat/Messages/CodeBlock.svelte +++ b/src/lib/components/chat/Messages/CodeBlock.svelte @@ -30,7 +30,9 @@ import Tooltip from '$lib/components/common/Tooltip.svelte'; const i18n = getContext>('i18n'); - const markdown = getContext<{ allowRemoteContent: boolean } | undefined>('markdown'); + const markdown = getContext<{ allowRemoteContent: boolean; document?: boolean } | undefined>( + 'markdown' + ); export let id = ''; export let edit = true; @@ -370,7 +372,10 @@ const render = async () => { onUpdate(token, id); if (markdown?.allowRemoteContent === false) return; - if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) { + if ( + lang === 'mermaid' && + (markdown?.document || (token?.raw ?? '').slice(-4).includes('```')) + ) { try { renderHTML = await renderMermaid(code); } catch (error) { @@ -381,7 +386,7 @@ } } else if ( (lang === 'vega' || lang === 'vega-lite') && - (token?.raw ?? '').slice(-4).includes('```') + (markdown?.document || (token?.raw ?? '').slice(-4).includes('```')) ) { try { renderHTML = await renderVegaVisualization(code, lang); diff --git a/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte b/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte index 1470e63634..6402b666b6 100644 --- a/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte +++ b/src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte @@ -43,7 +43,10 @@ } }; - export function alertComponent(token: Token): AlertData | false { + export function alertComponent( + token: Token, + lexer: (source: string) => Token[] = marked.lexer + ): AlertData | false { const regExpStr = `^(?:\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\])\\s*?\n*`; const regExp = new RegExp(regExpStr); const matches = token.text?.match(regExp); @@ -51,7 +54,7 @@ if (matches && matches.length) { const alertType = matches[1] as AlertType; const newText = token.text.replace(regExp, ''); - const newTokens = marked.lexer(newText); + const newTokens = lexer(newText); return { type: alertType, text: newText, diff --git a/src/lib/components/chat/Messages/Markdown/HTMLToken.svelte b/src/lib/components/chat/Messages/Markdown/HTMLToken.svelte index a3a949e7a4..784244ad31 100644 --- a/src/lib/components/chat/Messages/Markdown/HTMLToken.svelte +++ b/src/lib/components/chat/Messages/Markdown/HTMLToken.svelte @@ -7,6 +7,7 @@ import { settings } from '$lib/stores'; const i18n: any = getContext('i18n'); + const markdown = getContext<{ document?: boolean } | undefined>('markdown'); export let id: string; export let token: Token; @@ -18,7 +19,9 @@ {#if token.type === 'html'} - {#if html && html.includes(']*>([\s\S]*?)<\/video>/)} {@const videoSrc = video && video[1]} {#if videoSrc} diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte index 38f3857894..e515b544b3 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte @@ -7,7 +7,10 @@ import { goto } from '$app/navigation'; const i18n = getContext('i18n'); - const markdown = getContext<{ allowRemoteContent: boolean } | undefined>('markdown'); + const markdown = getContext< + | { allowRemoteContent: boolean; document?: boolean; parseInline?: (tokens: Token[]) => string } + | undefined + >('markdown'); import { WEBUI_BASE_URL } from '$lib/constants'; import { skills, terminalSkills } from '$lib/stores'; @@ -82,16 +85,24 @@ // Invalid URL, let browser handle it } }; + $: inlineHtml = + markdown?.document && tokens.some((token) => token.type === 'html') + ? DOMPurify.sanitize(markdown.parseInline?.(tokens) ?? '') + : null; -{#each tokens as token, tokenIdx (tokenIdx)} + +{#if inlineHtml !== null} + {@html inlineHtml} +{/if} +{#each inlineHtml === null ? tokens : [] as token, tokenIdx (tokenIdx)} {#if token.type === 'escape'} {unescapeHtml(token.text)} {:else if token.type === 'html'} {:else if token.type === 'link'} {@const linkToken = getLinkToken(token)} - {#if linkToken.noteId && markdown?.allowRemoteContent !== false} + {#if linkToken.noteId && !markdown?.document && markdown?.allowRemoteContent !== false} {:else if token.tokens && !linkToken.isAutolink} {/if} {:else if token.type === 'text'} - + {#if markdown?.document} + {unescapeHtml(token.text)} + {:else} + + {/if} {/if} {/each} diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte index 02c8537863..de9ae88dce 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte @@ -2,6 +2,9 @@ import { decode } from 'html-entities'; import { onMount, getContext } from 'svelte'; const i18n = getContext('i18n'); + const markdown = getContext< + { document?: boolean; lexer?: (source: string) => Token[] } | undefined + >('markdown'); import fileSaver from 'file-saver'; const { saveAs } = fileSaver; @@ -184,17 +187,19 @@ /> {:else if token.type === 'code'} - {#if token.codeBlockStyle !== 'indented'} + {#if markdown?.document || token.codeBlockStyle !== 'indented'} { onSave({ @@ -295,7 +300,7 @@ {:else if token.type === 'blockquote'} - {@const alert = alertComponent(token)} + {@const alert = alertComponent(token, markdown?.lexer)} {#if alert} {:else} @@ -327,6 +332,7 @@ { onTaskClick({ @@ -368,6 +374,7 @@ { onTaskClick({