/
MarkdownCode.svelte
98 lines (88 loc) 路 2.08 KB
/
MarkdownCode.svelte
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
98
<script lang="ts">
import { afterUpdate, createEventDispatcher } from "svelte";
import DOMPurify from "dompurify";
import render_math_in_element from "katex/dist/contrib/auto-render.js";
import "katex/dist/katex.min.css";
import { marked } from "./utils";
import "./prism.css";
export let chatbot = true;
export let message: string;
export let sanitize_html = true;
export let latex_delimiters: {
left: string;
right: string;
display: boolean;
}[];
let el: HTMLSpanElement;
let html: string;
DOMPurify.addHook("afterSanitizeAttributes", function (node) {
if ("target" in node) {
node.setAttribute("target", "_blank");
node.setAttribute("rel", "noopener noreferrer");
}
});
$: if (message && message.trim()) {
html = sanitize_html
? DOMPurify.sanitize(marked.parse(message))
: marked.parse(message);
} else {
html = "";
}
async function render_html(value: string): Promise<void> {
if (latex_delimiters.length > 0) {
render_math_in_element(el, {
delimiters: latex_delimiters,
throwOnError: false
});
}
}
afterUpdate(() => render_html(message));
</script>
<span class:chatbot bind:this={el} class="md">
{@html html}
</span>
<style>
span :global(div[class*="code_wrap"]) {
position: relative;
}
/* KaTeX */
span :global(span.katex) {
font-size: var(--text-lg);
direction: ltr;
}
span :global(div[class*="code_wrap"] > button) {
position: absolute;
top: var(--spacing-sm);
right: var(--spacing-sm);
z-index: 1;
cursor: pointer;
border-bottom-left-radius: var(--radius-sm);
padding: 5px;
padding: var(--spacing-md);
width: 25px;
height: 25px;
}
span :global(code > button > span) {
position: absolute;
top: var(--spacing-sm);
right: var(--spacing-sm);
width: 12px;
height: 12px;
}
span :global(.check) {
position: absolute;
top: 0;
right: 0;
opacity: 0;
z-index: var(--layer-top);
transition: opacity 0.2s;
background: var(--background-fill-primary);
padding: var(--size-1);
width: 100%;
height: 100%;
color: var(--body-text-color);
}
span :global(pre) {
position: relative;
}
</style>