| | <script lang="ts"> |
| | import DOMPurify from 'dompurify'; |
| | import type { Token } from 'marked'; |
| |
|
| | import { WEBUI_BASE_URL } from '$lib/constants'; |
| | import { settings } from '$lib/stores'; |
| |
|
| | export let id: string; |
| | export let token: Token; |
| |
|
| | let html: string | null = null; |
| |
|
| | $: if (token.type === 'html' && token?.text) { |
| | html = DOMPurify.sanitize(token.text); |
| | } else { |
| | html = null; |
| | } |
| | </script> |
| |
|
| | {#if token.type === 'html'} |
| | {#if html && html.includes('<video')} |
| | {@const video = html.match(/<video[^>]*>([\s\S]*?)<\/video>/)} |
| | {@const videoSrc = video && video[1]} |
| | {#if videoSrc} |
| | <!-- svelte-ignore a11y-media-has-caption --> |
| | <video |
| | class="w-full my-2" |
| | src={videoSrc.replaceAll('&', '&')} |
| | title="Video player" |
| | frameborder="0" |
| | referrerpolicy="strict-origin-when-cross-origin" |
| | controls |
| | allowfullscreen |
| | ></video> |
| | {:else} |
| | {token.text} |
| | {/if} |
| | {:else if html && html.includes('<audio')} |
| | {@const audio = html.match(/<audio[^>]*>([\s\S]*?)<\/audio>/)} |
| | {@const audioSrc = audio && audio[1]} |
| | {#if audioSrc} |
| | <!-- svelte-ignore a11y-media-has-caption --> |
| | <audio |
| | class="w-full my-2" |
| | src={audioSrc.replaceAll('&', '&')} |
| | title="Audio player" |
| | controls |
| | ></audio> |
| | {:else} |
| | {token.text} |
| | {/if} |
| | {:else if token.text && token.text.match(/<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})(?:\?[^"]*)?"[^>]*><\/iframe>/)} |
| | {@const match = token.text.match( |
| | /<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})(?:\?[^"]*)?"[^>]*><\/iframe>/ |
| | )} |
| | {@const ytId = match && match[1]} |
| | {#if ytId} |
| | <iframe |
| | class="w-full aspect-video my-2" |
| | src={`https://www.youtube.com/embed/${ytId}`} |
| | title="YouTube video player" |
| | frameborder="0" |
| | allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" |
| | referrerpolicy="strict-origin-when-cross-origin" |
| | allowfullscreen |
| | > |
| | </iframe> |
| | {/if} |
| | {:else if token.text && token.text.includes('<iframe')} |
| | {@const match = token.text.match(/<iframe\s+[^>]*src="([^"]+)"[^>]*><\/iframe>/)} |
| | {@const iframeSrc = match && match[1]} |
| | {#if iframeSrc} |
| | <iframe |
| | class="w-full my-2" |
| | src={iframeSrc} |
| | title="Embedded content" |
| | frameborder="0" |
| | sandbox |
| | on:load={(e) => { |
| | try { |
| | e.currentTarget.style.height = |
| | e.currentTarget.contentWindow.document.body.scrollHeight + 20 + 'px'; |
| | } catch {} |
| | }} |
| | ></iframe> |
| | {:else} |
| | {token.text} |
| | {/if} |
| | {:else if token.text && token.text.includes('<status')} |
| | {@const match = token.text.match(/<status title="([^"]+)" done="(true|false)" ?\/?>/)} |
| | {@const statusTitle = match && match[1]} |
| | {@const statusDone = match && match[2] === 'true'} |
| | {#if statusTitle} |
| | <div class="flex flex-col justify-center -space-y-0.5"> |
| | <div |
| | class="{statusDone === false |
| | ? 'shimmer' |
| | : ''} text-gray-500 dark:text-gray-500 line-clamp-1 text-wrap" |
| | > |
| | {statusTitle} |
| | </div> |
| | </div> |
| | {:else} |
| | {token.text} |
| | {/if} |
| | {:else if token.text.includes(`<file type="html"`)} |
| | {@const match = token.text.match(/<file type="html" id="([^"]+)"/)} |
| | {@const fileId = match && match[1]} |
| | {#if fileId} |
| | <iframe |
| | class="w-full my-2" |
| | src={`${WEBUI_BASE_URL}/api/v1/files/${fileId}/content/html`} |
| | title="Content" |
| | frameborder="0" |
| | sandbox="allow-scripts allow-downloads{($settings?.iframeSandboxAllowForms ?? false) |
| | ? ' allow-forms' |
| | : ''}{($settings?.iframeSandboxAllowSameOrigin ?? false) ? ' allow-same-origin' : ''}" |
| | referrerpolicy="strict-origin-when-cross-origin" |
| | allowfullscreen |
| | width="100%" |
| | on:load={(e) => { |
| | try { |
| | e.currentTarget.style.height = |
| | e.currentTarget.contentWindow.document.body.scrollHeight + 20 + 'px'; |
| | } catch {} |
| | }} |
| | ></iframe> |
| | {/if} |
| | {:else if token.text.trim().match(/^<br\s*\/?>$/i)} |
| | <br /> |
| | {:else} |
| | {token.text} |
| | {/if} |
| | {/if} |
| |
|