@terryavg/neptune-ai-chatbot 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -2
- package/dist/chat-input-42V4ESQB.mjs +478 -0
- package/dist/chat-input-4T42R7FR.mjs +481 -0
- package/dist/chat-input-BJVIIYOP.mjs +484 -0
- package/dist/chat-input-HT47ZLQN.mjs +456 -0
- package/dist/chat-input-JFGPZBBQ.mjs +495 -0
- package/dist/chat-input-JQ7PSHNW.mjs +515 -0
- package/dist/chat-input-USWVSAYY.mjs +461 -0
- package/dist/chat-input-VTCTV5ED.mjs +495 -0
- package/dist/chat-input-WJMGLQJI.mjs +495 -0
- package/dist/chat-message-2VQW74CO.mjs +2230 -0
- package/dist/chat-message-35ZWSSQV.mjs +1926 -0
- package/dist/chat-message-3CUUWTZG.mjs +2429 -0
- package/dist/chat-message-3NHSJNKL.mjs +2241 -0
- package/dist/chat-message-3Z7B2WYC.mjs +2228 -0
- package/dist/chat-message-564AHZHH.mjs +2186 -0
- package/dist/chat-message-5QLTW4K7.mjs +2122 -0
- package/dist/chat-message-7EH2TDZG.mjs +1910 -0
- package/dist/chat-message-7QHJRHQG.mjs +1909 -0
- package/dist/chat-message-AAXNH5TF.mjs +2088 -0
- package/dist/chat-message-D36YF274.mjs +1910 -0
- package/dist/chat-message-DVCXEL4Z.mjs +2111 -0
- package/dist/chat-message-E6KB3AST.mjs +1906 -0
- package/dist/chat-message-G2NWPAXK.mjs +1904 -0
- package/dist/chat-message-H62Z3DW5.mjs +2368 -0
- package/dist/chat-message-HIEZ7B5R.mjs +2190 -0
- package/dist/chat-message-I6AKFPK6.mjs +2156 -0
- package/dist/chat-message-IKYSAVAB.mjs +1918 -0
- package/dist/chat-message-IZL6JHV2.mjs +2429 -0
- package/dist/chat-message-J7PVUQO6.mjs +1878 -0
- package/dist/chat-message-K6QILTW5.mjs +1897 -0
- package/dist/chat-message-MDORLI2R.mjs +2228 -0
- package/dist/chat-message-MFUY6KOE.mjs +1910 -0
- package/dist/chat-message-MYKOR5OF.mjs +1890 -0
- package/dist/chat-message-NKMTAMGG.mjs +1906 -0
- package/dist/chat-message-NNGD3FUH.mjs +2168 -0
- package/dist/chat-message-QAPRO542.mjs +1915 -0
- package/dist/chat-message-R4IJ3MXU.mjs +2146 -0
- package/dist/chat-message-U7UCBLHI.mjs +2145 -0
- package/dist/chat-message-UKXGFKUR.mjs +1903 -0
- package/dist/chat-message-UNIBCF3T.mjs +1900 -0
- package/dist/chat-message-UXLPL76T.mjs +1890 -0
- package/dist/chat-message-VB54UOHB.mjs +2306 -0
- package/dist/chat-message-WUNUZLKI.mjs +2228 -0
- package/dist/chat-message-WYN5UZRD.mjs +1927 -0
- package/dist/chat-message-Y5OJSR2O.mjs +2228 -0
- package/dist/chat-message-YPDHL6WW.mjs +2114 -0
- package/dist/chunk-26656QB3.mjs +406 -0
- package/dist/chunk-2RXQ2EZ2.mjs +295 -0
- package/dist/chunk-DVWFDUN4.mjs +407 -0
- package/dist/chunk-JLRHY3SB.mjs +405 -0
- package/dist/chunk-XFSEOBLD.mjs +432 -0
- package/dist/index.css +174 -43
- package/dist/index.d.mts +218 -1
- package/dist/index.d.ts +218 -1
- package/dist/index.js +2088 -1400
- package/dist/index.mjs +606 -413
- package/dist/styles.css +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,1906 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToolExecutionIndicator,
|
|
3
|
+
ToolExecutionWidget
|
|
4
|
+
} from "./chunk-C2VGAYER.mjs";
|
|
5
|
+
import {
|
|
6
|
+
__objRest,
|
|
7
|
+
__spreadProps,
|
|
8
|
+
__spreadValues
|
|
9
|
+
} from "./chunk-FWCSY2DS.mjs";
|
|
10
|
+
|
|
11
|
+
// app/components/chat-message.tsx
|
|
12
|
+
import {
|
|
13
|
+
useEffect,
|
|
14
|
+
useState,
|
|
15
|
+
memo,
|
|
16
|
+
useMemo,
|
|
17
|
+
useRef,
|
|
18
|
+
lazy,
|
|
19
|
+
Suspense
|
|
20
|
+
} from "react";
|
|
21
|
+
import ReactMarkdown from "react-markdown";
|
|
22
|
+
import remarkGfm from "remark-gfm";
|
|
23
|
+
import rehypeRaw from "rehype-raw";
|
|
24
|
+
import {
|
|
25
|
+
Copy,
|
|
26
|
+
Check,
|
|
27
|
+
FileText,
|
|
28
|
+
Image as ImageIcon,
|
|
29
|
+
X,
|
|
30
|
+
Download,
|
|
31
|
+
ChevronDown,
|
|
32
|
+
ChevronRight
|
|
33
|
+
} from "lucide-react";
|
|
34
|
+
import { marked } from "marked";
|
|
35
|
+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
36
|
+
import {
|
|
37
|
+
vscDarkPlus,
|
|
38
|
+
oneLight
|
|
39
|
+
} from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
40
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
41
|
+
var CodeBlock = memo(
|
|
42
|
+
({
|
|
43
|
+
language,
|
|
44
|
+
code,
|
|
45
|
+
theme
|
|
46
|
+
}) => {
|
|
47
|
+
const [copied, setCopied] = useState(false);
|
|
48
|
+
const handleCopy = (e) => {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
navigator.clipboard.writeText(code).then(() => {
|
|
51
|
+
setCopied(true);
|
|
52
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
53
|
+
}).catch((err) => console.error("Failed to copy code: ", err));
|
|
54
|
+
};
|
|
55
|
+
const getLanguageLabel = (lang) => {
|
|
56
|
+
const langMap = {
|
|
57
|
+
js: "JavaScript",
|
|
58
|
+
javascript: "JavaScript",
|
|
59
|
+
jsx: "JavaScript React",
|
|
60
|
+
ts: "TypeScript",
|
|
61
|
+
typescript: "TypeScript",
|
|
62
|
+
tsx: "TypeScript React",
|
|
63
|
+
py: "Python",
|
|
64
|
+
python: "Python",
|
|
65
|
+
java: "Java",
|
|
66
|
+
cpp: "C++",
|
|
67
|
+
c: "C",
|
|
68
|
+
cs: "C#",
|
|
69
|
+
csharp: "C#",
|
|
70
|
+
go: "Go",
|
|
71
|
+
rs: "Rust",
|
|
72
|
+
rust: "Rust",
|
|
73
|
+
php: "PHP",
|
|
74
|
+
rb: "Ruby",
|
|
75
|
+
ruby: "Ruby",
|
|
76
|
+
sh: "Shell",
|
|
77
|
+
shell: "Shell",
|
|
78
|
+
bash: "Bash",
|
|
79
|
+
zsh: "Zsh",
|
|
80
|
+
sql: "SQL",
|
|
81
|
+
html: "HTML",
|
|
82
|
+
css: "CSS",
|
|
83
|
+
scss: "SCSS",
|
|
84
|
+
json: "JSON",
|
|
85
|
+
xml: "XML",
|
|
86
|
+
yaml: "YAML",
|
|
87
|
+
yml: "YAML",
|
|
88
|
+
md: "Markdown",
|
|
89
|
+
markdown: "Markdown",
|
|
90
|
+
text: "Text",
|
|
91
|
+
plaintext: "Plain Text"
|
|
92
|
+
};
|
|
93
|
+
return langMap[lang.toLowerCase()] || lang.toUpperCase();
|
|
94
|
+
};
|
|
95
|
+
const isDark = theme === "dark";
|
|
96
|
+
const syntaxTheme = isDark ? vscDarkPlus : oneLight;
|
|
97
|
+
const bgColor = isDark ? "#1e1e1e" : "#e0e0e0";
|
|
98
|
+
const headerBg = isDark ? "#1e1e1e" : "#f5f5f5";
|
|
99
|
+
const borderColor = isDark ? "border-gray-700" : "border-gray-300";
|
|
100
|
+
const textColor = isDark ? "text-gray-300" : "text-gray-700";
|
|
101
|
+
const buttonHover = isDark ? "hover:bg-gray-700" : "hover:bg-gray-200";
|
|
102
|
+
const iconColor = isDark ? "text-gray-400" : "text-gray-600";
|
|
103
|
+
return /* @__PURE__ */ jsxs("div", { className: `mt-1 mb-3 rounded-lg border-2 ${borderColor}`, children: [
|
|
104
|
+
/* @__PURE__ */ jsxs(
|
|
105
|
+
"div",
|
|
106
|
+
{
|
|
107
|
+
className: `sticky top-0 z-20 flex items-center justify-between px-4 py-2 border-b ${borderColor} rounded-tl-lg rounded-tr-lg`,
|
|
108
|
+
style: { top: "-22px", backgroundColor: headerBg },
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs font-medium ${textColor}`, children: getLanguageLabel(language) }),
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
"button",
|
|
113
|
+
{
|
|
114
|
+
onClick: handleCopy,
|
|
115
|
+
className: `p-1.5 rounded transition-colors ${buttonHover}`,
|
|
116
|
+
title: "Copy code",
|
|
117
|
+
children: copied ? /* @__PURE__ */ jsx(Check, { size: 14, className: "text-green-500" }) : /* @__PURE__ */ jsx(Copy, { size: 14, className: iconColor })
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-80 overflow-auto", children: /* @__PURE__ */ jsx(
|
|
124
|
+
SyntaxHighlighter,
|
|
125
|
+
{
|
|
126
|
+
language: language.toLowerCase(),
|
|
127
|
+
style: syntaxTheme,
|
|
128
|
+
customStyle: {
|
|
129
|
+
margin: 0,
|
|
130
|
+
background: bgColor,
|
|
131
|
+
fontSize: "0.875rem",
|
|
132
|
+
padding: "1rem"
|
|
133
|
+
},
|
|
134
|
+
codeTagProps: {
|
|
135
|
+
style: {
|
|
136
|
+
backgroundColor: bgColor
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
children: code
|
|
140
|
+
}
|
|
141
|
+
) })
|
|
142
|
+
] });
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
CodeBlock.displayName = "CodeBlock";
|
|
146
|
+
var DynamicChartComponent = lazy(() => import("./chart-component-RCLR3IKU.mjs"));
|
|
147
|
+
var MemoizedChart = memo(
|
|
148
|
+
({
|
|
149
|
+
type,
|
|
150
|
+
data,
|
|
151
|
+
theme
|
|
152
|
+
}) => {
|
|
153
|
+
return /* @__PURE__ */ jsx(
|
|
154
|
+
Suspense,
|
|
155
|
+
{
|
|
156
|
+
fallback: /* @__PURE__ */ jsx("div", { className: "animate-pulse h-64 bg-gray-100 dark:bg-gray-800 rounded-lg" }),
|
|
157
|
+
children: /* @__PURE__ */ jsx(DynamicChartComponent, { type, data, theme })
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
(prevProps, nextProps) => {
|
|
162
|
+
return prevProps.type === nextProps.type && prevProps.theme === nextProps.theme && JSON.stringify(prevProps.data) === JSON.stringify(nextProps.data);
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
MemoizedChart.displayName = "MemoizedChart";
|
|
166
|
+
var JsonBlock = memo(
|
|
167
|
+
({
|
|
168
|
+
title,
|
|
169
|
+
jsonContent,
|
|
170
|
+
keyProp
|
|
171
|
+
}) => {
|
|
172
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
173
|
+
const [copyJsonSuccess, setCopyJsonSuccess] = useState(false);
|
|
174
|
+
const formattedJson = useMemo(() => {
|
|
175
|
+
try {
|
|
176
|
+
const parsed = JSON.parse(jsonContent.trim());
|
|
177
|
+
return JSON.stringify(parsed, null, 2);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error("Failed to parse JSON:", error);
|
|
180
|
+
return jsonContent;
|
|
181
|
+
}
|
|
182
|
+
}, [jsonContent]);
|
|
183
|
+
const highlightedJson = useMemo(() => {
|
|
184
|
+
return formattedJson.replace(
|
|
185
|
+
/"([^"]+)":/g,
|
|
186
|
+
'<span class="json-key">"$1"</span>:'
|
|
187
|
+
).replace(
|
|
188
|
+
/:\s*"([^"]*)"/g,
|
|
189
|
+
': <span class="json-string">"$1"</span>'
|
|
190
|
+
).replace(
|
|
191
|
+
/:\s*(-?\d+\.?\d*)/g,
|
|
192
|
+
': <span class="json-number">$1</span>'
|
|
193
|
+
).replace(
|
|
194
|
+
/:\s*(true|false)/g,
|
|
195
|
+
': <span class="json-boolean">$1</span>'
|
|
196
|
+
).replace(
|
|
197
|
+
/:\s*(null)/g,
|
|
198
|
+
': <span class="json-null">$1</span>'
|
|
199
|
+
);
|
|
200
|
+
}, [formattedJson]);
|
|
201
|
+
const handleCopyJson = (e) => {
|
|
202
|
+
e.stopPropagation();
|
|
203
|
+
navigator.clipboard.writeText(formattedJson).then(() => {
|
|
204
|
+
setCopyJsonSuccess(true);
|
|
205
|
+
setTimeout(() => setCopyJsonSuccess(false), 2e3);
|
|
206
|
+
}).catch((err) => console.error("Failed to copy JSON: ", err));
|
|
207
|
+
};
|
|
208
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-4 border border-gray-200 dark:border-gray-600 rounded-lg overflow-hidden bg-gray-50 dark:bg-gray-900", children: [
|
|
209
|
+
/* @__PURE__ */ jsxs(
|
|
210
|
+
"div",
|
|
211
|
+
{
|
|
212
|
+
onClick: () => setIsExpanded(!isExpanded),
|
|
213
|
+
className: "flex items-center justify-between p-4 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors bg-gray-50 bg-gray-900",
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
216
|
+
isExpanded ? /* @__PURE__ */ jsx(
|
|
217
|
+
ChevronDown,
|
|
218
|
+
{
|
|
219
|
+
size: 20,
|
|
220
|
+
className: "text-gray-600 dark:text-gray-300"
|
|
221
|
+
}
|
|
222
|
+
) : /* @__PURE__ */ jsx(
|
|
223
|
+
ChevronRight,
|
|
224
|
+
{
|
|
225
|
+
size: 20,
|
|
226
|
+
className: "text-gray-600 dark:text-gray-300"
|
|
227
|
+
}
|
|
228
|
+
),
|
|
229
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-gray-800 dark:text-white", children: title }),
|
|
230
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs px-2 py-0.5 bg-blue-100 dark:bg-blue-600 text-blue-700 dark:text-white rounded-full", children: "JSON" })
|
|
231
|
+
] }),
|
|
232
|
+
/* @__PURE__ */ jsx(
|
|
233
|
+
"button",
|
|
234
|
+
{
|
|
235
|
+
onClick: handleCopyJson,
|
|
236
|
+
className: "p-1.5 hover:bg-gray-200 dark:hover:bg-gray-600 rounded transition-colors",
|
|
237
|
+
title: "Copy JSON",
|
|
238
|
+
children: copyJsonSuccess ? /* @__PURE__ */ jsx(Check, { size: 16, className: "text-green-500" }) : /* @__PURE__ */ jsx(
|
|
239
|
+
Copy,
|
|
240
|
+
{
|
|
241
|
+
size: 16,
|
|
242
|
+
className: "text-gray-600 dark:text-gray-300"
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
isExpanded && /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx("pre", { className: "p-4 overflow-x-auto bg-white dark:bg-black text-sm font-mono", children: /* @__PURE__ */ jsx(
|
|
251
|
+
"code",
|
|
252
|
+
{
|
|
253
|
+
className: "language-json text-gray-800 dark:text-gray-100",
|
|
254
|
+
dangerouslySetInnerHTML: {
|
|
255
|
+
__html: highlightedJson
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
) }) }),
|
|
259
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
260
|
+
:global(.json-key) {
|
|
261
|
+
color: #d19a66;
|
|
262
|
+
}
|
|
263
|
+
:global(.json-string) {
|
|
264
|
+
color: #98c379;
|
|
265
|
+
}
|
|
266
|
+
:global(.json-number) {
|
|
267
|
+
color: #d19a66;
|
|
268
|
+
}
|
|
269
|
+
:global(.json-boolean) {
|
|
270
|
+
color: #56b6c2;
|
|
271
|
+
}
|
|
272
|
+
:global(.json-null) {
|
|
273
|
+
color: #c678dd;
|
|
274
|
+
}
|
|
275
|
+
:global(.dark .json-key) {
|
|
276
|
+
color: #e5c07b;
|
|
277
|
+
}
|
|
278
|
+
:global(.dark .json-string) {
|
|
279
|
+
color: #98c379;
|
|
280
|
+
}
|
|
281
|
+
:global(.dark .json-number) {
|
|
282
|
+
color: #d19a66;
|
|
283
|
+
}
|
|
284
|
+
:global(.dark .json-boolean) {
|
|
285
|
+
color: #61afef;
|
|
286
|
+
}
|
|
287
|
+
:global(.dark .json-null) {
|
|
288
|
+
color: #c678dd;
|
|
289
|
+
}
|
|
290
|
+
` })
|
|
291
|
+
] });
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
JsonBlock.displayName = "JsonBlock";
|
|
295
|
+
function ChatMessage({
|
|
296
|
+
message,
|
|
297
|
+
isStreaming = false,
|
|
298
|
+
theme,
|
|
299
|
+
onAppOpen,
|
|
300
|
+
onAnalyticOpen,
|
|
301
|
+
onWidgetSubmit,
|
|
302
|
+
onWidgetCancel,
|
|
303
|
+
messageBubbleColor = "#E5E3F8"
|
|
304
|
+
}) {
|
|
305
|
+
const { role, content } = message;
|
|
306
|
+
const [copied, setCopied] = useState(false);
|
|
307
|
+
const [imageDialogOpen, setImageDialogOpen] = useState(false);
|
|
308
|
+
const [selectedImage, setSelectedImage] = useState(null);
|
|
309
|
+
const [displayedLength, setDisplayedLength] = useState(0);
|
|
310
|
+
useEffect(() => {
|
|
311
|
+
if (isStreaming && typeof content === "string") {
|
|
312
|
+
const timer = setTimeout(() => {
|
|
313
|
+
setDisplayedLength(content.length);
|
|
314
|
+
}, 100);
|
|
315
|
+
return () => clearTimeout(timer);
|
|
316
|
+
} else if (!isStreaming) {
|
|
317
|
+
setDisplayedLength(0);
|
|
318
|
+
}
|
|
319
|
+
}, [content, isStreaming]);
|
|
320
|
+
const messageContainerRef = useRef(null);
|
|
321
|
+
const handleImageClick = (imageSrc, imageAlt = "Image") => {
|
|
322
|
+
setSelectedImage({ src: imageSrc, alt: imageAlt });
|
|
323
|
+
setImageDialogOpen(true);
|
|
324
|
+
};
|
|
325
|
+
const closeImageDialog = () => {
|
|
326
|
+
setImageDialogOpen(false);
|
|
327
|
+
setSelectedImage(null);
|
|
328
|
+
};
|
|
329
|
+
useEffect(() => {
|
|
330
|
+
const handleEscape = (e) => {
|
|
331
|
+
if (e.key === "Escape" && imageDialogOpen) {
|
|
332
|
+
closeImageDialog();
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
if (imageDialogOpen) {
|
|
336
|
+
document.addEventListener("keydown", handleEscape);
|
|
337
|
+
document.body.style.overflow = "hidden";
|
|
338
|
+
}
|
|
339
|
+
return () => {
|
|
340
|
+
document.removeEventListener("keydown", handleEscape);
|
|
341
|
+
document.body.style.overflow = "unset";
|
|
342
|
+
};
|
|
343
|
+
}, [imageDialogOpen]);
|
|
344
|
+
const detectChartBlocks = (markdown) => {
|
|
345
|
+
const chartPattern = /```chart:([a-z]+)\n([\s\S]*?)\n```/g;
|
|
346
|
+
const charts = [];
|
|
347
|
+
let match;
|
|
348
|
+
while ((match = chartPattern.exec(markdown)) !== null) {
|
|
349
|
+
charts.push({
|
|
350
|
+
type: match[1],
|
|
351
|
+
data: match[2],
|
|
352
|
+
index: match.index,
|
|
353
|
+
fullMatch: match[0]
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return charts;
|
|
357
|
+
};
|
|
358
|
+
const captureChartsAsImages = async () => {
|
|
359
|
+
if (!messageContainerRef.current) {
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
const canvases = messageContainerRef.current.querySelectorAll("canvas");
|
|
363
|
+
const images = [];
|
|
364
|
+
canvases.forEach((canvas) => {
|
|
365
|
+
try {
|
|
366
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
367
|
+
images.push(dataUrl);
|
|
368
|
+
} catch (e) {
|
|
369
|
+
console.error("Failed to capture chart canvas:", e);
|
|
370
|
+
images.push("");
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
return images;
|
|
374
|
+
};
|
|
375
|
+
const convertMarkdownToStyledHTML = (markdown, chartImages) => {
|
|
376
|
+
let processedMarkdown = markdown;
|
|
377
|
+
if (chartImages && chartImages.length > 0) {
|
|
378
|
+
const chartBlocks = detectChartBlocks(markdown);
|
|
379
|
+
chartBlocks.reverse().forEach((chart, index) => {
|
|
380
|
+
const imageIndex = chartBlocks.length - 1 - index;
|
|
381
|
+
const imageData = chartImages[imageIndex];
|
|
382
|
+
if (imageData) {
|
|
383
|
+
const imgTag = `
|
|
384
|
+
|
|
385
|
+

|
|
386
|
+
|
|
387
|
+
`;
|
|
388
|
+
processedMarkdown = processedMarkdown.substring(0, chart.index) + imgTag + processedMarkdown.substring(
|
|
389
|
+
chart.index + chart.fullMatch.length
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
marked.setOptions({
|
|
395
|
+
gfm: true,
|
|
396
|
+
// GitHub Flavored Markdown
|
|
397
|
+
breaks: true
|
|
398
|
+
// Convert \n to <br>
|
|
399
|
+
});
|
|
400
|
+
let html = marked.parse(processedMarkdown);
|
|
401
|
+
const styledHTML = `
|
|
402
|
+
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; font-size: 14px; line-height: 1.6; color: #333;">
|
|
403
|
+
${html}
|
|
404
|
+
</div>
|
|
405
|
+
`;
|
|
406
|
+
return styledHTML.replace(
|
|
407
|
+
/<h1>/g,
|
|
408
|
+
'<h1 style="font-size: 2em; font-weight: bold; margin: 0.67em 0; color: #1a1a1a;">'
|
|
409
|
+
).replace(
|
|
410
|
+
/<h2>/g,
|
|
411
|
+
'<h2 style="font-size: 1.5em; font-weight: bold; margin: 0.75em 0; color: #1a1a1a;">'
|
|
412
|
+
).replace(
|
|
413
|
+
/<h3>/g,
|
|
414
|
+
'<h3 style="font-size: 1.17em; font-weight: bold; margin: 0.83em 0; color: #1a1a1a;">'
|
|
415
|
+
).replace(
|
|
416
|
+
/<h4>/g,
|
|
417
|
+
'<h4 style="font-size: 1em; font-weight: bold; margin: 1em 0; color: #1a1a1a;">'
|
|
418
|
+
).replace(
|
|
419
|
+
/<h5>/g,
|
|
420
|
+
'<h5 style="font-size: 0.83em; font-weight: bold; margin: 1.17em 0; color: #1a1a1a;">'
|
|
421
|
+
).replace(
|
|
422
|
+
/<h6>/g,
|
|
423
|
+
'<h6 style="font-size: 0.67em; font-weight: bold; margin: 1.33em 0; color: #1a1a1a;">'
|
|
424
|
+
).replace(/<p>/g, '<p style="margin: 0.5em 0;">').replace(/<strong>/g, '<strong style="font-weight: bold;">').replace(/<em>/g, '<em style="font-style: italic;">').replace(
|
|
425
|
+
/<pre>/g,
|
|
426
|
+
`<pre style="background-color: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; padding: 12px; overflow-x: auto; margin: 1em 0; font-family: 'Courier New', Courier, monospace; font-size: 13px;">`
|
|
427
|
+
).replace(
|
|
428
|
+
/<code>/g,
|
|
429
|
+
`<code style="font-family: 'Courier New', Courier, monospace; font-size: 13px; background-color: #f5f5f5; padding: 2px 4px; border-radius: 3px;">`
|
|
430
|
+
).replace(
|
|
431
|
+
/<ul>/g,
|
|
432
|
+
'<ul style="margin: 0.5em 0; padding-left: 2em; list-style-type: disc;">'
|
|
433
|
+
).replace(
|
|
434
|
+
/<ol>/g,
|
|
435
|
+
'<ol style="margin: 0.5em 0; padding-left: 2em; list-style-type: decimal;">'
|
|
436
|
+
).replace(/<li>/g, '<li style="margin: 0.25em 0;">').replace(
|
|
437
|
+
/<table>/g,
|
|
438
|
+
'<table style="border-collapse: collapse; width: 100%; margin: 1em 0; border: 1px solid #ddd;">'
|
|
439
|
+
).replace(
|
|
440
|
+
/<th>/g,
|
|
441
|
+
'<th style="border: 1px solid #ddd; padding: 8px 12px; background-color: #f5f5f5; font-weight: bold; text-align: left;">'
|
|
442
|
+
).replace(
|
|
443
|
+
/<td>/g,
|
|
444
|
+
'<td style="border: 1px solid #ddd; padding: 8px 12px;">'
|
|
445
|
+
).replace(/<tr>/g, '<tr style="border-bottom: 1px solid #ddd;">').replace(
|
|
446
|
+
/<a href=/g,
|
|
447
|
+
'<a style="color: #0066cc; text-decoration: underline;" href='
|
|
448
|
+
).replace(
|
|
449
|
+
/<blockquote>/g,
|
|
450
|
+
'<blockquote style="border-left: 4px solid #ddd; margin: 1em 0; padding: 0.5em 1em; color: #666; background-color: #f9f9f9;">'
|
|
451
|
+
).replace(
|
|
452
|
+
/<hr>/g,
|
|
453
|
+
'<hr style="border: none; border-top: 1px solid #ddd; margin: 1em 0;">'
|
|
454
|
+
).replace(
|
|
455
|
+
/<img /g,
|
|
456
|
+
'<img style="max-width: 100%; height: auto; display: block; margin: 1em 0; border: 1px solid #ddd; border-radius: 4px;" '
|
|
457
|
+
);
|
|
458
|
+
};
|
|
459
|
+
const copyToClipboard = async () => {
|
|
460
|
+
const textToCopy = typeof content === "string" ? content : Array.isArray(content) ? content.filter((part) => part.type === "text").map((part) => part.text).join("\n") : "";
|
|
461
|
+
try {
|
|
462
|
+
if (navigator.clipboard && window.ClipboardItem) {
|
|
463
|
+
const chartImages = await captureChartsAsImages();
|
|
464
|
+
const htmlContent = convertMarkdownToStyledHTML(
|
|
465
|
+
textToCopy,
|
|
466
|
+
chartImages
|
|
467
|
+
);
|
|
468
|
+
const blob = new Blob([htmlContent], { type: "text/html" });
|
|
469
|
+
const textBlob = new Blob([textToCopy], { type: "text/plain" });
|
|
470
|
+
const clipboardItem = new ClipboardItem({
|
|
471
|
+
"text/html": blob,
|
|
472
|
+
"text/plain": textBlob
|
|
473
|
+
});
|
|
474
|
+
await navigator.clipboard.write([clipboardItem]);
|
|
475
|
+
setCopied(true);
|
|
476
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
477
|
+
} else {
|
|
478
|
+
await navigator.clipboard.writeText(textToCopy);
|
|
479
|
+
setCopied(true);
|
|
480
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
481
|
+
}
|
|
482
|
+
} catch (err) {
|
|
483
|
+
console.error("Failed to copy: ", err);
|
|
484
|
+
try {
|
|
485
|
+
await navigator.clipboard.writeText(textToCopy);
|
|
486
|
+
setCopied(true);
|
|
487
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
488
|
+
} catch (fallbackErr) {
|
|
489
|
+
console.error("Fallback copy also failed: ", fallbackErr);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
const StreamingIndicator = () => {
|
|
494
|
+
if (!isStreaming || role !== "assistant") {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-3 inline-flex items-center", children: [
|
|
498
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-1", children: [
|
|
499
|
+
/* @__PURE__ */ jsx("div", { className: "naia-spinner" }),
|
|
500
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2 text-sm font-medium bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent", children: "NAIA is working on it..." })
|
|
501
|
+
] }),
|
|
502
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
503
|
+
.naia-spinner {
|
|
504
|
+
display: inline-flex;
|
|
505
|
+
align-items: center;
|
|
506
|
+
justify-content: center;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.naia-spinner img {
|
|
510
|
+
animation: bounce 1.5s ease-in-out infinite;
|
|
511
|
+
filter: drop-shadow(0 2px 8px rgba(168, 140, 250, 0.3));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
@keyframes bounce {
|
|
515
|
+
0%, 100% {
|
|
516
|
+
transform: translateY(0px);
|
|
517
|
+
}
|
|
518
|
+
50% {
|
|
519
|
+
transform: translateY(-8px);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/* Dark mode adjustments */
|
|
524
|
+
:global(.dark) .naia-spinner img {
|
|
525
|
+
filter: drop-shadow(0 2px 8px rgba(168, 140, 250, 0.4));
|
|
526
|
+
}
|
|
527
|
+
` })
|
|
528
|
+
] });
|
|
529
|
+
};
|
|
530
|
+
const renderChart = (chartType, chartData, key) => {
|
|
531
|
+
try {
|
|
532
|
+
const cleanJsonString = chartData.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
|
|
533
|
+
const parsedData = JSON.parse(cleanJsonString);
|
|
534
|
+
const formattedData = parsedData.data ? parsedData : { data: parsedData };
|
|
535
|
+
return /* @__PURE__ */ jsx(
|
|
536
|
+
MemoizedChart,
|
|
537
|
+
{
|
|
538
|
+
type: chartType,
|
|
539
|
+
data: formattedData,
|
|
540
|
+
theme
|
|
541
|
+
},
|
|
542
|
+
key || `chart-${chartType}-${cleanJsonString.length}`
|
|
543
|
+
);
|
|
544
|
+
} catch (error) {
|
|
545
|
+
console.error("Failed to parse chart data:", error);
|
|
546
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-6 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-300 rounded-lg border border-red-100 dark:border-red-800 w-full max-w-full my-4", children: [
|
|
547
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
|
|
548
|
+
/* @__PURE__ */ jsx(
|
|
549
|
+
"svg",
|
|
550
|
+
{
|
|
551
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
552
|
+
className: "h-5 w-5",
|
|
553
|
+
viewBox: "0 0 20 20",
|
|
554
|
+
fill: "currentColor",
|
|
555
|
+
children: /* @__PURE__ */ jsx(
|
|
556
|
+
"path",
|
|
557
|
+
{
|
|
558
|
+
fillRule: "evenodd",
|
|
559
|
+
d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z",
|
|
560
|
+
clipRule: "evenodd"
|
|
561
|
+
}
|
|
562
|
+
)
|
|
563
|
+
}
|
|
564
|
+
),
|
|
565
|
+
/* @__PURE__ */ jsx("h3", { className: "font-medium", children: "Unable to generate chart" })
|
|
566
|
+
] }),
|
|
567
|
+
/* @__PURE__ */ jsx("p", { className: "ml-8 text-sm", children: "The data format is not compatible with the requested chart type. Please try a different visualization or check the data structure." })
|
|
568
|
+
] });
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
const renderImage = (imageData, key) => {
|
|
572
|
+
const trimmedData = imageData.trim();
|
|
573
|
+
return /* @__PURE__ */ jsx(
|
|
574
|
+
"div",
|
|
575
|
+
{
|
|
576
|
+
className: "my-6 p-2",
|
|
577
|
+
children: /* @__PURE__ */ jsxs("div", { className: "max-w-full", children: [
|
|
578
|
+
/* @__PURE__ */ jsx(
|
|
579
|
+
"img",
|
|
580
|
+
{
|
|
581
|
+
src: trimmedData,
|
|
582
|
+
alt: "Generated image",
|
|
583
|
+
className: "max-w-full max-h-96 rounded-md object-contain mb-2 cursor-pointer hover:opacity-90 transition-opacity",
|
|
584
|
+
onClick: () => handleImageClick(trimmedData, "Generated image"),
|
|
585
|
+
onError: (e) => {
|
|
586
|
+
console.error("Failed to load image:", trimmedData);
|
|
587
|
+
e.target.style.display = "none";
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
),
|
|
591
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-end text-sm mr-2", children: /* @__PURE__ */ jsx(
|
|
592
|
+
"a",
|
|
593
|
+
{
|
|
594
|
+
href: trimmedData,
|
|
595
|
+
download: "generated-image.jpeg",
|
|
596
|
+
className: "text-blue-500 hover:text-blue-600",
|
|
597
|
+
children: "Download"
|
|
598
|
+
}
|
|
599
|
+
) })
|
|
600
|
+
] })
|
|
601
|
+
},
|
|
602
|
+
key || `image-${trimmedData.substring(0, 50)}`
|
|
603
|
+
);
|
|
604
|
+
};
|
|
605
|
+
const renderApp = (appName, appUrl, key) => {
|
|
606
|
+
const handleAppClick = () => {
|
|
607
|
+
if (onAppOpen) {
|
|
608
|
+
onAppOpen(appName, appUrl);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
return /* @__PURE__ */ jsx(
|
|
612
|
+
"div",
|
|
613
|
+
{
|
|
614
|
+
onClick: handleAppClick,
|
|
615
|
+
className: "my-6 p-4 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 cursor-pointer",
|
|
616
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
617
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-blue-500 flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
618
|
+
"svg",
|
|
619
|
+
{
|
|
620
|
+
className: "w-6 h-6 text-white",
|
|
621
|
+
fill: "none",
|
|
622
|
+
stroke: "currentColor",
|
|
623
|
+
viewBox: "0 0 24 24",
|
|
624
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
625
|
+
children: /* @__PURE__ */ jsx(
|
|
626
|
+
"path",
|
|
627
|
+
{
|
|
628
|
+
strokeLinecap: "round",
|
|
629
|
+
strokeLinejoin: "round",
|
|
630
|
+
strokeWidth: 2,
|
|
631
|
+
d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
}
|
|
635
|
+
) }),
|
|
636
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
637
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-800 dark:text-gray-200", children: appName }),
|
|
638
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Click to open application" })
|
|
639
|
+
] })
|
|
640
|
+
] }) })
|
|
641
|
+
},
|
|
642
|
+
key || `app-${appName}`
|
|
643
|
+
);
|
|
644
|
+
};
|
|
645
|
+
const renderJson = (title, jsonData, key) => {
|
|
646
|
+
return /* @__PURE__ */ jsx(
|
|
647
|
+
JsonBlock,
|
|
648
|
+
{
|
|
649
|
+
title,
|
|
650
|
+
jsonContent: jsonData.trim(),
|
|
651
|
+
keyProp: key || `json-${title.replace(/\s/g, "")}`
|
|
652
|
+
},
|
|
653
|
+
key || `json-${title.replace(/\s/g, "")}`
|
|
654
|
+
);
|
|
655
|
+
};
|
|
656
|
+
const renderAnalytic = (analyticData, key) => {
|
|
657
|
+
var _a;
|
|
658
|
+
const lines = analyticData.trim().split("\n");
|
|
659
|
+
const headers = ((_a = lines[0]) == null ? void 0 : _a.split(";")) || [];
|
|
660
|
+
const dataRows = lines.slice(1);
|
|
661
|
+
const recordCount = dataRows.length;
|
|
662
|
+
const columnCount = headers.length;
|
|
663
|
+
const datasetName = headers.length > 0 ? `Dataset (${headers.join(", ")})` : "Analytics Dataset";
|
|
664
|
+
const handleAnalyticClick = () => {
|
|
665
|
+
if (onAnalyticOpen) {
|
|
666
|
+
onAnalyticOpen(datasetName, analyticData);
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
return /* @__PURE__ */ jsx(
|
|
670
|
+
"div",
|
|
671
|
+
{
|
|
672
|
+
onClick: handleAnalyticClick,
|
|
673
|
+
className: "my-6 p-4 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-r from-emerald-50 to-teal-50 dark:from-emerald-900/20 dark:to-teal-900/20 cursor-pointer hover:shadow-md transition-shadow",
|
|
674
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
675
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
676
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-emerald-500 flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
677
|
+
"svg",
|
|
678
|
+
{
|
|
679
|
+
className: "w-6 h-6 text-white",
|
|
680
|
+
fill: "none",
|
|
681
|
+
stroke: "currentColor",
|
|
682
|
+
viewBox: "0 0 24 24",
|
|
683
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
684
|
+
children: /* @__PURE__ */ jsx(
|
|
685
|
+
"path",
|
|
686
|
+
{
|
|
687
|
+
strokeLinecap: "round",
|
|
688
|
+
strokeLinejoin: "round",
|
|
689
|
+
strokeWidth: 2,
|
|
690
|
+
d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
}
|
|
694
|
+
) }),
|
|
695
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
696
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-800 dark:text-gray-200", children: "Analytics Dataset" }),
|
|
697
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: [
|
|
698
|
+
recordCount,
|
|
699
|
+
" records, ",
|
|
700
|
+
columnCount,
|
|
701
|
+
" columns - Click to analyze"
|
|
702
|
+
] }),
|
|
703
|
+
headers.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-500 mt-1", children: [
|
|
704
|
+
"Fields: ",
|
|
705
|
+
headers.slice(0, 3).join(", "),
|
|
706
|
+
headers.length > 3 ? ` (+${headers.length - 3} more)` : ""
|
|
707
|
+
] })
|
|
708
|
+
] })
|
|
709
|
+
] }),
|
|
710
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-1 bg-emerald-100 dark:bg-emerald-800/30 text-emerald-700 dark:text-emerald-300 text-xs font-medium rounded-full", children: "Pivot Table" })
|
|
711
|
+
] })
|
|
712
|
+
},
|
|
713
|
+
key || `analytic-${analyticData.substring(0, 50)}`
|
|
714
|
+
);
|
|
715
|
+
};
|
|
716
|
+
const ImageLoadingIndicator = memo(
|
|
717
|
+
({ isStreaming: isStreaming2 }) => {
|
|
718
|
+
useEffect(() => {
|
|
719
|
+
if (isStreaming2) {
|
|
720
|
+
const timeout = setTimeout(() => {
|
|
721
|
+
console.warn(
|
|
722
|
+
"Image generation timeout - this may indicate a streaming issue"
|
|
723
|
+
);
|
|
724
|
+
}, 3e4);
|
|
725
|
+
return () => clearTimeout(timeout);
|
|
726
|
+
}
|
|
727
|
+
}, [isStreaming2]);
|
|
728
|
+
return /* @__PURE__ */ jsxs(
|
|
729
|
+
"div",
|
|
730
|
+
{
|
|
731
|
+
className: "my-6 p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 w-full block",
|
|
732
|
+
style: {
|
|
733
|
+
display: "block",
|
|
734
|
+
contain: "layout",
|
|
735
|
+
marginTop: "1.5rem",
|
|
736
|
+
marginBottom: "1.5rem",
|
|
737
|
+
overscrollBehavior: "contain",
|
|
738
|
+
scrollSnapStop: "always"
|
|
739
|
+
},
|
|
740
|
+
children: [
|
|
741
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
742
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-indigo-100 dark:bg-indigo-900 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-5 w-5 border-2 border-indigo-500 dark:border-indigo-400 border-t-transparent rounded-full" }) }),
|
|
743
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-gray-700 dark:text-gray-300", children: "Generating image..." })
|
|
744
|
+
] }),
|
|
745
|
+
/* @__PURE__ */ jsx("div", { className: "h-64 md:h-80 relative rounded-md overflow-hidden bg-gray-100 dark:bg-gray-700 w-full flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "w-full h-full bg-gradient-to-r from-gray-200 via-gray-300 to-gray-200 dark:from-gray-600 dark:via-gray-500 dark:to-gray-600 animate-pulse relative overflow-hidden", children: [
|
|
746
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent animate-[shimmer_2s_infinite] -translate-x-full" }),
|
|
747
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
748
|
+
ImageIcon,
|
|
749
|
+
{
|
|
750
|
+
size: 48,
|
|
751
|
+
className: "text-gray-400 dark:text-gray-500"
|
|
752
|
+
}
|
|
753
|
+
) }),
|
|
754
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 w-4 h-4 border-l-2 border-t-2 border-gray-400 dark:border-gray-500" }),
|
|
755
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2 w-4 h-4 border-r-2 border-t-2 border-gray-400 dark:border-gray-500" }),
|
|
756
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-2 left-2 w-4 h-4 border-l-2 border-b-2 border-gray-400 dark:border-gray-500" }),
|
|
757
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-2 right-2 w-4 h-4 border-r-2 border-b-2 border-gray-400 dark:border-gray-500" })
|
|
758
|
+
] }) }),
|
|
759
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-between text-xs text-gray-500 dark:text-gray-400", children: [
|
|
760
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
761
|
+
/* @__PURE__ */ jsx("div", { className: "w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500 animate-pulse" }),
|
|
762
|
+
/* @__PURE__ */ jsx("span", { children: "Processing image data..." })
|
|
763
|
+
] }),
|
|
764
|
+
/* @__PURE__ */ jsx("div", { children: "Please wait..." })
|
|
765
|
+
] }),
|
|
766
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
767
|
+
@keyframes shimmer {
|
|
768
|
+
0% {
|
|
769
|
+
transform: translateX(-100%);
|
|
770
|
+
}
|
|
771
|
+
100% {
|
|
772
|
+
transform: translateX(100%);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
` })
|
|
776
|
+
]
|
|
777
|
+
}
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
ImageLoadingIndicator.displayName = "ImageLoadingIndicator";
|
|
782
|
+
const renderImageLoading = () => {
|
|
783
|
+
return /* @__PURE__ */ jsx(ImageLoadingIndicator, { isStreaming });
|
|
784
|
+
};
|
|
785
|
+
const renderChartLoading = (type = "unknown") => {
|
|
786
|
+
const normalizedType = type.toLowerCase();
|
|
787
|
+
return /* @__PURE__ */ jsxs(
|
|
788
|
+
"div",
|
|
789
|
+
{
|
|
790
|
+
className: "my-6 p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 w-full block",
|
|
791
|
+
style: {
|
|
792
|
+
display: "block",
|
|
793
|
+
contain: "layout",
|
|
794
|
+
marginTop: "1.5rem",
|
|
795
|
+
marginBottom: "1.5rem",
|
|
796
|
+
overscrollBehavior: "contain",
|
|
797
|
+
scrollSnapStop: "always"
|
|
798
|
+
},
|
|
799
|
+
children: [
|
|
800
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
801
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-indigo-100 dark:bg-indigo-900 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-5 w-5 border-2 border-indigo-500 dark:border-indigo-400 border-t-transparent rounded-full" }) }),
|
|
802
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-700 dark:text-gray-300", children: [
|
|
803
|
+
"Generating ",
|
|
804
|
+
normalizedType,
|
|
805
|
+
" chart..."
|
|
806
|
+
] })
|
|
807
|
+
] }),
|
|
808
|
+
/* @__PURE__ */ jsxs("div", { className: "h-64 md:h-80 relative rounded-md overflow-hidden bg-gray-100 dark:bg-gray-700 w-full", children: [
|
|
809
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 w-full h-0.5 bg-gray-300 dark:bg-gray-600" }),
|
|
810
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 w-0.5 h-full bg-gray-300 dark:bg-gray-600" }),
|
|
811
|
+
[1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx(
|
|
812
|
+
"div",
|
|
813
|
+
{
|
|
814
|
+
className: "absolute w-full h-px bg-gray-200 dark:bg-gray-600",
|
|
815
|
+
style: { bottom: `${i * 20}%` }
|
|
816
|
+
},
|
|
817
|
+
`h-${i}`
|
|
818
|
+
)),
|
|
819
|
+
[1, 2, 3, 4, 5, 6, 7, 8].map((i) => /* @__PURE__ */ jsx(
|
|
820
|
+
"div",
|
|
821
|
+
{
|
|
822
|
+
className: "absolute h-full w-px bg-gray-200 dark:bg-gray-600",
|
|
823
|
+
style: { left: `${i * 12.5}%` }
|
|
824
|
+
},
|
|
825
|
+
`v-${i}`
|
|
826
|
+
)),
|
|
827
|
+
normalizedType === "bar" && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 w-full h-full flex items-end justify-around p-4", children: [45, 80, 30, 65, 50, 75, 40].map((h, i) => /* @__PURE__ */ jsx(
|
|
828
|
+
"div",
|
|
829
|
+
{
|
|
830
|
+
className: "w-8 bg-gray-300 dark:bg-gray-600 animate-pulse rounded-t-sm opacity-60",
|
|
831
|
+
style: { height: `${h}%` }
|
|
832
|
+
},
|
|
833
|
+
`bar-${i}`
|
|
834
|
+
)) }),
|
|
835
|
+
normalizedType === "line" && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 w-full h-full flex items-end justify-around p-4", children: [45, 80, 30, 65, 50, 75, 40].map((h, i) => /* @__PURE__ */ jsx(
|
|
836
|
+
"div",
|
|
837
|
+
{
|
|
838
|
+
className: "w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500 animate-pulse",
|
|
839
|
+
style: {
|
|
840
|
+
position: "absolute",
|
|
841
|
+
bottom: `${h}%`,
|
|
842
|
+
left: `${10 + i * 12}%`
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
`point-${i}`
|
|
846
|
+
)) }),
|
|
847
|
+
(normalizedType === "pie" || normalizedType === "doughnut") && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex items-center justify-center", children: [
|
|
848
|
+
/* @__PURE__ */ jsx(
|
|
849
|
+
"div",
|
|
850
|
+
{
|
|
851
|
+
className: `w-32 h-32 rounded-full border-8 border-gray-300 dark:border-gray-600 animate-pulse ${normalizedType === "doughnut" ? "border-[16px]" : "border-8"}`
|
|
852
|
+
}
|
|
853
|
+
),
|
|
854
|
+
/* @__PURE__ */ jsx("div", { className: "absolute w-32 h-32", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx(
|
|
855
|
+
"div",
|
|
856
|
+
{
|
|
857
|
+
className: "absolute w-16 h-0.5 bg-gray-400 dark:bg-gray-500 origin-left",
|
|
858
|
+
style: {
|
|
859
|
+
left: "50%",
|
|
860
|
+
top: "50%",
|
|
861
|
+
transform: `rotate(${i * 45}deg)`
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
`slice-${i}`
|
|
865
|
+
)) })
|
|
866
|
+
] }),
|
|
867
|
+
normalizedType === "scatter" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: Array.from({ length: 15 }).map((_, i) => {
|
|
868
|
+
const x = 10 + Math.random() * 80;
|
|
869
|
+
const y = 10 + Math.random() * 80;
|
|
870
|
+
return /* @__PURE__ */ jsx(
|
|
871
|
+
"div",
|
|
872
|
+
{
|
|
873
|
+
className: "absolute w-3 h-3 rounded-full bg-gray-400 dark:bg-gray-500 animate-pulse",
|
|
874
|
+
style: {
|
|
875
|
+
left: `${x}%`,
|
|
876
|
+
bottom: `${y}%`,
|
|
877
|
+
animationDelay: `${i * 100}ms`
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
`scatter-${i}`
|
|
881
|
+
);
|
|
882
|
+
}) }),
|
|
883
|
+
normalizedType === "radar" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "w-48 h-48 relative", children: [
|
|
884
|
+
[1, 2, 3].map((level) => /* @__PURE__ */ jsx(
|
|
885
|
+
"div",
|
|
886
|
+
{
|
|
887
|
+
className: "absolute rounded-full border border-gray-300 dark:border-gray-600",
|
|
888
|
+
style: {
|
|
889
|
+
width: `${level * 33}%`,
|
|
890
|
+
height: `${level * 33}%`,
|
|
891
|
+
left: `${50 - level * 33 / 2}%`,
|
|
892
|
+
top: `${50 - level * 33 / 2}%`
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
`radar-web-${level}`
|
|
896
|
+
)),
|
|
897
|
+
[0, 60, 120, 180, 240, 300].map((angle) => /* @__PURE__ */ jsx(
|
|
898
|
+
"div",
|
|
899
|
+
{
|
|
900
|
+
className: "absolute w-24 h-0.5 bg-gray-300 dark:bg-gray-600 origin-left",
|
|
901
|
+
style: {
|
|
902
|
+
left: "50%",
|
|
903
|
+
top: "50%",
|
|
904
|
+
transform: `rotate(${angle}deg)`
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
`radar-axis-${angle}`
|
|
908
|
+
)),
|
|
909
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute w-full h-full animate-pulse", children: [
|
|
910
|
+
/* @__PURE__ */ jsx(
|
|
911
|
+
"div",
|
|
912
|
+
{
|
|
913
|
+
className: "w-3 h-3 absolute rounded-full bg-gray-400 dark:bg-gray-500",
|
|
914
|
+
style: {
|
|
915
|
+
left: "50%",
|
|
916
|
+
top: "10%",
|
|
917
|
+
transform: "translate(-50%, -50%)"
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
),
|
|
921
|
+
/* @__PURE__ */ jsx(
|
|
922
|
+
"div",
|
|
923
|
+
{
|
|
924
|
+
className: "w-3 h-3 absolute rounded-full bg-gray-400 dark:bg-gray-500",
|
|
925
|
+
style: {
|
|
926
|
+
left: "85%",
|
|
927
|
+
top: "35%",
|
|
928
|
+
transform: "translate(-50%, -50%)"
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
),
|
|
932
|
+
/* @__PURE__ */ jsx(
|
|
933
|
+
"div",
|
|
934
|
+
{
|
|
935
|
+
className: "w-3 h-3 absolute rounded-full bg-gray-400 dark:bg-gray-500",
|
|
936
|
+
style: {
|
|
937
|
+
left: "75%",
|
|
938
|
+
top: "75%",
|
|
939
|
+
transform: "translate(-50%, -50%)"
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
),
|
|
943
|
+
/* @__PURE__ */ jsx(
|
|
944
|
+
"div",
|
|
945
|
+
{
|
|
946
|
+
className: "w-3 h-3 absolute rounded-full bg-gray-400 dark:bg-gray-500",
|
|
947
|
+
style: {
|
|
948
|
+
left: "25%",
|
|
949
|
+
top: "75%",
|
|
950
|
+
transform: "translate(-50%, -50%)"
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
),
|
|
954
|
+
/* @__PURE__ */ jsx(
|
|
955
|
+
"div",
|
|
956
|
+
{
|
|
957
|
+
className: "w-3 h-3 absolute rounded-full bg-gray-400 dark:bg-gray-500",
|
|
958
|
+
style: {
|
|
959
|
+
left: "15%",
|
|
960
|
+
top: "35%",
|
|
961
|
+
transform: "translate(-50%, -50%)"
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
)
|
|
965
|
+
] })
|
|
966
|
+
] }) }),
|
|
967
|
+
normalizedType !== "bar" && normalizedType !== "line" && normalizedType !== "pie" && normalizedType !== "doughnut" && normalizedType !== "scatter" && normalizedType !== "radar" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-gray-400 dark:text-gray-500 text-lg", children: [
|
|
968
|
+
"Preparing ",
|
|
969
|
+
normalizedType,
|
|
970
|
+
" chart..."
|
|
971
|
+
] }) })
|
|
972
|
+
] }),
|
|
973
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-between text-xs text-gray-500 dark:text-gray-400", children: [
|
|
974
|
+
/* @__PURE__ */ jsx("div", { className: "w-2/3 flex gap-2", children: ["Dataset 1", "Dataset 2"].map((label, i) => /* @__PURE__ */ jsxs(
|
|
975
|
+
"div",
|
|
976
|
+
{
|
|
977
|
+
className: "flex items-center",
|
|
978
|
+
children: [
|
|
979
|
+
/* @__PURE__ */ jsx(
|
|
980
|
+
"div",
|
|
981
|
+
{
|
|
982
|
+
className: `w-3 h-3 rounded-full mr-1 ${i === 0 ? "bg-gray-400 dark:bg-gray-500" : "bg-gray-300 dark:bg-gray-600"}`
|
|
983
|
+
}
|
|
984
|
+
),
|
|
985
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
`legend-${i}`
|
|
989
|
+
)) }),
|
|
990
|
+
/* @__PURE__ */ jsx("div", { children: "Processing data..." })
|
|
991
|
+
] })
|
|
992
|
+
]
|
|
993
|
+
}
|
|
994
|
+
);
|
|
995
|
+
};
|
|
996
|
+
const renderAppLoading = (appName = "Unknown App") => {
|
|
997
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-6 p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 w-full block", children: [
|
|
998
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
999
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-blue-100 dark:bg-blue-900 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-5 w-5 border-2 border-blue-500 dark:border-blue-400 border-t-transparent rounded-full" }) }),
|
|
1000
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-700 dark:text-gray-300", children: [
|
|
1001
|
+
"Preparing ",
|
|
1002
|
+
appName,
|
|
1003
|
+
"..."
|
|
1004
|
+
] })
|
|
1005
|
+
] }),
|
|
1006
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1007
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
1008
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-blue-500 animate-pulse flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
1009
|
+
"svg",
|
|
1010
|
+
{
|
|
1011
|
+
className: "w-6 h-6 text-white",
|
|
1012
|
+
fill: "none",
|
|
1013
|
+
stroke: "currentColor",
|
|
1014
|
+
viewBox: "0 0 24 24",
|
|
1015
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1016
|
+
children: /* @__PURE__ */ jsx(
|
|
1017
|
+
"path",
|
|
1018
|
+
{
|
|
1019
|
+
strokeLinecap: "round",
|
|
1020
|
+
strokeLinejoin: "round",
|
|
1021
|
+
strokeWidth: 2,
|
|
1022
|
+
d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
1023
|
+
}
|
|
1024
|
+
)
|
|
1025
|
+
}
|
|
1026
|
+
) }),
|
|
1027
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1028
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-800 dark:text-gray-200", children: appName }),
|
|
1029
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Getting ready to launch..." })
|
|
1030
|
+
] })
|
|
1031
|
+
] }),
|
|
1032
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 py-2 bg-gray-300 dark:bg-gray-600 text-gray-500 dark:text-gray-400 rounded-lg", children: "Loading..." })
|
|
1033
|
+
] })
|
|
1034
|
+
] });
|
|
1035
|
+
};
|
|
1036
|
+
const renderAnalyticLoading = () => {
|
|
1037
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-6 p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-gradient-to-r from-emerald-50 to-teal-50 dark:from-emerald-900/20 dark:to-teal-900/20 w-full block", children: [
|
|
1038
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
1039
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-emerald-100 dark:bg-emerald-900 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-5 w-5 border-2 border-emerald-500 dark:border-emerald-400 border-t-transparent rounded-full" }) }),
|
|
1040
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-gray-700 dark:text-gray-300", children: "Processing analytics data..." })
|
|
1041
|
+
] }),
|
|
1042
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1043
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
1044
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-emerald-500 animate-pulse flex items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
1045
|
+
"svg",
|
|
1046
|
+
{
|
|
1047
|
+
className: "w-6 h-6 text-white",
|
|
1048
|
+
fill: "none",
|
|
1049
|
+
stroke: "currentColor",
|
|
1050
|
+
viewBox: "0 0 24 24",
|
|
1051
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1052
|
+
children: /* @__PURE__ */ jsx(
|
|
1053
|
+
"path",
|
|
1054
|
+
{
|
|
1055
|
+
strokeLinecap: "round",
|
|
1056
|
+
strokeLinejoin: "round",
|
|
1057
|
+
strokeWidth: 2,
|
|
1058
|
+
d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
|
1059
|
+
}
|
|
1060
|
+
)
|
|
1061
|
+
}
|
|
1062
|
+
) }),
|
|
1063
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1064
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-gray-800 dark:text-gray-200", children: "Analytics Dataset" }),
|
|
1065
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Preparing pivot table interface..." })
|
|
1066
|
+
] })
|
|
1067
|
+
] }),
|
|
1068
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-1 bg-emerald-100 dark:bg-emerald-800/30 text-emerald-700 dark:text-emerald-300 text-xs font-medium rounded-full animate-pulse", children: "Loading..." })
|
|
1069
|
+
] })
|
|
1070
|
+
] });
|
|
1071
|
+
};
|
|
1072
|
+
const renderWidgetLoading = (widgetType = "card") => {
|
|
1073
|
+
const isForm = widgetType === "form";
|
|
1074
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-6 p-6 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 w-full block", children: [
|
|
1075
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
1076
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-indigo-100 dark:bg-indigo-900 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "animate-spin h-5 w-5 border-2 border-indigo-500 dark:border-indigo-400 border-t-transparent rounded-full" }) }),
|
|
1077
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-gray-700 dark:text-gray-300", children: [
|
|
1078
|
+
"Preparing ",
|
|
1079
|
+
isForm ? "form" : "card",
|
|
1080
|
+
" widget..."
|
|
1081
|
+
] })
|
|
1082
|
+
] }),
|
|
1083
|
+
isForm ? (
|
|
1084
|
+
// Form loading skeleton
|
|
1085
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx("div", { className: "h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1087
|
+
/* @__PURE__ */ jsx("div", { className: "h-10 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1088
|
+
/* @__PURE__ */ jsx("div", { className: "h-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1089
|
+
/* @__PURE__ */ jsx("div", { className: "h-10 bg-gray-200 dark:bg-gray-700 rounded w-32 animate-pulse" })
|
|
1090
|
+
] })
|
|
1091
|
+
) : (
|
|
1092
|
+
// Card loading skeleton
|
|
1093
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1094
|
+
/* @__PURE__ */ jsx("div", { className: "h-6 bg-gray-200 dark:bg-gray-700 rounded w-3/4 animate-pulse" }),
|
|
1095
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
1096
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1097
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1098
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }),
|
|
1099
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" })
|
|
1100
|
+
] })
|
|
1101
|
+
] })
|
|
1102
|
+
)
|
|
1103
|
+
] });
|
|
1104
|
+
};
|
|
1105
|
+
const CustomMarkdown = ({ content: content2 }) => /* @__PURE__ */ jsx(
|
|
1106
|
+
ReactMarkdown,
|
|
1107
|
+
{
|
|
1108
|
+
remarkPlugins: [remarkGfm],
|
|
1109
|
+
rehypePlugins: [rehypeRaw],
|
|
1110
|
+
components: {
|
|
1111
|
+
blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "border-l-4 border-gray-300 dark:border-gray-700 pl-4 py-2 my-4 bg-gray-100 dark:bg-gray-800 rounded-md", children }),
|
|
1112
|
+
p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-2 last:mb-0", children }),
|
|
1113
|
+
h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold mb-2 last:mb-0", children }),
|
|
1114
|
+
h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold mb-2 last:mb-0", children }),
|
|
1115
|
+
h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-lg font-bold mb-2 last:mb-0", children }),
|
|
1116
|
+
h4: ({ children }) => /* @__PURE__ */ jsx("h4", { className: "text-base font-bold mb-2 last:mb-0", children }),
|
|
1117
|
+
h5: ({ children }) => /* @__PURE__ */ jsx("h5", { className: "text-sm font-bold mb-2 last:mb-0", children }),
|
|
1118
|
+
h6: ({ children }) => /* @__PURE__ */ jsx("h6", { className: "text-xs font-bold mb-2 last:mb-0", children }),
|
|
1119
|
+
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "list-disc list-outside ml-6 mb-2 last:mb-0 space-y-1", children }),
|
|
1120
|
+
ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "list-decimal list-outside ml-6 mb-2 last:mb-0 space-y-1", children }),
|
|
1121
|
+
li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "mb-1", children }),
|
|
1122
|
+
hr: ({ children }) => /* @__PURE__ */ jsx("hr", { className: "my-4 border-t border-gray-200 dark:border-gray-700 mb-3" }),
|
|
1123
|
+
a: ({ href, children }) => /* @__PURE__ */ jsx(
|
|
1124
|
+
"a",
|
|
1125
|
+
{
|
|
1126
|
+
href,
|
|
1127
|
+
target: "_blank",
|
|
1128
|
+
rel: "noopener noreferrer",
|
|
1129
|
+
className: "text-blue-500 hover:text-blue-600 underline",
|
|
1130
|
+
children
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
pre: (_a) => {
|
|
1134
|
+
var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
|
|
1135
|
+
const childArray = Array.isArray(children) ? children : [children];
|
|
1136
|
+
const codeElement = childArray.find(
|
|
1137
|
+
(child) => {
|
|
1138
|
+
var _a2, _b2;
|
|
1139
|
+
return (_b2 = (_a2 = child == null ? void 0 : child.props) == null ? void 0 : _a2.className) == null ? void 0 : _b2.startsWith("language-");
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
if (codeElement) {
|
|
1143
|
+
const language = codeElement.props.className.replace(
|
|
1144
|
+
"language-",
|
|
1145
|
+
""
|
|
1146
|
+
) || "text";
|
|
1147
|
+
const code = String(
|
|
1148
|
+
codeElement.props.children || ""
|
|
1149
|
+
).replace(/\n$/, "");
|
|
1150
|
+
return /* @__PURE__ */ jsx(
|
|
1151
|
+
CodeBlock,
|
|
1152
|
+
{
|
|
1153
|
+
language,
|
|
1154
|
+
code,
|
|
1155
|
+
theme
|
|
1156
|
+
}
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
return /* @__PURE__ */ jsx("pre", { className: "my-3 p-4 rounded-lg bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 overflow-x-auto", children: /* @__PURE__ */ jsx("code", { className: "text-sm font-mono text-gray-800 dark:text-gray-200", children }) });
|
|
1160
|
+
},
|
|
1161
|
+
code: (_c) => {
|
|
1162
|
+
var _d = _c, { className, children } = _d, props = __objRest(_d, ["className", "children"]);
|
|
1163
|
+
const isInlineCode = !className;
|
|
1164
|
+
return isInlineCode ? /* @__PURE__ */ jsx("code", { className: "bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 px-1.5 py-0.5 rounded text-sm font-mono", children }) : /* @__PURE__ */ jsx("code", __spreadProps(__spreadValues({ className }, props), { children }));
|
|
1165
|
+
},
|
|
1166
|
+
table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsx("table", { className: "border-collapse w-full", children }) }),
|
|
1167
|
+
th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 px-4 py-2 text-left", children }),
|
|
1168
|
+
td: (_e) => {
|
|
1169
|
+
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
1170
|
+
return /* @__PURE__ */ jsx(
|
|
1171
|
+
"td",
|
|
1172
|
+
__spreadProps(__spreadValues({
|
|
1173
|
+
className: "border border-gray-300 dark:border-gray-700 px-4 py-2"
|
|
1174
|
+
}, props), {
|
|
1175
|
+
children
|
|
1176
|
+
})
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
},
|
|
1180
|
+
children: content2
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1183
|
+
const processTextContent = useMemo(() => {
|
|
1184
|
+
return (text) => {
|
|
1185
|
+
if (!isStreaming) {
|
|
1186
|
+
const parts = text.split(
|
|
1187
|
+
/(```(?:chart:[a-z]+|image|app:[^\n]+|analytic|(?:widget:)?(?:card|form|decision)|json:[^\n]+)\n[\s\S]*?\n```)/g
|
|
1188
|
+
);
|
|
1189
|
+
if (parts.length > 1) {
|
|
1190
|
+
return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, i) => {
|
|
1191
|
+
const chartMatch = part.match(
|
|
1192
|
+
/```chart:([a-z]+)\n([\s\S]*?)\n```/
|
|
1193
|
+
);
|
|
1194
|
+
const imageMatch = part.match(
|
|
1195
|
+
/```image\n([\s\S]*?)\n```/
|
|
1196
|
+
);
|
|
1197
|
+
const appMatch = part.match(
|
|
1198
|
+
/```app:([^\n]+)\n([\s\S]*?)\n```/
|
|
1199
|
+
);
|
|
1200
|
+
const analyticMatch = part.match(
|
|
1201
|
+
/```analytic\n([\s\S]*?)\n```/
|
|
1202
|
+
);
|
|
1203
|
+
const widgetMatch = part.match(
|
|
1204
|
+
/```(?:widget:(card|form|decision)|decision)\n([\s\S]*?)\n```/
|
|
1205
|
+
);
|
|
1206
|
+
const jsonMatch = part.match(
|
|
1207
|
+
/```json:([^\n]+)\n([\s\S]*?)\n```/
|
|
1208
|
+
);
|
|
1209
|
+
if (chartMatch) {
|
|
1210
|
+
const [_, chartType, chartData] = chartMatch;
|
|
1211
|
+
const chartKey = `completed-chart-${i}-${chartData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1212
|
+
return /* @__PURE__ */ jsx(
|
|
1213
|
+
"div",
|
|
1214
|
+
{
|
|
1215
|
+
className: "my-6 block w-full",
|
|
1216
|
+
style: {
|
|
1217
|
+
display: "block",
|
|
1218
|
+
contain: "layout",
|
|
1219
|
+
marginTop: "1.5rem",
|
|
1220
|
+
marginBottom: "1.5rem",
|
|
1221
|
+
overscrollBehavior: "contain",
|
|
1222
|
+
scrollSnapStop: "always"
|
|
1223
|
+
},
|
|
1224
|
+
children: renderChart(
|
|
1225
|
+
chartType,
|
|
1226
|
+
chartData,
|
|
1227
|
+
chartKey
|
|
1228
|
+
)
|
|
1229
|
+
},
|
|
1230
|
+
chartKey
|
|
1231
|
+
);
|
|
1232
|
+
} else if (imageMatch) {
|
|
1233
|
+
const [_, imageData] = imageMatch;
|
|
1234
|
+
const imageKey = `completed-image-${i}-${imageData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1235
|
+
return /* @__PURE__ */ jsx(
|
|
1236
|
+
"div",
|
|
1237
|
+
{
|
|
1238
|
+
className: "my-6 block w-full",
|
|
1239
|
+
style: {
|
|
1240
|
+
display: "block",
|
|
1241
|
+
contain: "layout",
|
|
1242
|
+
marginTop: "1.5rem",
|
|
1243
|
+
marginBottom: "1.5rem",
|
|
1244
|
+
overscrollBehavior: "contain",
|
|
1245
|
+
scrollSnapStop: "always"
|
|
1246
|
+
},
|
|
1247
|
+
children: renderImage(imageData, imageKey)
|
|
1248
|
+
},
|
|
1249
|
+
imageKey
|
|
1250
|
+
);
|
|
1251
|
+
} else if (appMatch) {
|
|
1252
|
+
const [_, appName, appUrl] = appMatch;
|
|
1253
|
+
const appKey = `completed-app-${i}-${appName.replace(
|
|
1254
|
+
/\s/g,
|
|
1255
|
+
""
|
|
1256
|
+
)}`;
|
|
1257
|
+
return /* @__PURE__ */ jsx(
|
|
1258
|
+
"div",
|
|
1259
|
+
{
|
|
1260
|
+
className: "my-6 block w-full",
|
|
1261
|
+
style: {
|
|
1262
|
+
display: "block",
|
|
1263
|
+
contain: "layout",
|
|
1264
|
+
marginTop: "1.5rem",
|
|
1265
|
+
marginBottom: "1.5rem",
|
|
1266
|
+
overscrollBehavior: "contain",
|
|
1267
|
+
scrollSnapStop: "always"
|
|
1268
|
+
},
|
|
1269
|
+
children: renderApp(
|
|
1270
|
+
appName,
|
|
1271
|
+
appUrl.trim(),
|
|
1272
|
+
appKey
|
|
1273
|
+
)
|
|
1274
|
+
},
|
|
1275
|
+
appKey
|
|
1276
|
+
);
|
|
1277
|
+
} else if (analyticMatch) {
|
|
1278
|
+
const [_, analyticData] = analyticMatch;
|
|
1279
|
+
const analyticKey = `completed-analytic-${i}-${analyticData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1280
|
+
return /* @__PURE__ */ jsx(
|
|
1281
|
+
"div",
|
|
1282
|
+
{
|
|
1283
|
+
className: "my-6 block w-full",
|
|
1284
|
+
style: {
|
|
1285
|
+
display: "block",
|
|
1286
|
+
contain: "layout",
|
|
1287
|
+
marginTop: "1.5rem",
|
|
1288
|
+
marginBottom: "1.5rem",
|
|
1289
|
+
overscrollBehavior: "contain",
|
|
1290
|
+
scrollSnapStop: "always"
|
|
1291
|
+
},
|
|
1292
|
+
children: renderAnalytic(
|
|
1293
|
+
analyticData.trim(),
|
|
1294
|
+
analyticKey
|
|
1295
|
+
)
|
|
1296
|
+
},
|
|
1297
|
+
analyticKey
|
|
1298
|
+
);
|
|
1299
|
+
} else if (jsonMatch) {
|
|
1300
|
+
const [_, jsonTitle, jsonData] = jsonMatch;
|
|
1301
|
+
const jsonKey = `completed-json-${i}-${jsonTitle.replace(
|
|
1302
|
+
/\s/g,
|
|
1303
|
+
""
|
|
1304
|
+
)}`;
|
|
1305
|
+
return renderJson(
|
|
1306
|
+
jsonTitle,
|
|
1307
|
+
jsonData,
|
|
1308
|
+
jsonKey
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
return part ? /* @__PURE__ */ jsx(
|
|
1312
|
+
CustomMarkdown,
|
|
1313
|
+
{
|
|
1314
|
+
content: part
|
|
1315
|
+
},
|
|
1316
|
+
`text-${i}`
|
|
1317
|
+
) : null;
|
|
1318
|
+
}) });
|
|
1319
|
+
}
|
|
1320
|
+
return /* @__PURE__ */ jsx(CustomMarkdown, { content: text });
|
|
1321
|
+
}
|
|
1322
|
+
const chartTagMatches = [...text.matchAll(/```chart:([a-z]+)\n/g)];
|
|
1323
|
+
const imageTagMatches = [...text.matchAll(/```image\n/g)];
|
|
1324
|
+
const appTagMatches = [...text.matchAll(/```app:([^\n]+)\n/g)];
|
|
1325
|
+
const analyticTagMatches = [...text.matchAll(/```analytic\n/g)];
|
|
1326
|
+
const widgetTagMatches = [
|
|
1327
|
+
...text.matchAll(
|
|
1328
|
+
/```(?:widget:(?:card|form|decision)|decision)\n/g
|
|
1329
|
+
)
|
|
1330
|
+
];
|
|
1331
|
+
const jsonTagMatches = [...text.matchAll(/```json:([^\n]+)\n/g)];
|
|
1332
|
+
if (!chartTagMatches.length && !imageTagMatches.length && !appTagMatches.length && !analyticTagMatches.length && !widgetTagMatches.length && !jsonTagMatches.length) {
|
|
1333
|
+
return /* @__PURE__ */ jsx(CustomMarkdown, { content: text });
|
|
1334
|
+
}
|
|
1335
|
+
const allTags = [
|
|
1336
|
+
...chartTagMatches.map((match) => ({
|
|
1337
|
+
type: "chart",
|
|
1338
|
+
index: match.index,
|
|
1339
|
+
chartType: match[1],
|
|
1340
|
+
match: match[0]
|
|
1341
|
+
})),
|
|
1342
|
+
...imageTagMatches.map((match) => ({
|
|
1343
|
+
type: "image",
|
|
1344
|
+
index: match.index,
|
|
1345
|
+
match: match[0]
|
|
1346
|
+
})),
|
|
1347
|
+
...appTagMatches.map((match) => ({
|
|
1348
|
+
type: "app",
|
|
1349
|
+
index: match.index,
|
|
1350
|
+
appName: match[1],
|
|
1351
|
+
match: match[0]
|
|
1352
|
+
})),
|
|
1353
|
+
...analyticTagMatches.map((match) => ({
|
|
1354
|
+
type: "analytic",
|
|
1355
|
+
index: match.index,
|
|
1356
|
+
match: match[0]
|
|
1357
|
+
})),
|
|
1358
|
+
...widgetTagMatches.map((match) => {
|
|
1359
|
+
const widgetType = match[1] || "decision";
|
|
1360
|
+
return {
|
|
1361
|
+
type: "widget",
|
|
1362
|
+
index: match.index,
|
|
1363
|
+
widgetType,
|
|
1364
|
+
match: match[0]
|
|
1365
|
+
};
|
|
1366
|
+
}),
|
|
1367
|
+
...jsonTagMatches.map((match) => ({
|
|
1368
|
+
type: "json",
|
|
1369
|
+
index: match.index,
|
|
1370
|
+
jsonTitle: match[1],
|
|
1371
|
+
match: match[0]
|
|
1372
|
+
}))
|
|
1373
|
+
].sort((a, b) => a.index - b.index);
|
|
1374
|
+
if (!allTags.length) {
|
|
1375
|
+
return /* @__PURE__ */ jsx(CustomMarkdown, { content: text });
|
|
1376
|
+
}
|
|
1377
|
+
const lastTag = allTags[allTags.length - 1];
|
|
1378
|
+
const lastOpeningTagIndex = lastTag.index;
|
|
1379
|
+
const textBeforeLastBlock = text.substring(0, lastOpeningTagIndex);
|
|
1380
|
+
const lastBlockContent = text.substring(lastOpeningTagIndex);
|
|
1381
|
+
const hasClosingTag = /\n```|```\n|```$/.test(lastBlockContent);
|
|
1382
|
+
let processedBeforeBlock = null;
|
|
1383
|
+
if (textBeforeLastBlock) {
|
|
1384
|
+
const beforeParts = textBeforeLastBlock.split(
|
|
1385
|
+
/(```(?:chart:[a-z]+|image|app:[^\n]+|analytic|(?:widget:)?(?:card|form|decision)|json:[^\n]+)\n[\s\S]*?\n```)/g
|
|
1386
|
+
);
|
|
1387
|
+
if (beforeParts.length > 1) {
|
|
1388
|
+
processedBeforeBlock = /* @__PURE__ */ jsx(Fragment, { children: beforeParts.map((part, i) => {
|
|
1389
|
+
const chartMatch = part.match(
|
|
1390
|
+
/```chart:([a-z]+)\n([\s\S]*?)\n```/
|
|
1391
|
+
);
|
|
1392
|
+
const imageMatch = part.match(
|
|
1393
|
+
/```image\n([\s\S]*?)\n```/
|
|
1394
|
+
);
|
|
1395
|
+
const appMatch = part.match(
|
|
1396
|
+
/```app:([^\n]+)\n([\s\S]*?)\n```/
|
|
1397
|
+
);
|
|
1398
|
+
const analyticMatch = part.match(
|
|
1399
|
+
/```analytic\n([\s\S]*?)\n```/
|
|
1400
|
+
);
|
|
1401
|
+
const widgetMatch = part.match(
|
|
1402
|
+
/```(?:widget:(card|form|decision)|decision)\n([\s\S]*?)\n```/
|
|
1403
|
+
);
|
|
1404
|
+
const jsonMatch = part.match(
|
|
1405
|
+
/```json:([^\n]+)\n([\s\S]*?)\n```/
|
|
1406
|
+
);
|
|
1407
|
+
if (chartMatch) {
|
|
1408
|
+
const [_, chartType, chartData] = chartMatch;
|
|
1409
|
+
const chartKey = `streaming-complete-chart-${i}-${chartData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1410
|
+
return /* @__PURE__ */ jsx(
|
|
1411
|
+
"div",
|
|
1412
|
+
{
|
|
1413
|
+
className: "my-6 block w-full",
|
|
1414
|
+
style: {
|
|
1415
|
+
display: "block",
|
|
1416
|
+
contain: "layout",
|
|
1417
|
+
marginTop: "1.5rem",
|
|
1418
|
+
marginBottom: "1.5rem",
|
|
1419
|
+
overscrollBehavior: "contain",
|
|
1420
|
+
scrollSnapStop: "always"
|
|
1421
|
+
},
|
|
1422
|
+
children: renderChart(
|
|
1423
|
+
chartType,
|
|
1424
|
+
chartData,
|
|
1425
|
+
chartKey
|
|
1426
|
+
)
|
|
1427
|
+
},
|
|
1428
|
+
chartKey
|
|
1429
|
+
);
|
|
1430
|
+
} else if (imageMatch) {
|
|
1431
|
+
const [_, imageData] = imageMatch;
|
|
1432
|
+
const imageKey = `streaming-complete-image-${i}-${imageData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1433
|
+
return /* @__PURE__ */ jsx(
|
|
1434
|
+
"div",
|
|
1435
|
+
{
|
|
1436
|
+
className: "my-6 block w-full",
|
|
1437
|
+
style: {
|
|
1438
|
+
display: "block",
|
|
1439
|
+
contain: "layout",
|
|
1440
|
+
marginTop: "1.5rem",
|
|
1441
|
+
marginBottom: "1.5rem",
|
|
1442
|
+
overscrollBehavior: "contain",
|
|
1443
|
+
scrollSnapStop: "always"
|
|
1444
|
+
},
|
|
1445
|
+
children: renderImage(imageData, imageKey)
|
|
1446
|
+
},
|
|
1447
|
+
imageKey
|
|
1448
|
+
);
|
|
1449
|
+
} else if (appMatch) {
|
|
1450
|
+
const [_, appName, appUrl] = appMatch;
|
|
1451
|
+
const appKey = `streaming-complete-app-${i}-${appName.replace(
|
|
1452
|
+
/\s/g,
|
|
1453
|
+
""
|
|
1454
|
+
)}`;
|
|
1455
|
+
return /* @__PURE__ */ jsx(
|
|
1456
|
+
"div",
|
|
1457
|
+
{
|
|
1458
|
+
className: "my-6 block w-full",
|
|
1459
|
+
style: {
|
|
1460
|
+
display: "block",
|
|
1461
|
+
contain: "layout",
|
|
1462
|
+
marginTop: "1.5rem",
|
|
1463
|
+
marginBottom: "1.5rem",
|
|
1464
|
+
overscrollBehavior: "contain",
|
|
1465
|
+
scrollSnapStop: "always"
|
|
1466
|
+
},
|
|
1467
|
+
children: renderApp(
|
|
1468
|
+
appName,
|
|
1469
|
+
appUrl.trim(),
|
|
1470
|
+
appKey
|
|
1471
|
+
)
|
|
1472
|
+
},
|
|
1473
|
+
appKey
|
|
1474
|
+
);
|
|
1475
|
+
} else if (analyticMatch) {
|
|
1476
|
+
const [_, analyticData] = analyticMatch;
|
|
1477
|
+
const analyticKey = `streaming-complete-analytic-${i}-${analyticData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1478
|
+
return /* @__PURE__ */ jsx(
|
|
1479
|
+
"div",
|
|
1480
|
+
{
|
|
1481
|
+
className: "my-6 block w-full",
|
|
1482
|
+
style: {
|
|
1483
|
+
display: "block",
|
|
1484
|
+
contain: "layout",
|
|
1485
|
+
marginTop: "1.5rem",
|
|
1486
|
+
marginBottom: "1.5rem",
|
|
1487
|
+
overscrollBehavior: "contain",
|
|
1488
|
+
scrollSnapStop: "always"
|
|
1489
|
+
},
|
|
1490
|
+
children: renderAnalytic(
|
|
1491
|
+
analyticData.trim(),
|
|
1492
|
+
analyticKey
|
|
1493
|
+
)
|
|
1494
|
+
},
|
|
1495
|
+
analyticKey
|
|
1496
|
+
);
|
|
1497
|
+
} else if (jsonMatch) {
|
|
1498
|
+
const [_, jsonTitle, jsonData] = jsonMatch;
|
|
1499
|
+
const jsonKey = `streaming-complete-json-${i}-${jsonTitle.replace(
|
|
1500
|
+
/\s/g,
|
|
1501
|
+
""
|
|
1502
|
+
)}`;
|
|
1503
|
+
return renderJson(
|
|
1504
|
+
jsonTitle,
|
|
1505
|
+
jsonData,
|
|
1506
|
+
jsonKey
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
return part ? /* @__PURE__ */ jsx(
|
|
1510
|
+
CustomMarkdown,
|
|
1511
|
+
{
|
|
1512
|
+
content: part
|
|
1513
|
+
},
|
|
1514
|
+
`text-${i}`
|
|
1515
|
+
) : null;
|
|
1516
|
+
}) });
|
|
1517
|
+
} else {
|
|
1518
|
+
processedBeforeBlock = /* @__PURE__ */ jsx(CustomMarkdown, { content: textBeforeLastBlock });
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
let lastBlockElement = null;
|
|
1522
|
+
if (hasClosingTag) {
|
|
1523
|
+
if (lastTag.type === "chart") {
|
|
1524
|
+
const chartMatch = lastBlockContent.match(
|
|
1525
|
+
/```chart:([a-z]+)\n([\s\S]*?)\n```/
|
|
1526
|
+
);
|
|
1527
|
+
if (chartMatch) {
|
|
1528
|
+
const [_, chartType, chartData] = chartMatch;
|
|
1529
|
+
const chartKey = `streaming-last-complete-chart-${chartData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1530
|
+
lastBlockElement = /* @__PURE__ */ jsx(
|
|
1531
|
+
"div",
|
|
1532
|
+
{
|
|
1533
|
+
className: "my-6 block w-full",
|
|
1534
|
+
style: {
|
|
1535
|
+
display: "block",
|
|
1536
|
+
contain: "layout",
|
|
1537
|
+
marginTop: "1.5rem",
|
|
1538
|
+
marginBottom: "1.5rem",
|
|
1539
|
+
overscrollBehavior: "contain",
|
|
1540
|
+
scrollSnapStop: "always"
|
|
1541
|
+
},
|
|
1542
|
+
children: renderChart(chartType, chartData, chartKey)
|
|
1543
|
+
},
|
|
1544
|
+
chartKey
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
} else if (lastTag.type === "image") {
|
|
1548
|
+
const imageMatch = lastBlockContent.match(
|
|
1549
|
+
/```image\n([\s\S]*?)\n```/
|
|
1550
|
+
);
|
|
1551
|
+
if (imageMatch) {
|
|
1552
|
+
const [_, imageData] = imageMatch;
|
|
1553
|
+
const imageKey = `streaming-last-complete-image-${imageData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1554
|
+
lastBlockElement = /* @__PURE__ */ jsx(
|
|
1555
|
+
"div",
|
|
1556
|
+
{
|
|
1557
|
+
className: "my-6 block w-full",
|
|
1558
|
+
style: {
|
|
1559
|
+
display: "block",
|
|
1560
|
+
contain: "layout",
|
|
1561
|
+
marginTop: "1.5rem",
|
|
1562
|
+
marginBottom: "1.5rem",
|
|
1563
|
+
overscrollBehavior: "contain",
|
|
1564
|
+
scrollSnapStop: "always"
|
|
1565
|
+
},
|
|
1566
|
+
children: renderImage(imageData, imageKey)
|
|
1567
|
+
},
|
|
1568
|
+
imageKey
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
} else if (lastTag.type === "app") {
|
|
1572
|
+
const appMatch = lastBlockContent.match(
|
|
1573
|
+
/```app:([^\n]+)\n([\s\S]*?)\n```/
|
|
1574
|
+
);
|
|
1575
|
+
if (appMatch) {
|
|
1576
|
+
const [_, appName, appUrl] = appMatch;
|
|
1577
|
+
const appKey = `streaming-last-complete-app-${appName.replace(
|
|
1578
|
+
/\s/g,
|
|
1579
|
+
""
|
|
1580
|
+
)}`;
|
|
1581
|
+
lastBlockElement = /* @__PURE__ */ jsx(
|
|
1582
|
+
"div",
|
|
1583
|
+
{
|
|
1584
|
+
className: "my-6 block w-full",
|
|
1585
|
+
style: {
|
|
1586
|
+
display: "block",
|
|
1587
|
+
contain: "layout",
|
|
1588
|
+
marginTop: "1.5rem",
|
|
1589
|
+
marginBottom: "1.5rem",
|
|
1590
|
+
overscrollBehavior: "contain",
|
|
1591
|
+
scrollSnapStop: "always"
|
|
1592
|
+
},
|
|
1593
|
+
children: renderApp(appName, appUrl.trim(), appKey)
|
|
1594
|
+
},
|
|
1595
|
+
appKey
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
} else if (lastTag.type === "analytic") {
|
|
1599
|
+
const analyticMatch = lastBlockContent.match(
|
|
1600
|
+
/```analytic\n([\s\S]*?)\n```/
|
|
1601
|
+
);
|
|
1602
|
+
if (analyticMatch) {
|
|
1603
|
+
const [_, analyticData] = analyticMatch;
|
|
1604
|
+
const analyticKey = `streaming-last-complete-analytic-${analyticData.substring(0, 50).replace(/\s/g, "")}`;
|
|
1605
|
+
lastBlockElement = /* @__PURE__ */ jsx(
|
|
1606
|
+
"div",
|
|
1607
|
+
{
|
|
1608
|
+
className: "my-6 block w-full",
|
|
1609
|
+
style: {
|
|
1610
|
+
display: "block",
|
|
1611
|
+
contain: "layout",
|
|
1612
|
+
marginTop: "1.5rem",
|
|
1613
|
+
marginBottom: "1.5rem",
|
|
1614
|
+
overscrollBehavior: "contain",
|
|
1615
|
+
scrollSnapStop: "always"
|
|
1616
|
+
},
|
|
1617
|
+
children: renderAnalytic(
|
|
1618
|
+
analyticData.trim(),
|
|
1619
|
+
analyticKey
|
|
1620
|
+
)
|
|
1621
|
+
},
|
|
1622
|
+
analyticKey
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
} else if (lastTag.type === "json") {
|
|
1626
|
+
const jsonMatch = lastBlockContent.match(
|
|
1627
|
+
/```json:([^\n]+)\n([\s\S]*?)\n```/
|
|
1628
|
+
);
|
|
1629
|
+
if (jsonMatch) {
|
|
1630
|
+
const [_, jsonTitle, jsonData] = jsonMatch;
|
|
1631
|
+
const jsonKey = `streaming-last-complete-json-${jsonTitle.replace(
|
|
1632
|
+
/\s/g,
|
|
1633
|
+
""
|
|
1634
|
+
)}`;
|
|
1635
|
+
lastBlockElement = renderJson(
|
|
1636
|
+
jsonTitle,
|
|
1637
|
+
jsonData,
|
|
1638
|
+
jsonKey
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
} else {
|
|
1643
|
+
if (lastTag.type === "chart") {
|
|
1644
|
+
const chartType = lastTag.chartType;
|
|
1645
|
+
lastBlockElement = renderChartLoading(chartType);
|
|
1646
|
+
} else if (lastTag.type === "image") {
|
|
1647
|
+
lastBlockElement = renderImageLoading();
|
|
1648
|
+
} else if (lastTag.type === "app") {
|
|
1649
|
+
const appName = lastTag.appName;
|
|
1650
|
+
lastBlockElement = renderAppLoading(appName);
|
|
1651
|
+
} else if (lastTag.type === "analytic") {
|
|
1652
|
+
lastBlockElement = renderAnalyticLoading();
|
|
1653
|
+
} else if (lastTag.type === "widget") {
|
|
1654
|
+
const widgetType = lastTag.widgetType;
|
|
1655
|
+
lastBlockElement = renderWidgetLoading(widgetType);
|
|
1656
|
+
} else if (lastTag.type === "json") {
|
|
1657
|
+
const jsonTitle = lastTag.jsonTitle;
|
|
1658
|
+
lastBlockElement = /* @__PURE__ */ jsx("div", { className: "my-4 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-gray-50 dark:bg-gray-800", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1659
|
+
/* @__PURE__ */ jsx("div", { className: "animate-spin h-4 w-4 border-2 border-blue-500 dark:border-blue-400 border-t-transparent rounded-full" }),
|
|
1660
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-gray-800 dark:text-gray-200", children: jsonTitle }),
|
|
1661
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs px-2 py-0.5 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full", children: "JSON" })
|
|
1662
|
+
] }) }) });
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1666
|
+
processedBeforeBlock,
|
|
1667
|
+
lastBlockElement
|
|
1668
|
+
] });
|
|
1669
|
+
};
|
|
1670
|
+
}, [isStreaming, theme]);
|
|
1671
|
+
const renderContent = () => {
|
|
1672
|
+
var _a, _b;
|
|
1673
|
+
const contentToRender = content;
|
|
1674
|
+
if (typeof contentToRender === "string") {
|
|
1675
|
+
if (isStreaming && role === "assistant" && displayedLength < contentToRender.length) {
|
|
1676
|
+
const staticContent = contentToRender.slice(0, displayedLength);
|
|
1677
|
+
const newContent = contentToRender.slice(displayedLength);
|
|
1678
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1679
|
+
message.isToolExecuting && message.executingToolName && /* @__PURE__ */ jsx(
|
|
1680
|
+
ToolExecutionIndicator,
|
|
1681
|
+
{
|
|
1682
|
+
toolName: message.executingToolName
|
|
1683
|
+
}
|
|
1684
|
+
),
|
|
1685
|
+
staticContent && processTextContent(staticContent),
|
|
1686
|
+
newContent && /* @__PURE__ */ jsx("span", { className: "streaming-content", children: processTextContent(newContent) }),
|
|
1687
|
+
/* @__PURE__ */ jsx(StreamingIndicator, {})
|
|
1688
|
+
] });
|
|
1689
|
+
}
|
|
1690
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1691
|
+
message.isToolExecuting && message.executingToolName && /* @__PURE__ */ jsx(
|
|
1692
|
+
ToolExecutionIndicator,
|
|
1693
|
+
{
|
|
1694
|
+
toolName: message.executingToolName
|
|
1695
|
+
}
|
|
1696
|
+
),
|
|
1697
|
+
((_a = message.metadata) == null ? void 0 : _a.steps) && /* @__PURE__ */ jsx(
|
|
1698
|
+
ToolExecutionWidget,
|
|
1699
|
+
{
|
|
1700
|
+
steps: message.metadata.steps,
|
|
1701
|
+
theme
|
|
1702
|
+
}
|
|
1703
|
+
),
|
|
1704
|
+
processTextContent(contentToRender),
|
|
1705
|
+
/* @__PURE__ */ jsx(StreamingIndicator, {})
|
|
1706
|
+
] });
|
|
1707
|
+
} else if (Array.isArray(contentToRender)) {
|
|
1708
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1709
|
+
message.isToolExecuting && message.executingToolName && /* @__PURE__ */ jsx(
|
|
1710
|
+
ToolExecutionIndicator,
|
|
1711
|
+
{
|
|
1712
|
+
toolName: message.executingToolName
|
|
1713
|
+
}
|
|
1714
|
+
),
|
|
1715
|
+
((_b = message.metadata) == null ? void 0 : _b.steps) && /* @__PURE__ */ jsx(
|
|
1716
|
+
ToolExecutionWidget,
|
|
1717
|
+
{
|
|
1718
|
+
steps: message.metadata.steps,
|
|
1719
|
+
theme
|
|
1720
|
+
}
|
|
1721
|
+
),
|
|
1722
|
+
contentToRender.map((part, i) => {
|
|
1723
|
+
if (part.type === "text") {
|
|
1724
|
+
const textContent = part.text;
|
|
1725
|
+
return /* @__PURE__ */ jsx("div", { children: processTextContent(textContent) }, `text-${i}`);
|
|
1726
|
+
} else if (part.type === "file") {
|
|
1727
|
+
const filePart = part;
|
|
1728
|
+
return /* @__PURE__ */ jsxs(
|
|
1729
|
+
"div",
|
|
1730
|
+
{
|
|
1731
|
+
className: "border border-gray-200 dark:border-gray-700 rounded-md p-4",
|
|
1732
|
+
children: [
|
|
1733
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-500 mb-2 flex items-center", children: [
|
|
1734
|
+
/* @__PURE__ */ jsx(FileText, { size: 16, className: "mr-1" }),
|
|
1735
|
+
"PDF Document:"
|
|
1736
|
+
] }),
|
|
1737
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1738
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium mb-2", children: filePart.filename || "Document" }),
|
|
1739
|
+
/* @__PURE__ */ jsx(
|
|
1740
|
+
"a",
|
|
1741
|
+
{
|
|
1742
|
+
href: filePart.data,
|
|
1743
|
+
download: filePart.filename,
|
|
1744
|
+
className: "mb-2 inline-flex items-center text-blue-500 hover:text-blue-600",
|
|
1745
|
+
children: "Download"
|
|
1746
|
+
}
|
|
1747
|
+
)
|
|
1748
|
+
] })
|
|
1749
|
+
]
|
|
1750
|
+
},
|
|
1751
|
+
`file-${i}-${filePart.filename || i}`
|
|
1752
|
+
);
|
|
1753
|
+
} else if (part.type === "image") {
|
|
1754
|
+
const imagePart = part;
|
|
1755
|
+
return /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "max-w-full", children: [
|
|
1756
|
+
/* @__PURE__ */ jsx(
|
|
1757
|
+
"img",
|
|
1758
|
+
{
|
|
1759
|
+
src: imagePart.image,
|
|
1760
|
+
alt: "Attached image",
|
|
1761
|
+
className: "max-w-full max-h-96 rounded-md object-contain mb-2 cursor-pointer hover:opacity-90 transition-opacity",
|
|
1762
|
+
onClick: () => handleImageClick(
|
|
1763
|
+
imagePart.image,
|
|
1764
|
+
"Attached image"
|
|
1765
|
+
)
|
|
1766
|
+
}
|
|
1767
|
+
),
|
|
1768
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-end text-sm mr-2", children: /* @__PURE__ */ jsx(
|
|
1769
|
+
"a",
|
|
1770
|
+
{
|
|
1771
|
+
href: imagePart.image,
|
|
1772
|
+
download: "image.png",
|
|
1773
|
+
className: "text-blue-500 hover:text-blue-600",
|
|
1774
|
+
children: "Download"
|
|
1775
|
+
}
|
|
1776
|
+
) })
|
|
1777
|
+
] }) }, `image-${i}-${i}`);
|
|
1778
|
+
}
|
|
1779
|
+
return null;
|
|
1780
|
+
}),
|
|
1781
|
+
/* @__PURE__ */ jsx(StreamingIndicator, {})
|
|
1782
|
+
] });
|
|
1783
|
+
}
|
|
1784
|
+
return /* @__PURE__ */ jsx("div", { children: "..." });
|
|
1785
|
+
};
|
|
1786
|
+
const formatTime = (date) => {
|
|
1787
|
+
try {
|
|
1788
|
+
if (!date) {
|
|
1789
|
+
return "";
|
|
1790
|
+
}
|
|
1791
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
1792
|
+
day: "numeric",
|
|
1793
|
+
month: "short",
|
|
1794
|
+
year: "numeric",
|
|
1795
|
+
hour: "numeric",
|
|
1796
|
+
minute: "numeric",
|
|
1797
|
+
hour12: false
|
|
1798
|
+
}).format(new Date(date));
|
|
1799
|
+
} catch (error) {
|
|
1800
|
+
console.error("Error formatting date:", date, error);
|
|
1801
|
+
return "--:--";
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1805
|
+
/* @__PURE__ */ jsx("div", { ref: messageContainerRef, className: "mb-3", children: /* @__PURE__ */ jsx(
|
|
1806
|
+
"div",
|
|
1807
|
+
{
|
|
1808
|
+
className: `flex ${role === "user" ? "justify-end" : "justify-start"}`,
|
|
1809
|
+
children: /* @__PURE__ */ jsxs(
|
|
1810
|
+
"div",
|
|
1811
|
+
{
|
|
1812
|
+
className: `max-w-[100%] sm:max-w-[90%] ${role === "user" ? "" : ""}`,
|
|
1813
|
+
children: [
|
|
1814
|
+
/* @__PURE__ */ jsx(
|
|
1815
|
+
"div",
|
|
1816
|
+
{
|
|
1817
|
+
className: `rounded-2xl ${role === "assistant" ? "bg-transparent pl-0" : ""} p-3 transition-all duration-200`,
|
|
1818
|
+
style: role === "user" ? { backgroundColor: messageBubbleColor } : void 0,
|
|
1819
|
+
children: /* @__PURE__ */ jsx(
|
|
1820
|
+
"div",
|
|
1821
|
+
{
|
|
1822
|
+
className: `prose dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 max-w-none`,
|
|
1823
|
+
children: renderContent()
|
|
1824
|
+
}
|
|
1825
|
+
)
|
|
1826
|
+
}
|
|
1827
|
+
),
|
|
1828
|
+
/* @__PURE__ */ jsxs(
|
|
1829
|
+
"div",
|
|
1830
|
+
{
|
|
1831
|
+
className: `mt-1 text-xs text-gray-500 dark:text-gray-400 ${role === "user" ? "text-right pr-1" : "text-left"}`,
|
|
1832
|
+
children: [
|
|
1833
|
+
formatTime(message.createdAt),
|
|
1834
|
+
role === "assistant" && /* @__PURE__ */ jsx(
|
|
1835
|
+
"button",
|
|
1836
|
+
{
|
|
1837
|
+
onClick: copyToClipboard,
|
|
1838
|
+
className: "ml-2 inline-flex items-center text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition-colors",
|
|
1839
|
+
"aria-label": "Copy message",
|
|
1840
|
+
children: copied ? /* @__PURE__ */ jsx(
|
|
1841
|
+
Check,
|
|
1842
|
+
{
|
|
1843
|
+
size: 14,
|
|
1844
|
+
className: "text-green-500"
|
|
1845
|
+
}
|
|
1846
|
+
) : /* @__PURE__ */ jsx(Copy, { size: 14 })
|
|
1847
|
+
}
|
|
1848
|
+
)
|
|
1849
|
+
]
|
|
1850
|
+
}
|
|
1851
|
+
)
|
|
1852
|
+
]
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
}
|
|
1856
|
+
) }),
|
|
1857
|
+
imageDialogOpen && selectedImage && /* @__PURE__ */ jsx(
|
|
1858
|
+
"div",
|
|
1859
|
+
{
|
|
1860
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",
|
|
1861
|
+
onClick: closeImageDialog,
|
|
1862
|
+
children: /* @__PURE__ */ jsxs(
|
|
1863
|
+
"div",
|
|
1864
|
+
{
|
|
1865
|
+
className: "relative max-w-[95vw] max-h-[95vh] bg-white dark:bg-gray-900 rounded-lg overflow-hidden shadow-2xl",
|
|
1866
|
+
onClick: (e) => e.stopPropagation(),
|
|
1867
|
+
children: [
|
|
1868
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-0 right-0 z-10 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1869
|
+
/* @__PURE__ */ jsx(
|
|
1870
|
+
"a",
|
|
1871
|
+
{
|
|
1872
|
+
href: selectedImage.src,
|
|
1873
|
+
download: "image.png",
|
|
1874
|
+
className: "p-2 bg-black bg-opacity-50 hover:bg-opacity-70 text-white rounded-full transition-all cursor-pointer",
|
|
1875
|
+
title: "Download image",
|
|
1876
|
+
children: /* @__PURE__ */ jsx(Download, { size: 20 })
|
|
1877
|
+
}
|
|
1878
|
+
),
|
|
1879
|
+
/* @__PURE__ */ jsx(
|
|
1880
|
+
"button",
|
|
1881
|
+
{
|
|
1882
|
+
onClick: closeImageDialog,
|
|
1883
|
+
className: "p-2 bg-black bg-opacity-50 hover:bg-opacity-70 text-white rounded-full transition-all cursor-pointer",
|
|
1884
|
+
title: "Close",
|
|
1885
|
+
children: /* @__PURE__ */ jsx(X, { size: 20 })
|
|
1886
|
+
}
|
|
1887
|
+
)
|
|
1888
|
+
] }) }),
|
|
1889
|
+
/* @__PURE__ */ jsx(
|
|
1890
|
+
"img",
|
|
1891
|
+
{
|
|
1892
|
+
src: selectedImage.src,
|
|
1893
|
+
alt: selectedImage.alt,
|
|
1894
|
+
className: "max-w-full max-h-[95vh] object-contain"
|
|
1895
|
+
}
|
|
1896
|
+
)
|
|
1897
|
+
]
|
|
1898
|
+
}
|
|
1899
|
+
)
|
|
1900
|
+
}
|
|
1901
|
+
)
|
|
1902
|
+
] });
|
|
1903
|
+
}
|
|
1904
|
+
export {
|
|
1905
|
+
ChatMessage as default
|
|
1906
|
+
};
|