Spaces:
Build error
Build error
File size: 2,390 Bytes
a3ae6ee c3aa4e3 fc15a4c 8811ee0 bd8c7a0 8811ee0 a3ae6ee 1b66f8d a3ae6ee e5eb656 fc15a4c a3ae6ee 8811ee0 a3ae6ee 663005a a3ae6ee |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
<script lang="ts">
import { marked } from 'marked';
import type { Message } from '$lib/types/Message';
import { afterUpdate } from 'svelte';
import CopyToClipBoardBtn from '../CopyToClipBoardBtn.svelte';
export let message: Message;
let html = '';
let el: HTMLElement;
const renderer = new marked.Renderer();
// Add wrapper to code blocks
renderer.code = (code, lang) => {
return `
<div class="code-block">
<pre>
<code class="language-${lang}">${code}</code>
</pre>
</div>
`.replaceAll('\t', '');
};
const handleParsed = (err: Error | null, parsedHtml: string) => {
if (err) {
console.error(err);
} else {
html = parsedHtml;
}
};
const options: marked.MarkedOptions = {
...marked.getDefaults(),
gfm: true,
highlight: (code, lang, callback) => {
import('highlight.js').then(
({ default: hljs }) => {
const language = hljs.getLanguage(lang);
callback?.(null, hljs.highlightAuto(code, language?.aliases).value);
},
(err) => {
console.error(err);
callback?.(err);
}
);
},
renderer
};
$: marked(message.content, options, handleParsed);
afterUpdate(() => {
if (el) {
const codeBlocks = el.querySelectorAll('.code-block');
// Add copy to clipboard button to each code block
codeBlocks.forEach((block) => {
if (block.classList.contains('has-copy-btn')) return;
new CopyToClipBoardBtn({
target: block,
props: {
value: (block as HTMLElement).innerText ?? '',
classNames: 'absolute top-2 right-2'
}
});
block.classList.add('has-copy-btn');
});
}
});
</script>
{#if message.from === 'assistant'}
<div class="flex items-start justify-start gap-4 leading-relaxed">
<img
alt=""
src="https://huggingface.co/avatars/2edb18bd0206c16b433841a47f53fa8e.svg"
class="mt-5 w-3 h-3 flex-none rounded-full shadow-lg"
/>
<div
class="group relative rounded-2xl px-5 py-3.5 border border-gray-100 bg-gradient-to-br from-gray-50 dark:from-gray-800/40 dark:border-gray-800 prose text-gray-600 dark:text-gray-300"
bind:this={el}
>
{@html html}
</div>
</div>
{/if}
{#if message.from === 'user'}
<div class="flex items-start justify-start gap-4">
<div class="mt-5 w-3 h-3 flex-none rounded-full" />
<div class="rounded-2xl px-5 py-3.5 text-gray-500 dark:text-gray-400">
{message.content}
</div>
</div>
{/if}
|