mirror of
https://github.com/open-webui/open-webui
synced 2025-01-10 21:07:59 +00:00
82 lines
2.5 KiB
Svelte
82 lines
2.5 KiB
Svelte
<script lang="ts">
|
|
import DOMPurify from 'dompurify';
|
|
import { toast } from 'svelte-sonner';
|
|
|
|
import type { Token } from 'marked';
|
|
import { getContext } from 'svelte';
|
|
|
|
const i18n = getContext('i18n');
|
|
|
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
|
import { copyToClipboard, revertSanitizedResponseContent, unescapeHtml } from '$lib/utils';
|
|
|
|
import Image from '$lib/components/common/Image.svelte';
|
|
import KatexRenderer from './KatexRenderer.svelte';
|
|
|
|
export let id: string;
|
|
export let tokens: Token[];
|
|
</script>
|
|
|
|
{#each tokens as token}
|
|
{#if token.type === 'escape'}
|
|
{unescapeHtml(token.text)}
|
|
{:else if token.type === 'html'}
|
|
{@const html = DOMPurify.sanitize(token.text)}
|
|
{#if html && html.includes('<video')}
|
|
{@html html}
|
|
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
|
|
{@html `${token.text}`}
|
|
{:else}
|
|
{token.text}
|
|
{/if}
|
|
{:else if token.type === 'link'}
|
|
{#if token.tokens}
|
|
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>
|
|
<svelte:self id={`${id}-a`} tokens={token.tokens} />
|
|
</a>
|
|
{:else}
|
|
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>{token.text}</a>
|
|
{/if}
|
|
{:else if token.type === 'image'}
|
|
<Image src={token.href} alt={token.text} />
|
|
{:else if token.type === 'strong'}
|
|
<strong>
|
|
<svelte:self id={`${id}-strong`} tokens={token.tokens} />
|
|
</strong>
|
|
{:else if token.type === 'em'}
|
|
<em>
|
|
<svelte:self id={`${id}-em`} tokens={token.tokens} />
|
|
</em>
|
|
{:else if token.type === 'codespan'}
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
|
<code
|
|
class="codespan cursor-pointer"
|
|
on:click={() => {
|
|
copyToClipboard(unescapeHtml(token.text));
|
|
toast.success($i18n.t('Copied to clipboard'));
|
|
}}>{unescapeHtml(token.text)}</code
|
|
>
|
|
{:else if token.type === 'br'}
|
|
<br />
|
|
{:else if token.type === 'del'}
|
|
<del>
|
|
<svelte:self id={`${id}-del`} tokens={token.tokens} />
|
|
</del>
|
|
{:else if token.type === 'inlineKatex'}
|
|
{#if token.text}
|
|
<KatexRenderer content={revertSanitizedResponseContent(token.text)} displayMode={false} />
|
|
{/if}
|
|
{:else if token.type === 'iframe'}
|
|
<iframe
|
|
src="{WEBUI_BASE_URL}/api/v1/files/{token.fileId}/content"
|
|
title={token.fileId}
|
|
width="100%"
|
|
frameborder="0"
|
|
onload="this.style.height=(this.contentWindow.document.body.scrollHeight+20)+'px';"
|
|
></iframe>
|
|
{:else if token.type === 'text'}
|
|
{token.raw}
|
|
{/if}
|
|
{/each}
|