|
4 | 4 | import 'overlayscrollbars/overlayscrollbars.css'; |
5 | 5 | import { OverlayScrollbars } from 'overlayscrollbars'; |
6 | 6 | import { v4 as uuidv4 } from 'uuid'; |
| 7 | + import LoadingDots from "$lib/common/LoadingDots.svelte"; |
7 | 8 |
|
8 | 9 | /** @type {import('$conversationTypes').ChatResponseModel?} */ |
9 | 10 | export let message; |
10 | 11 |
|
| 12 | + /** @type {string} */ |
| 13 | + export let containerClasses = ''; |
| 14 | +
|
| 15 | + /** @type {string} */ |
| 16 | + export let containerStyles = ''; |
| 17 | +
|
11 | 18 | /** @type {boolean} */ |
12 | 19 | export let scrollable = false; |
13 | 20 |
|
|
24 | 31 | } |
25 | 32 | }; |
26 | 33 |
|
| 34 | + /** @type {boolean} */ |
| 35 | + let isLoading = false; |
| 36 | +
|
27 | 37 | onMount(() => { |
28 | 38 | if (scrollable) { |
29 | 39 | initScrollbar(); |
|
46 | 56 | const parsedText = marked.lexer(text); |
47 | 57 | // @ts-ignore |
48 | 58 | const codeText = parsedText.filter(x => !!x.text).map(x => x.text).join(''); |
49 | | - loadScript(codeText); |
| 59 | + isLoading = true; |
| 60 | + loadScript(codeText).finally(() => { |
| 61 | + isLoading = false; |
| 62 | + }); |
50 | 63 | } catch (error) { |
51 | 64 | console.error('Error parsing js code:', error); |
52 | 65 | } |
53 | 66 | } |
54 | 67 |
|
55 | | - /** @param {string} codeText */ |
| 68 | + /** |
| 69 | + * @param {string} codeText |
| 70 | + * @returns {Promise<boolean>} |
| 71 | + */ |
56 | 72 | function loadScript(codeText) { |
57 | | - const code = codeText.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, '$1'); |
58 | | - const scriptTags = [...codeText.matchAll(/<script\s+[^>]*src\s*=\s*["']([^"']+)["'][^>]*>/gi)]; |
59 | | - const matchedSrcs = scriptTags.filter(x => !!x[1]).map(x => x[1]); |
| 73 | + return new Promise((resolve, reject) => { |
| 74 | + const code = codeText.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, '$1'); |
| 75 | + const scriptTags = [...codeText.matchAll(/<script\s+[^>]*src\s*=\s*["']([^"']+)["'][^>]*>/gi)]; |
| 76 | + const matchedSrcs = scriptTags.filter(x => !!x[1]).map(x => x[1]); |
60 | 77 |
|
61 | | - if (matchedSrcs.length > 0) { |
62 | | - const promises = matchedSrcs.map(x => loadScriptSrc(x)); |
63 | | - Promise.all(promises).then(() => setTimeout(() => eval(code), 0)); |
64 | | - } else { |
65 | | - setTimeout(() => eval(code), 0); |
66 | | - } |
| 78 | + if (matchedSrcs.length > 0) { |
| 79 | + const promises = matchedSrcs.map(x => loadScriptSrc(x)); |
| 80 | + Promise.all(promises).then(() => { |
| 81 | + setTimeout(() => { |
| 82 | + eval(code); |
| 83 | + resolve(true); |
| 84 | + }, 0); |
| 85 | + }).catch(() => { |
| 86 | + reject(false); |
| 87 | + }); |
| 88 | + } else { |
| 89 | + setTimeout(() => { |
| 90 | + eval(code); |
| 91 | + resolve(true); |
| 92 | + }, 0); |
| 93 | + } |
| 94 | + }); |
| 95 | + |
67 | 96 | } |
68 | 97 |
|
69 | 98 | /** @param {string} src */ |
|
95 | 124 | } |
96 | 125 | </script> |
97 | 126 |
|
98 | | -<div> |
| 127 | +<div class={`${containerClasses}`} style={`${containerStyles}`}> |
99 | 128 | {#if message?.text} |
100 | 129 | <div class="mb-3">{message.text}</div> |
101 | 130 | {/if} |
| 131 | + {#if isLoading} |
| 132 | + <div class="mb-3"> |
| 133 | + <LoadingDots duration={'1s'} size={5} gap={3} color={'var(--bs-primary)'} /> |
| 134 | + </div> |
| 135 | + {/if} |
102 | 136 | <div id={`${scrollbarId}`}> |
103 | 137 | <div id={`chart-${message?.message_id}`} style="min-width: 800px; max-height: 500px;"></div> |
104 | 138 | </div> |
|
0 commit comments