@orca-pt/orca-components 1.0.1

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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +473 -0
  3. package/dist/components/ContentElement.vue.d.ts +21 -0
  4. package/dist/components/OrcaMarkdown.vue.d.ts +15 -0
  5. package/dist/components/loading/CardLoading.vue.d.ts +9 -0
  6. package/dist/components/loading/GeneralLoading.vue.d.ts +11 -0
  7. package/dist/components/loading/ImageLoading.vue.d.ts +9 -0
  8. package/dist/components/loading/MapLoading.vue.d.ts +9 -0
  9. package/dist/components/loading/VideoLoading.vue.d.ts +9 -0
  10. package/dist/components/renderers/OrcaAudio.vue.d.ts +11 -0
  11. package/dist/components/renderers/OrcaButtons.vue.d.ts +16 -0
  12. package/dist/components/renderers/OrcaCardList.vue.d.ts +11 -0
  13. package/dist/components/renderers/OrcaImage.vue.d.ts +14 -0
  14. package/dist/components/renderers/OrcaLocation.vue.d.ts +13 -0
  15. package/dist/components/renderers/OrcaTracing.vue.d.ts +13 -0
  16. package/dist/components/renderers/OrcaVideo.vue.d.ts +11 -0
  17. package/dist/components/renderers/OrcaYouTube.vue.d.ts +10 -0
  18. package/dist/composables/__tests__/useContentParser.test.d.ts +1 -0
  19. package/dist/composables/core/index.d.ts +3 -0
  20. package/dist/composables/core/matchFinder.d.ts +13 -0
  21. package/dist/composables/core/matchProcessor.d.ts +9 -0
  22. package/dist/composables/core/recursiveParser.d.ts +6 -0
  23. package/dist/composables/parsers/__tests__/parsers.test.d.ts +1 -0
  24. package/dist/composables/parsers/baseParser.d.ts +34 -0
  25. package/dist/composables/parsers/index.d.ts +5 -0
  26. package/dist/composables/parsers/parseAudio.d.ts +2 -0
  27. package/dist/composables/parsers/parseButton.d.ts +2 -0
  28. package/dist/composables/parsers/parseCard.d.ts +2 -0
  29. package/dist/composables/parsers/parseLocation.d.ts +11 -0
  30. package/dist/composables/parsers/parseTracing.d.ts +9 -0
  31. package/dist/composables/parsing/index.d.ts +8 -0
  32. package/dist/composables/parsing/markerCleaner.d.ts +15 -0
  33. package/dist/composables/parsing/markerDefinitions.d.ts +20 -0
  34. package/dist/composables/parsing/markerOperations.d.ts +27 -0
  35. package/dist/composables/parsing/markerUtils.d.ts +58 -0
  36. package/dist/composables/useCodeButtons.d.ts +8 -0
  37. package/dist/composables/useContentParser.d.ts +12 -0
  38. package/dist/composables/useImageModal.d.ts +10 -0
  39. package/dist/composables/useLoadingStates.d.ts +13 -0
  40. package/dist/composables/useMarkdown.d.ts +8 -0
  41. package/dist/constants/loadingTypes.d.ts +9 -0
  42. package/dist/index.d.ts +16 -0
  43. package/dist/orca-components.css +13 -0
  44. package/dist/orca-components.es.js +1851 -0
  45. package/dist/orca-components.es.js.map +1 -0
  46. package/dist/orca-components.umd.js +2 -0
  47. package/dist/orca-components.umd.js.map +1 -0
  48. package/dist/types/index.d.ts +128 -0
  49. package/dist/utils/helpers.d.ts +48 -0
  50. package/package.json +83 -0
@@ -0,0 +1,1851 @@
1
+ import { computed, unref, ref, watch, onMounted, nextTick, defineComponent, createElementBlock, openBlock, createElementVNode, createStaticVNode, createVNode, Fragment, renderList, toDisplayString, createTextVNode, onUnmounted, createBlock, withCtx, createCommentVNode, normalizeStyle, normalizeClass, createSlots, Transition, isRef, withModifiers } from "vue";
2
+ import { VCard, VImg, VCardItem, VCardTitle, VBtn, VIcon, VExpandTransition, VProgressCircular, VDialog } from "vuetify/components";
3
+ import MarkdownIt from "markdown-it";
4
+ import hljs from "highlight.js";
5
+ import markdownItLinkAttributes from "markdown-it-link-attributes";
6
+ import markdownItKatex from "markdown-it-katex";
7
+ import { VideoPlayer } from "@videojs-player/vue";
8
+ import mapboxgl from "mapbox-gl";
9
+ import { components } from "vuetify/dist/vuetify-labs.esm.js";
10
+ function isImageFile(url) {
11
+ const imageExtensions = [
12
+ ".jpg",
13
+ ".jpeg",
14
+ ".png",
15
+ ".gif",
16
+ ".webp",
17
+ ".bmp",
18
+ ".svg"
19
+ ];
20
+ try {
21
+ const urlObj = new URL(url);
22
+ const pathname = urlObj.pathname.toLowerCase();
23
+ return imageExtensions.some((ext) => pathname.endsWith(ext));
24
+ } catch (e) {
25
+ return false;
26
+ }
27
+ }
28
+ function getFileNameFromUrl(url) {
29
+ try {
30
+ const urlObj = new URL(url);
31
+ const pathname = urlObj.pathname;
32
+ const segments = pathname.split("/");
33
+ const encodedFileName = segments.pop() || "";
34
+ return decodeURIComponent(encodedFileName);
35
+ } catch (e) {
36
+ return null;
37
+ }
38
+ }
39
+ function getYouTubeId(url) {
40
+ const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
41
+ const match = url.match(regExp);
42
+ return match && match[7].length === 11 ? match[7] : "";
43
+ }
44
+ function getVuetifyColor(colorName) {
45
+ if (!colorName) return "#1976D2";
46
+ const colorMap = {
47
+ primary: "#1976D2",
48
+ secondary: "#424242",
49
+ success: "#4CAF50",
50
+ info: "#2196F3",
51
+ warning: "#FB8C00",
52
+ error: "#FF5252",
53
+ accent: "#82B1FF"
54
+ };
55
+ if (colorMap[colorName.toLowerCase()]) {
56
+ return colorMap[colorName.toLowerCase()];
57
+ }
58
+ return colorName;
59
+ }
60
+ function getGroupedButtons(buttons) {
61
+ const rows = {};
62
+ buttons.forEach((button) => {
63
+ const row = button.row || 1;
64
+ if (!rows[row]) {
65
+ rows[row] = [];
66
+ }
67
+ rows[row].push(button);
68
+ });
69
+ return Object.keys(rows).sort((a, b) => parseInt(a) - parseInt(b)).map((row) => rows[parseInt(row)]);
70
+ }
71
+ function generateMapId(index) {
72
+ return `map-container-${index}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
73
+ }
74
+ function cleanOrcaMarkers(text) {
75
+ return text.replace(/\[orca\..*?\]/g, "").trim();
76
+ }
77
+ function hasLoadingMarkers(content) {
78
+ return /\[orca\.(?:loading|image\.loading|loading\.image)\.start\]/.test(
79
+ content
80
+ );
81
+ }
82
+ function getOutlinedButtonStyle(color) {
83
+ if (!color) return {};
84
+ const hexColor = getVuetifyColor(color);
85
+ return {
86
+ border: `1px solid ${hexColor}`,
87
+ color: hexColor,
88
+ "background-color": "transparent"
89
+ };
90
+ }
91
+ function getOutlinedButtonTextStyle(color) {
92
+ if (!color) return {};
93
+ const hexColor = getVuetifyColor(color);
94
+ return {
95
+ color: hexColor,
96
+ "background-color": "transparent"
97
+ };
98
+ }
99
+ function getAppendIconStyle(color) {
100
+ if (!color) return {};
101
+ const hexColor = getVuetifyColor(color);
102
+ return {
103
+ color: hexColor,
104
+ fill: hexColor
105
+ };
106
+ }
107
+ const MARKERS = [
108
+ // Loading markers (general)
109
+ {
110
+ type: "general-loading",
111
+ start: "[orca.loading.start]",
112
+ end: "[orca.loading.end]"
113
+ },
114
+ {
115
+ type: "thinking-loading",
116
+ start: "[orca.loading.thinking.start]",
117
+ end: "[orca.loading.thinking.end]"
118
+ },
119
+ {
120
+ type: "searching-loading",
121
+ start: "[orca.loading.searching.start]",
122
+ end: "[orca.loading.searching.end]"
123
+ },
124
+ {
125
+ type: "coding-loading",
126
+ start: "[orca.loading.coding.start]",
127
+ end: "[orca.loading.coding.end]"
128
+ },
129
+ {
130
+ type: "analyzing-loading",
131
+ start: "[orca.loading.analyzing.start]",
132
+ end: "[orca.loading.analyzing.end]"
133
+ },
134
+ {
135
+ type: "generating-loading",
136
+ start: "[orca.loading.generating.start]",
137
+ end: "[orca.loading.generating.end]"
138
+ },
139
+ {
140
+ type: "custom-loading",
141
+ start: "[orca.loading.custom.start]",
142
+ end: "[orca.loading.custom.end]"
143
+ },
144
+ // Loading markers (content-specific)
145
+ {
146
+ type: "image-loading",
147
+ start: "[orca.loading.image.start]",
148
+ end: "[orca.loading.image.end]"
149
+ },
150
+ {
151
+ type: "video-loading",
152
+ start: "[orca.loading.video.start]",
153
+ end: "[orca.loading.video.end]"
154
+ },
155
+ {
156
+ type: "youtube-loading",
157
+ start: "[orca.loading.youtube.start]",
158
+ end: "[orca.loading.youtube.end]"
159
+ },
160
+ {
161
+ type: "card-loading",
162
+ start: "[orca.loading.card.list.start]",
163
+ end: "[orca.loading.card.list.end]"
164
+ },
165
+ {
166
+ type: "map-loading",
167
+ start: "[orca.loading.map.start]",
168
+ end: "[orca.loading.map.end]"
169
+ },
170
+ // Content markers
171
+ { type: "image", start: "[orca.image.start]", end: "[orca.image.end]" },
172
+ { type: "video", start: "[orca.video.start]", end: "[orca.video.end]" },
173
+ {
174
+ type: "youtube",
175
+ start: "[orca.youtube.start]",
176
+ end: "[orca.youtube.end]"
177
+ },
178
+ {
179
+ type: "card",
180
+ start: "[orca.list.card.start]",
181
+ end: "[orca.list.card.end]"
182
+ },
183
+ {
184
+ type: "location",
185
+ start: "[orca.location.start]",
186
+ end: "[orca.location.end]"
187
+ },
188
+ {
189
+ type: "buttons",
190
+ start: "[orca.buttons.start]",
191
+ end: "[orca.buttons.end]"
192
+ },
193
+ {
194
+ type: "tracing",
195
+ start: "[orca.tracing.start]",
196
+ end: "[orca.tracing.end]"
197
+ },
198
+ { type: "audio", start: "[orca.audio.start]", end: "[orca.audio.end]" }
199
+ ];
200
+ const GENERAL_LOADING_TYPES = [
201
+ "general-loading",
202
+ "thinking-loading",
203
+ "searching-loading",
204
+ "coding-loading",
205
+ "analyzing-loading",
206
+ "generating-loading",
207
+ "custom-loading"
208
+ ];
209
+ function escapeRegex(str) {
210
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
211
+ }
212
+ function createMarkerPattern(config) {
213
+ const start = escapeRegex(config.start);
214
+ const end = escapeRegex(config.end);
215
+ return new RegExp(`${start}(.*?)${end}`, "s");
216
+ }
217
+ function generatePatterns(markers) {
218
+ return markers.map((marker) => ({
219
+ type: marker.type,
220
+ regex: createMarkerPattern(marker)
221
+ }));
222
+ }
223
+ const CONTENT_PATTERNS = generatePatterns(MARKERS);
224
+ function filterMarkers(markers, predicate) {
225
+ return markers.filter(predicate);
226
+ }
227
+ function isLoadingType$2(type) {
228
+ return type.includes("-loading");
229
+ }
230
+ function isGeneralLoadingType$1(type) {
231
+ return GENERAL_LOADING_TYPES.includes(type);
232
+ }
233
+ function getGeneralLoadingMarkers(markers) {
234
+ return filterMarkers(markers, (m) => isGeneralLoadingType$1(m.type));
235
+ }
236
+ function getContentMarkers(markers) {
237
+ return filterMarkers(markers, (m) => !isLoadingType$2(m.type));
238
+ }
239
+ function removeByPattern(content, pattern, preserveContent) {
240
+ return content.replace(pattern, preserveContent ? "$1" : "");
241
+ }
242
+ function removeMarkers(content, markers, preserveContent = false) {
243
+ let cleaned = content;
244
+ for (const marker of markers) {
245
+ const pattern = createMarkerPattern(marker);
246
+ cleaned = removeByPattern(cleaned, pattern, preserveContent);
247
+ }
248
+ return cleaned;
249
+ }
250
+ function removeLoadingMarkers(content, loadingMarkers) {
251
+ return removeMarkers(content, loadingMarkers, true);
252
+ }
253
+ function removeContentMarkers(content, contentMarkers) {
254
+ return removeMarkers(content, contentMarkers, false);
255
+ }
256
+ function removeAllMarkers(content, loadingMarkers, contentMarkers) {
257
+ let cleaned = removeLoadingMarkers(content, loadingMarkers);
258
+ cleaned = removeContentMarkers(cleaned, contentMarkers);
259
+ return cleaned;
260
+ }
261
+ const GENERAL_LOADING_MARKERS = getGeneralLoadingMarkers(MARKERS);
262
+ const CONTENT_MARKERS = getContentMarkers(MARKERS);
263
+ function removeOnlyLoadingMarkers(content) {
264
+ return removeLoadingMarkers(content, GENERAL_LOADING_MARKERS);
265
+ }
266
+ function removeCompleteMarkers(content) {
267
+ return removeAllMarkers(content, GENERAL_LOADING_MARKERS, CONTENT_MARKERS);
268
+ }
269
+ function findMatches(content) {
270
+ const matches = CONTENT_PATTERNS.map(({ type, regex }) => {
271
+ const match = content.match(regex);
272
+ return {
273
+ type,
274
+ match,
275
+ index: match ? content.indexOf(match[0]) : Infinity
276
+ };
277
+ });
278
+ return matches.filter(
279
+ (m) => m.match !== null && m.index !== Infinity
280
+ );
281
+ }
282
+ function createFieldPattern(fieldName, allFieldNames) {
283
+ const otherFields = allFieldNames.filter((f) => f !== fieldName).map((f) => `${f}:`).join("|");
284
+ const pattern = `${fieldName}:\\s*([\\s\\S]*?)(?=\\s*(?:${otherFields})|$)`;
285
+ return new RegExp(pattern, "m");
286
+ }
287
+ function extractField(block, fieldName, allFieldNames) {
288
+ const pattern = createFieldPattern(fieldName, allFieldNames);
289
+ const match = block.match(pattern);
290
+ if (!match || !match[1]) {
291
+ return "";
292
+ }
293
+ let value = match[1];
294
+ value = value.replace(/\u200b/g, "");
295
+ const firstLine = value.split("\n")[0];
296
+ return firstLine.trim();
297
+ }
298
+ function parseYamlList(payload, fields, mapper) {
299
+ const fieldNames = fields.map((f) => f.name);
300
+ const blocks = payload.split("- ").map((block) => block.trim()).filter((block) => block);
301
+ const results = blocks.map((block) => {
302
+ const extracted = {};
303
+ for (const field of fields) {
304
+ const value = extractField(block, field.name, fieldNames);
305
+ if (field.type === "number") {
306
+ const num = parseInt(value, 10);
307
+ extracted[field.name] = Number.isFinite(num) ? num : field.defaultValue !== void 0 ? field.defaultValue : void 0;
308
+ } else {
309
+ extracted[field.name] = value || (field.defaultValue !== void 0 ? field.defaultValue : field.required ? "" : void 0);
310
+ }
311
+ }
312
+ return mapper(extracted);
313
+ });
314
+ return results;
315
+ }
316
+ const CARD_FIELDS = [
317
+ {
318
+ name: "photo",
319
+ required: true,
320
+ defaultValue: "https://via.placeholder.com/300x200"
321
+ },
322
+ { name: "header", required: true, defaultValue: "Card Title" },
323
+ { name: "subheader", defaultValue: "" }
324
+ ];
325
+ function parseCard(payload) {
326
+ return parseYamlList(payload, CARD_FIELDS, (data) => ({
327
+ photo: data.photo || "",
328
+ header: data.header || "",
329
+ subheader: data.subheader || ""
330
+ }));
331
+ }
332
+ const BUTTON_FIELDS = [
333
+ { name: "type", required: true, defaultValue: "action" },
334
+ { name: "label", required: true, defaultValue: "Button" },
335
+ { name: "url", defaultValue: void 0 },
336
+ { name: "id", type: "number", defaultValue: void 0 },
337
+ { name: "color", defaultValue: "primary" },
338
+ { name: "row", type: "number", defaultValue: 1 }
339
+ ];
340
+ function parseButton(payload) {
341
+ const result = parseYamlList(payload, BUTTON_FIELDS, (data) => {
342
+ const type = data.type === "link" ? "link" : "action";
343
+ return {
344
+ type,
345
+ label: data.label || "",
346
+ url: data.url,
347
+ id: data.id,
348
+ color: data.color,
349
+ row: data.row
350
+ };
351
+ });
352
+ return result;
353
+ }
354
+ const AUDIO_FIELDS = [
355
+ { name: "label", required: true, defaultValue: "Audio Track" },
356
+ { name: "url", required: true, defaultValue: "" },
357
+ { name: "type", required: true, defaultValue: "audio/mpeg" }
358
+ ];
359
+ function parseAudio(payload) {
360
+ return parseYamlList(payload, AUDIO_FIELDS, (data) => ({
361
+ label: data.label || "",
362
+ url: data.url || "",
363
+ type: data.type || ""
364
+ }));
365
+ }
366
+ function parseLocation(payload) {
367
+ const [latitude, longitude] = payload.split(",").map((coord) => coord.trim());
368
+ const parsedLatitude = parseFloat(latitude);
369
+ const parsedLongitude = parseFloat(longitude);
370
+ return {
371
+ latitude: Number.isFinite(parsedLatitude) ? parsedLatitude : 0,
372
+ longitude: Number.isFinite(parsedLongitude) ? parsedLongitude : 0
373
+ };
374
+ }
375
+ function parseTracing(payload) {
376
+ var _a;
377
+ const visibilityMatch = payload.match(/visibility:\s*(\w+)/);
378
+ const visibility = (visibilityMatch == null ? void 0 : visibilityMatch[1]) || "all";
379
+ const contentMatch = payload.match(/content:\s*([\s\S]*)/);
380
+ const content = ((_a = contentMatch == null ? void 0 : contentMatch[1]) == null ? void 0 : _a.trim()) || payload;
381
+ return {
382
+ visibility,
383
+ content,
384
+ rawContent: payload
385
+ };
386
+ }
387
+ function isLoadingType$1(type) {
388
+ return type.includes("-loading");
389
+ }
390
+ const SIMPLE_CONTENT_TYPES = ["image", "video", "youtube"];
391
+ const PARSER_MAP = {
392
+ card: parseCard,
393
+ location: parseLocation,
394
+ buttons: parseButton,
395
+ tracing: parseTracing,
396
+ audio: parseAudio
397
+ };
398
+ function processMatch(type, payload) {
399
+ if (isLoadingType$1(type)) {
400
+ return null;
401
+ }
402
+ if (SIMPLE_CONTENT_TYPES.includes(type)) {
403
+ return { type, content: payload };
404
+ }
405
+ const parser = PARSER_MAP[type];
406
+ if (parser) {
407
+ const content = parser(payload);
408
+ return { type, content };
409
+ }
410
+ return null;
411
+ }
412
+ function isGeneralLoadingType(type) {
413
+ return GENERAL_LOADING_TYPES.includes(type);
414
+ }
415
+ function parseContentRecursively(content) {
416
+ const parts = [];
417
+ let remainingContent = content;
418
+ let iteration = 0;
419
+ const maxIterations = 100;
420
+ while (remainingContent.length > 0 && iteration < maxIterations) {
421
+ iteration++;
422
+ const matches = findMatches(remainingContent);
423
+ if (matches.length === 0) {
424
+ const cleanText = removeCompleteMarkers(remainingContent).trim();
425
+ if (cleanText) {
426
+ parts.push({ type: "text", content: cleanText });
427
+ }
428
+ break;
429
+ }
430
+ const firstMatch = matches.reduce(
431
+ (prev, current) => prev.index < current.index ? prev : current
432
+ );
433
+ const shouldSkip = isGeneralLoadingType(firstMatch.type);
434
+ const textBefore = remainingContent.substring(0, firstMatch.index);
435
+ const cleanTextBefore = removeCompleteMarkers(textBefore).trim();
436
+ if (cleanTextBefore) {
437
+ parts.push({ type: "text", content: cleanTextBefore });
438
+ }
439
+ if (!shouldSkip) {
440
+ const matchPayload = (firstMatch.match[1] ?? "").trim();
441
+ const part = processMatch(firstMatch.type, matchPayload);
442
+ if (part) {
443
+ parts.push(part);
444
+ }
445
+ }
446
+ const matchEnd = firstMatch.index + firstMatch.match[0].length;
447
+ remainingContent = remainingContent.substring(matchEnd);
448
+ }
449
+ return parts;
450
+ }
451
+ function useContentParser(description) {
452
+ return computed(() => {
453
+ const content = unref(description);
454
+ return parseContent(content || "");
455
+ });
456
+ }
457
+ function parseContent(content) {
458
+ const parts = [];
459
+ let remainingContent = content;
460
+ let iteration = 0;
461
+ const MAX_ITERATIONS = 100;
462
+ while (remainingContent.length > 0 && iteration < MAX_ITERATIONS) {
463
+ iteration++;
464
+ const matches = findMatches(remainingContent);
465
+ if (matches.length === 0) {
466
+ addCleanTextIfExists(parts, remainingContent);
467
+ break;
468
+ }
469
+ const firstMatch = matches.reduce(
470
+ (prev, current) => prev.index < current.index ? prev : current
471
+ );
472
+ const textBefore = remainingContent.substring(0, firstMatch.index);
473
+ addCleanTextIfExists(parts, textBefore);
474
+ processMatchAndAddParts(parts, firstMatch);
475
+ const matchEnd = firstMatch.index + firstMatch.match[0].length;
476
+ remainingContent = remainingContent.substring(matchEnd);
477
+ }
478
+ return parts;
479
+ }
480
+ function addCleanTextIfExists(parts, text) {
481
+ const cleanText = removeCompleteMarkers(text).trim();
482
+ if (cleanText) {
483
+ parts.push({ type: "text", content: cleanText });
484
+ }
485
+ }
486
+ function processMatchAndAddParts(parts, match) {
487
+ const matchPayload = (match.match[1] ?? "").trim();
488
+ const isLoadingType2 = match.type.includes("-loading");
489
+ if (isLoadingType2 && !matchPayload) {
490
+ return;
491
+ }
492
+ if (isLoadingType2 && matchPayload) {
493
+ const cleanPayload = removeOnlyLoadingMarkers(matchPayload);
494
+ if (cleanPayload.trim()) {
495
+ const nestedParts = parseContentRecursively(cleanPayload);
496
+ parts.push(...nestedParts);
497
+ }
498
+ return;
499
+ }
500
+ const part = processMatch(match.type, matchPayload);
501
+ if (part) {
502
+ parts.push(part);
503
+ }
504
+ }
505
+ const LOADING_PATTERNS = {
506
+ general: {
507
+ start: "[orca.loading.start]",
508
+ end: "[orca.loading.end]"
509
+ },
510
+ thinking: {
511
+ start: "[orca.loading.thinking.start]",
512
+ end: "[orca.loading.thinking.end]"
513
+ },
514
+ searching: {
515
+ start: "[orca.loading.searching.start]",
516
+ end: "[orca.loading.searching.end]"
517
+ },
518
+ coding: {
519
+ start: "[orca.loading.coding.start]",
520
+ end: "[orca.loading.coding.end]"
521
+ },
522
+ analyzing: {
523
+ start: "[orca.loading.analyzing.start]",
524
+ end: "[orca.loading.analyzing.end]"
525
+ },
526
+ generating: {
527
+ start: "[orca.loading.generating.start]",
528
+ end: "[orca.loading.generating.end]"
529
+ },
530
+ custom: {
531
+ start: "[orca.loading.custom.start]",
532
+ end: "[orca.loading.custom.end]"
533
+ },
534
+ image: {
535
+ start: "[orca.loading.image.start]",
536
+ end: "[orca.loading.image.end]",
537
+ actual: /\[orca\.image\.start\](.*?)\[orca\.image\.end\]/s
538
+ },
539
+ video: {
540
+ start: "[orca.loading.video.start]",
541
+ end: "[orca.loading.video.end]",
542
+ actual: /\[orca\.video\.start\](.*?)\[orca\.video\.end\]/s
543
+ },
544
+ youtube: {
545
+ start: "[orca.loading.youtube.start]",
546
+ end: "[orca.loading.youtube.end]",
547
+ actual: /\[orca\.youtube\.start\](.*?)\[orca\.youtube\.end\]/s
548
+ },
549
+ card: {
550
+ start: "[orca.loading.card.start]",
551
+ end: "[orca.loading.card.end]",
552
+ actual: /\[orca\.list\.card\.start\](.*?)\[orca\.list\.card\.end\]/s
553
+ },
554
+ map: {
555
+ start: "[orca.loading.map.start]",
556
+ end: "[orca.loading.map.end]",
557
+ actual: /\[orca\.location\.start\](.*?)\[orca\.location\.end\]/s
558
+ }
559
+ };
560
+ const LOADING_MESSAGES = {
561
+ "general-loading": "⏳ Loading...",
562
+ "thinking-loading": "🤔 Thinking...",
563
+ "searching-loading": "🔍 Searching...",
564
+ "coding-loading": "💻 Coding...",
565
+ "analyzing-loading": "📊 Analyzing...",
566
+ "generating-loading": "✨ Generating...",
567
+ "custom-loading": "⏳ Processing...",
568
+ "image-loading": "🖼️ Loading image...",
569
+ "video-loading": "🎥 Loading video...",
570
+ "youtube-loading": "📺 Loading YouTube video...",
571
+ "card-loading": "🃏 Loading cards...",
572
+ "map-loading": "🗺️ Loading map..."
573
+ };
574
+ function isActiveLoading(content, startPattern, endPattern) {
575
+ const hasStart = content.includes(startPattern);
576
+ const hasEnd = content.includes(endPattern);
577
+ return hasStart && !hasEnd;
578
+ }
579
+ function isActiveContentLoading(content, startPattern, endPattern, actualPattern) {
580
+ const hasStart = content.includes(startPattern);
581
+ const hasEnd = content.includes(endPattern);
582
+ const hasActual = actualPattern ? actualPattern.test(content) : false;
583
+ return hasStart && !hasEnd && !hasActual;
584
+ }
585
+ function useLoadingStates(description) {
586
+ const isLoading = ref(false);
587
+ const isImageLoading = ref(false);
588
+ const isVideoLoading = ref(false);
589
+ const isCardLoading = ref(false);
590
+ const isLocationLoading = ref(false);
591
+ const descriptionValue = computed(() => {
592
+ return unref(description);
593
+ });
594
+ watch(
595
+ descriptionValue,
596
+ (val) => {
597
+ if (!val) {
598
+ isLoading.value = false;
599
+ return;
600
+ }
601
+ const hasActiveLoading = isActiveLoading(
602
+ val,
603
+ LOADING_PATTERNS.general.start,
604
+ LOADING_PATTERNS.general.end
605
+ ) || isActiveLoading(
606
+ val,
607
+ LOADING_PATTERNS.thinking.start,
608
+ LOADING_PATTERNS.thinking.end
609
+ ) || isActiveLoading(
610
+ val,
611
+ LOADING_PATTERNS.searching.start,
612
+ LOADING_PATTERNS.searching.end
613
+ ) || isActiveLoading(
614
+ val,
615
+ LOADING_PATTERNS.coding.start,
616
+ LOADING_PATTERNS.coding.end
617
+ ) || isActiveLoading(
618
+ val,
619
+ LOADING_PATTERNS.analyzing.start,
620
+ LOADING_PATTERNS.analyzing.end
621
+ ) || isActiveLoading(
622
+ val,
623
+ LOADING_PATTERNS.generating.start,
624
+ LOADING_PATTERNS.generating.end
625
+ ) || isActiveLoading(
626
+ val,
627
+ LOADING_PATTERNS.custom.start,
628
+ LOADING_PATTERNS.custom.end
629
+ );
630
+ isLoading.value = hasActiveLoading;
631
+ },
632
+ { immediate: true }
633
+ );
634
+ watch(
635
+ descriptionValue,
636
+ (val) => {
637
+ isImageLoading.value = isActiveContentLoading(
638
+ val,
639
+ LOADING_PATTERNS.image.start,
640
+ LOADING_PATTERNS.image.end,
641
+ LOADING_PATTERNS.image.actual
642
+ );
643
+ },
644
+ { immediate: true }
645
+ );
646
+ watch(
647
+ descriptionValue,
648
+ (val) => {
649
+ const videoLoading = isActiveContentLoading(
650
+ val,
651
+ LOADING_PATTERNS.video.start,
652
+ LOADING_PATTERNS.video.end,
653
+ LOADING_PATTERNS.video.actual
654
+ );
655
+ const youtubeLoading = isActiveContentLoading(
656
+ val,
657
+ LOADING_PATTERNS.youtube.start,
658
+ LOADING_PATTERNS.youtube.end,
659
+ LOADING_PATTERNS.youtube.actual
660
+ );
661
+ isVideoLoading.value = videoLoading || youtubeLoading;
662
+ },
663
+ { immediate: true }
664
+ );
665
+ watch(
666
+ descriptionValue,
667
+ (val) => {
668
+ isCardLoading.value = isActiveContentLoading(
669
+ val,
670
+ LOADING_PATTERNS.card.start,
671
+ LOADING_PATTERNS.card.end,
672
+ LOADING_PATTERNS.card.actual
673
+ );
674
+ },
675
+ { immediate: true }
676
+ );
677
+ watch(
678
+ descriptionValue,
679
+ (val) => {
680
+ isLocationLoading.value = isActiveContentLoading(
681
+ val,
682
+ LOADING_PATTERNS.map.start,
683
+ LOADING_PATTERNS.map.end,
684
+ LOADING_PATTERNS.map.actual
685
+ );
686
+ },
687
+ { immediate: true }
688
+ );
689
+ const getLoadingMessage = (loadingType) => {
690
+ return LOADING_MESSAGES[loadingType] || LOADING_MESSAGES["general-loading"];
691
+ };
692
+ return {
693
+ isLoading,
694
+ isImageLoading,
695
+ isVideoLoading,
696
+ isCardLoading,
697
+ isLocationLoading,
698
+ getLoadingMessage
699
+ };
700
+ }
701
+ const COPY_ICON = `
702
+ <div class="d-flex align-center">
703
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
704
+ <rect x="6.66675" y="6.66675" width="10" height="10" rx="2" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
705
+ <path d="M13.3333 6.66659V4.99992C13.3333 4.07944 12.5871 3.33325 11.6666 3.33325H4.99992C4.07944 3.33325 3.33325 4.07944 3.33325 4.99992V11.6666C3.33325 12.5871 4.07944 13.3333 4.99992 13.3333H6.66659" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
706
+ </svg>
707
+ <span style="color:rgb(var(--v-theme-on-surface)); font-feature-settings: 'liga' off, 'clig' off; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 24px;">Copy</span>
708
+ </div>
709
+ `;
710
+ const COPIED_ICON = `
711
+ <div class="d-flex align-center">
712
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
713
+ <path d="M4.16663 9.99992L8.33329 14.1666L16.6666 5.83325" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
714
+ </svg>
715
+ <span style="color: rgb(var(--v-theme-on-surface)); font-feature-settings: 'liga' off, 'clig' off; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 24px;"> Copied</span>
716
+ </div>
717
+ `;
718
+ const COLLAPSE_ICON = `
719
+ <div class="d-flex align-center">
720
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
721
+ <path d="M7.5 14.1667L10 11.6667L12.5 14.1667" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
722
+ <path d="M7.5 5.83325L10 8.33325L12.5 5.83325" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
723
+ </svg>
724
+ <span style="color: rgb(var(--v-theme-on-surface)); font-feature-settings: 'liga' off, 'clig' off; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 24px;"> Collapse</span>
725
+ </div>
726
+ `;
727
+ const EXPAND_ICON = `
728
+ <div class="d-flex align-center">
729
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
730
+ <path d="M7.5 14.1667L10 11.6667L12.5 14.1667" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
731
+ <path d="M7.5 5.83325L10 8.33325L12.5 5.83325" stroke="rgb(var(--v-theme-on-surface))" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
732
+ </svg>
733
+ <span style="color: rgb(var(--v-theme-on-surface)); font-feature-settings: 'liga' off, 'clig' off; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 400; line-height: 24px;"> Expand</span>
734
+ </div>
735
+ `;
736
+ async function copyToClipboard(text, button) {
737
+ try {
738
+ await navigator.clipboard.writeText(text);
739
+ button.innerHTML = COPIED_ICON;
740
+ setTimeout(() => {
741
+ button.innerHTML = COPY_ICON;
742
+ }, 2e3);
743
+ } catch (error) {
744
+ console.error("Failed to copy code:", error);
745
+ }
746
+ }
747
+ function toggleCodeBlock(wrapper, button) {
748
+ const isCollapsed = wrapper.classList.contains("collapsed");
749
+ if (isCollapsed) {
750
+ wrapper.classList.remove("collapsed");
751
+ wrapper.style.maxHeight = "";
752
+ wrapper.style.overflow = "";
753
+ button.innerHTML = COLLAPSE_ICON;
754
+ } else {
755
+ wrapper.classList.add("collapsed");
756
+ const height = wrapper.scrollHeight;
757
+ wrapper.style.maxHeight = `${height}px`;
758
+ wrapper.offsetHeight;
759
+ wrapper.style.maxHeight = "0px";
760
+ wrapper.style.overflow = "hidden";
761
+ button.innerHTML = EXPAND_ICON;
762
+ }
763
+ }
764
+ function attachCodeButtons(block) {
765
+ if (block.closest(".code-container")) return;
766
+ const codeContainer = document.createElement("div");
767
+ codeContainer.className = "code-container";
768
+ const codeWrapper = document.createElement("div");
769
+ codeWrapper.className = "code-wrapper";
770
+ codeWrapper.style.transition = "max-height 0.3s ease, opacity 0.3s ease";
771
+ codeWrapper.style.overflow = "hidden";
772
+ codeWrapper.appendChild(block.cloneNode(true));
773
+ const buttonsContainer = document.createElement("div");
774
+ buttonsContainer.className = "buttons-container";
775
+ const copyButton = document.createElement("button");
776
+ copyButton.innerHTML = COPY_ICON;
777
+ copyButton.className = "copy-btn";
778
+ copyButton.onclick = () => {
779
+ var _a;
780
+ const code = ((_a = block.querySelector("code")) == null ? void 0 : _a.innerText) || "";
781
+ copyToClipboard(code, copyButton);
782
+ };
783
+ const collapseButton = document.createElement("button");
784
+ collapseButton.innerHTML = COLLAPSE_ICON;
785
+ collapseButton.className = "collapse-btn";
786
+ collapseButton.onclick = () => {
787
+ toggleCodeBlock(codeWrapper, collapseButton);
788
+ };
789
+ buttonsContainer.appendChild(collapseButton);
790
+ buttonsContainer.appendChild(copyButton);
791
+ codeContainer.appendChild(buttonsContainer);
792
+ codeContainer.appendChild(codeWrapper);
793
+ block.replaceWith(codeContainer);
794
+ }
795
+ function useCodeButtons(containerRef, shouldAddButtons) {
796
+ const addCodeButtons = () => {
797
+ nextTick(() => {
798
+ if (!containerRef.value || !shouldAddButtons()) return;
799
+ const codeBlocks = containerRef.value.querySelectorAll("pre");
800
+ codeBlocks.forEach((block) => {
801
+ attachCodeButtons(block);
802
+ });
803
+ });
804
+ };
805
+ onMounted(() => {
806
+ addCodeButtons();
807
+ });
808
+ return {
809
+ addCodeButtons
810
+ };
811
+ }
812
+ function useImageModal() {
813
+ const modalVisible = ref(false);
814
+ const currentImage = ref("");
815
+ const openModal = (imageUrl) => {
816
+ currentImage.value = imageUrl;
817
+ modalVisible.value = true;
818
+ };
819
+ const closeModal = () => {
820
+ modalVisible.value = false;
821
+ setTimeout(() => {
822
+ currentImage.value = "";
823
+ }, 300);
824
+ };
825
+ return {
826
+ modalVisible,
827
+ currentImage,
828
+ openModal,
829
+ closeModal
830
+ };
831
+ }
832
+ const LOADING_CONTENT_TYPES = [
833
+ "general-loading",
834
+ "thinking-loading",
835
+ "searching-loading",
836
+ "coding-loading",
837
+ "analyzing-loading",
838
+ "generating-loading",
839
+ "custom-loading",
840
+ "image-loading",
841
+ "video-loading",
842
+ "youtube-loading",
843
+ "card-loading",
844
+ "map-loading"
845
+ ];
846
+ function isLoadingType(type) {
847
+ return LOADING_CONTENT_TYPES.includes(type);
848
+ }
849
+ const escapeCodeHtml = (value) => {
850
+ const map = {
851
+ "&": "&amp;",
852
+ "<": "&lt;",
853
+ ">": "&gt;",
854
+ '"': "&quot;",
855
+ "'": "&#039;"
856
+ };
857
+ return value.replace(/[&<>"']/g, (m) => map[m]);
858
+ };
859
+ const md = new MarkdownIt({
860
+ html: false,
861
+ linkify: true,
862
+ typographer: true,
863
+ highlight: (str, lang) => {
864
+ if (lang && hljs.getLanguage(lang)) {
865
+ try {
866
+ return `<pre><code class="hljs">${hljs.highlight(str, { language: lang }).value}</code></pre>`;
867
+ } catch {
868
+ }
869
+ }
870
+ return `<pre><code class="hljs">${escapeCodeHtml(str)}</code></pre>`;
871
+ }
872
+ }).use(markdownItKatex).use(markdownItLinkAttributes, {
873
+ pattern: /^https?:\/\//,
874
+ attrs: {
875
+ target: "_blank",
876
+ rel: "noopener noreferrer"
877
+ }
878
+ });
879
+ function useMarkdown() {
880
+ const render = (text) => {
881
+ const cleanText = text.replace(/\[orca\..*?\]/g, "").trim();
882
+ return cleanText ? md.render(cleanText) : "";
883
+ };
884
+ return { render };
885
+ }
886
+ const _hoisted_1$e = { class: "image-container tw-my-4" };
887
+ const _hoisted_2$a = { class: "image-wrapper" };
888
+ const _hoisted_3$7 = ["src"];
889
+ const _sfc_main$e = /* @__PURE__ */ defineComponent({
890
+ __name: "OrcaImage",
891
+ props: {
892
+ url: {}
893
+ },
894
+ emits: ["open-modal"],
895
+ setup(__props, { emit: __emit }) {
896
+ const props = __props;
897
+ const emit = __emit;
898
+ const openModal = () => {
899
+ emit("open-modal", props.url);
900
+ };
901
+ return (_ctx, _cache) => {
902
+ return openBlock(), createElementBlock("div", _hoisted_1$e, [
903
+ createElementVNode("div", _hoisted_2$a, [
904
+ createElementVNode("img", {
905
+ src: __props.url,
906
+ alt: "Generated image",
907
+ class: "orca-image",
908
+ loading: "lazy",
909
+ onClick: openModal
910
+ }, null, 8, _hoisted_3$7),
911
+ _cache[0] || (_cache[0] = createStaticVNode('<div class="image-overlay" data-v-e4f9d4c4><div class="zoom-icon" data-v-e4f9d4c4><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-e4f9d4c4><circle cx="11" cy="11" r="8" data-v-e4f9d4c4></circle><path d="m21 21-4.35-4.35" data-v-e4f9d4c4></path><line x1="11" y1="8" x2="11" y2="14" data-v-e4f9d4c4></line><line x1="8" y1="11" x2="14" y2="11" data-v-e4f9d4c4></line></svg></div></div>', 1))
912
+ ])
913
+ ]);
914
+ };
915
+ }
916
+ });
917
+ const _export_sfc = (sfc, props) => {
918
+ const target = sfc.__vccOpts || sfc;
919
+ for (const [key, val] of props) {
920
+ target[key] = val;
921
+ }
922
+ return target;
923
+ };
924
+ const OrcaImage = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-e4f9d4c4"]]);
925
+ const _hoisted_1$d = { class: "orca-video-container" };
926
+ const _hoisted_2$9 = { class: "video-wrapper" };
927
+ const _sfc_main$d = /* @__PURE__ */ defineComponent({
928
+ __name: "OrcaVideo",
929
+ props: {
930
+ url: {}
931
+ },
932
+ setup(__props) {
933
+ const videoOptions = ref({
934
+ autoplay: false,
935
+ controls: true,
936
+ responsive: true,
937
+ fluid: true,
938
+ sources: [
939
+ {
940
+ type: "video/mp4",
941
+ src: ""
942
+ }
943
+ ]
944
+ });
945
+ return (_ctx, _cache) => {
946
+ return openBlock(), createElementBlock("div", _hoisted_1$d, [
947
+ createElementVNode("div", _hoisted_2$9, [
948
+ createVNode(unref(VideoPlayer), {
949
+ options: {
950
+ ...videoOptions.value,
951
+ sources: [
952
+ {
953
+ type: "video/mp4",
954
+ src: __props.url
955
+ }
956
+ ]
957
+ },
958
+ class: "video-player-custom"
959
+ }, null, 8, ["options"])
960
+ ])
961
+ ]);
962
+ };
963
+ }
964
+ });
965
+ const OrcaVideo = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-7a20a30c"]]);
966
+ const _hoisted_1$c = { class: "orca-youtube-container" };
967
+ const _hoisted_2$8 = { class: "youtube-wrapper" };
968
+ const _hoisted_3$6 = ["src"];
969
+ const _sfc_main$c = /* @__PURE__ */ defineComponent({
970
+ __name: "OrcaYouTube",
971
+ props: {
972
+ url: {}
973
+ },
974
+ setup(__props) {
975
+ const props = __props;
976
+ const embedUrl = computed(() => {
977
+ const videoId = getYouTubeId(props.url);
978
+ return `https://www.youtube.com/embed/${videoId}`;
979
+ });
980
+ return (_ctx, _cache) => {
981
+ return openBlock(), createElementBlock("div", _hoisted_1$c, [
982
+ createElementVNode("div", _hoisted_2$8, [
983
+ createElementVNode("iframe", {
984
+ width: "100%",
985
+ height: "100%",
986
+ src: embedUrl.value,
987
+ frameborder: "0",
988
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
989
+ allowfullscreen: "",
990
+ class: "youtube-iframe"
991
+ }, null, 8, _hoisted_3$6)
992
+ ])
993
+ ]);
994
+ };
995
+ }
996
+ });
997
+ const OrcaYouTube = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-9cd52c38"]]);
998
+ const _hoisted_1$b = { class: "orca-audio-container" };
999
+ const _hoisted_2$7 = { class: "audio-list" };
1000
+ const _hoisted_3$5 = { class: "audio-content" };
1001
+ const _hoisted_4$4 = { class: "audio-label" };
1002
+ const _hoisted_5 = ["type"];
1003
+ const _hoisted_6 = ["src", "type"];
1004
+ const _sfc_main$b = /* @__PURE__ */ defineComponent({
1005
+ __name: "OrcaAudio",
1006
+ props: {
1007
+ audioItems: {}
1008
+ },
1009
+ setup(__props) {
1010
+ return (_ctx, _cache) => {
1011
+ return openBlock(), createElementBlock("div", _hoisted_1$b, [
1012
+ createElementVNode("div", _hoisted_2$7, [
1013
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.audioItems, (audio, audioIndex) => {
1014
+ return openBlock(), createElementBlock("div", {
1015
+ key: audioIndex,
1016
+ class: "audio-item"
1017
+ }, [
1018
+ _cache[1] || (_cache[1] = createElementVNode("div", { class: "audio-icon-wrapper" }, [
1019
+ createElementVNode("svg", {
1020
+ class: "audio-icon",
1021
+ fill: "none",
1022
+ stroke: "currentColor",
1023
+ viewBox: "0 0 24 24"
1024
+ }, [
1025
+ createElementVNode("path", {
1026
+ "stroke-linecap": "round",
1027
+ "stroke-linejoin": "round",
1028
+ "stroke-width": "2",
1029
+ d: "M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
1030
+ })
1031
+ ])
1032
+ ], -1)),
1033
+ createElementVNode("div", _hoisted_3$5, [
1034
+ createElementVNode("p", _hoisted_4$4, toDisplayString(audio.label), 1),
1035
+ createElementVNode("audio", {
1036
+ controls: "",
1037
+ class: "audio-player",
1038
+ type: audio.type
1039
+ }, [
1040
+ createElementVNode("source", {
1041
+ src: audio.url,
1042
+ type: audio.type
1043
+ }, null, 8, _hoisted_6),
1044
+ _cache[0] || (_cache[0] = createTextVNode(" Your browser does not support the audio element. ", -1))
1045
+ ], 8, _hoisted_5)
1046
+ ])
1047
+ ]);
1048
+ }), 128))
1049
+ ])
1050
+ ]);
1051
+ };
1052
+ }
1053
+ });
1054
+ const OrcaAudio = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-ade9342b"]]);
1055
+ const _hoisted_1$a = { class: "orca-location-container" };
1056
+ const _hoisted_2$6 = { class: "map-wrapper" };
1057
+ const _hoisted_3$4 = { class: "location-info" };
1058
+ const _hoisted_4$3 = { class: "location-text" };
1059
+ const _sfc_main$a = /* @__PURE__ */ defineComponent({
1060
+ __name: "OrcaLocation",
1061
+ props: {
1062
+ latitude: {},
1063
+ longitude: {},
1064
+ mapboxToken: {}
1065
+ },
1066
+ setup(__props) {
1067
+ const props = __props;
1068
+ const mapInstance = ref(null);
1069
+ const mapLoading = ref(false);
1070
+ const onMapContainerReady = (el) => {
1071
+ const htmlEl = el && "tagName" in el ? el : null;
1072
+ if (!htmlEl) return;
1073
+ if (!el) return;
1074
+ mapLoading.value = true;
1075
+ nextTick(() => {
1076
+ try {
1077
+ mapboxgl.accessToken = props.mapboxToken || "pk.eyJ1IjoicG91cnlhYnpwIiwiYSI6ImNsZ3Vuanl4YzF2NXkzZW1tcnR0MTlxNXEifQ.I3RdtfiL0ObnXbWVKxW1gQ";
1078
+ if (mapInstance.value) {
1079
+ mapInstance.value.remove();
1080
+ mapInstance.value = null;
1081
+ }
1082
+ const containerId = `map-${props.latitude}-${props.longitude}`;
1083
+ htmlEl.id = containerId;
1084
+ const newMap = new mapboxgl.Map({
1085
+ container: htmlEl,
1086
+ style: "mapbox://styles/mapbox/streets-v11",
1087
+ center: [props.longitude, props.latitude],
1088
+ zoom: 12,
1089
+ attributionControl: false
1090
+ });
1091
+ mapInstance.value = newMap;
1092
+ newMap.on("load", () => {
1093
+ new mapboxgl.Marker({
1094
+ color: "#0D5FD6"
1095
+ }).setLngLat([props.longitude, props.latitude]).addTo(newMap);
1096
+ newMap.addControl(new mapboxgl.NavigationControl());
1097
+ setTimeout(() => {
1098
+ newMap.resize();
1099
+ }, 100);
1100
+ mapLoading.value = false;
1101
+ });
1102
+ newMap.on("error", (e) => {
1103
+ console.error("Mapbox error:", e);
1104
+ mapLoading.value = false;
1105
+ });
1106
+ newMap.on("render", () => {
1107
+ newMap.resize();
1108
+ });
1109
+ } catch (error) {
1110
+ console.error("Error initializing map:", error);
1111
+ mapLoading.value = false;
1112
+ }
1113
+ });
1114
+ };
1115
+ onUnmounted(() => {
1116
+ if (mapInstance.value) {
1117
+ mapInstance.value.remove();
1118
+ mapInstance.value = null;
1119
+ }
1120
+ });
1121
+ return (_ctx, _cache) => {
1122
+ return openBlock(), createElementBlock("div", _hoisted_1$a, [
1123
+ createElementVNode("div", _hoisted_2$6, [
1124
+ (openBlock(), createElementBlock("div", {
1125
+ ref: (el) => onMapContainerReady(el),
1126
+ class: "map-container",
1127
+ key: `map-${__props.latitude}-${__props.longitude}`
1128
+ }))
1129
+ ]),
1130
+ createElementVNode("div", _hoisted_3$4, [
1131
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "location-icon" }, [
1132
+ createElementVNode("svg", {
1133
+ width: "16",
1134
+ height: "16",
1135
+ viewBox: "0 0 24 24",
1136
+ fill: "none",
1137
+ stroke: "currentColor",
1138
+ "stroke-width": "2"
1139
+ }, [
1140
+ createElementVNode("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }),
1141
+ createElementVNode("circle", {
1142
+ cx: "12",
1143
+ cy: "10",
1144
+ r: "3"
1145
+ })
1146
+ ])
1147
+ ], -1)),
1148
+ createElementVNode("span", _hoisted_4$3, toDisplayString(__props.latitude.toFixed(6)) + ", " + toDisplayString(__props.longitude.toFixed(6)), 1)
1149
+ ])
1150
+ ]);
1151
+ };
1152
+ }
1153
+ });
1154
+ const OrcaLocation = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-99a42606"]]);
1155
+ const _hoisted_1$9 = { class: "orca-card-container" };
1156
+ const _hoisted_2$5 = {
1157
+ key: 0,
1158
+ class: "card-image-wrapper"
1159
+ };
1160
+ const _hoisted_3$3 = {
1161
+ key: 1,
1162
+ class: "card-subheader"
1163
+ };
1164
+ const _hoisted_4$2 = {
1165
+ key: 2,
1166
+ class: "card-text"
1167
+ };
1168
+ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
1169
+ __name: "OrcaCardList",
1170
+ props: {
1171
+ cards: {}
1172
+ },
1173
+ setup(__props) {
1174
+ return (_ctx, _cache) => {
1175
+ return openBlock(), createElementBlock("div", _hoisted_1$9, [
1176
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.cards, (card, i) => {
1177
+ return openBlock(), createBlock(unref(VCard), {
1178
+ key: i,
1179
+ class: "orca-card",
1180
+ elevation: "2"
1181
+ }, {
1182
+ default: withCtx(() => [
1183
+ card.photo ? (openBlock(), createElementBlock("div", _hoisted_2$5, [
1184
+ createVNode(unref(VImg), {
1185
+ src: card.photo,
1186
+ height: "223",
1187
+ cover: "",
1188
+ class: "card-image"
1189
+ }, null, 8, ["src"])
1190
+ ])) : createCommentVNode("", true),
1191
+ createVNode(unref(VCardItem), { class: "card-content" }, {
1192
+ default: withCtx(() => [
1193
+ card.header ? (openBlock(), createBlock(unref(VCardTitle), {
1194
+ key: 0,
1195
+ class: "card-header"
1196
+ }, {
1197
+ default: withCtx(() => [
1198
+ createTextVNode(toDisplayString(card.header), 1)
1199
+ ]),
1200
+ _: 2
1201
+ }, 1024)) : createCommentVNode("", true),
1202
+ card.subheader ? (openBlock(), createElementBlock("span", _hoisted_3$3, toDisplayString(card.subheader), 1)) : createCommentVNode("", true),
1203
+ card.text ? (openBlock(), createElementBlock("p", _hoisted_4$2, toDisplayString(card.text), 1)) : createCommentVNode("", true)
1204
+ ]),
1205
+ _: 2
1206
+ }, 1024)
1207
+ ]),
1208
+ _: 2
1209
+ }, 1024);
1210
+ }), 128))
1211
+ ]);
1212
+ };
1213
+ }
1214
+ });
1215
+ const OrcaCardList = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__scopeId", "data-v-d9e3b93c"]]);
1216
+ const _hoisted_1$8 = { class: "orca-buttons-container tw-my-4" };
1217
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
1218
+ __name: "OrcaButtons",
1219
+ props: {
1220
+ buttons: {},
1221
+ disabled: { type: Boolean }
1222
+ },
1223
+ emits: ["button-click"],
1224
+ setup(__props, { emit: __emit }) {
1225
+ const props = __props;
1226
+ const emit = __emit;
1227
+ const groupedButtons = computed(() => getGroupedButtons(props.buttons));
1228
+ const handleButtonClick = (button) => {
1229
+ if (button.type === "action" && !props.disabled) {
1230
+ emit("button-click", button);
1231
+ }
1232
+ };
1233
+ return (_ctx, _cache) => {
1234
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [
1235
+ (openBlock(true), createElementBlock(Fragment, null, renderList(groupedButtons.value, (row, rowIndex) => {
1236
+ return openBlock(), createElementBlock("div", {
1237
+ key: rowIndex,
1238
+ class: "button-row"
1239
+ }, [
1240
+ (openBlock(true), createElementBlock(Fragment, null, renderList(row, (button, index) => {
1241
+ return openBlock(), createBlock(unref(VBtn), {
1242
+ disabled: __props.disabled,
1243
+ key: index,
1244
+ class: normalizeClass(["orca-button", "custom-outlined-button"]),
1245
+ style: normalizeStyle(unref(getOutlinedButtonStyle)(button.color)),
1246
+ variant: "text",
1247
+ rounded: "xl",
1248
+ target: button.type === "link" ? "_blank" : void 0,
1249
+ href: button.type === "link" ? button.url : void 0,
1250
+ onClick: ($event) => handleButtonClick(button)
1251
+ }, createSlots({
1252
+ default: withCtx(() => [
1253
+ createElementVNode("span", {
1254
+ style: normalizeStyle(unref(getOutlinedButtonTextStyle)(button.color))
1255
+ }, toDisplayString(button.label), 5)
1256
+ ]),
1257
+ _: 2
1258
+ }, [
1259
+ button.type === "link" ? {
1260
+ name: "append",
1261
+ fn: withCtx(() => [
1262
+ createVNode(unref(VIcon), {
1263
+ icon: "tabler-external-link",
1264
+ style: normalizeStyle(unref(getAppendIconStyle)(button.color)),
1265
+ size: "small"
1266
+ }, null, 8, ["style"])
1267
+ ]),
1268
+ key: "0"
1269
+ } : void 0
1270
+ ]), 1032, ["disabled", "style", "target", "href", "onClick"]);
1271
+ }), 128))
1272
+ ]);
1273
+ }), 128))
1274
+ ]);
1275
+ };
1276
+ }
1277
+ });
1278
+ const OrcaButtons = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-480c6090"]]);
1279
+ const _hoisted_1$7 = {
1280
+ key: 0,
1281
+ class: "orca-trace-container"
1282
+ };
1283
+ const _hoisted_2$4 = { class: "trace-header" };
1284
+ const _hoisted_3$2 = {
1285
+ key: 0,
1286
+ class: "trace-content"
1287
+ };
1288
+ const _hoisted_4$1 = { class: "trace-pre" };
1289
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
1290
+ __name: "OrcaTracing",
1291
+ props: {
1292
+ tracingData: {},
1293
+ visibility: {},
1294
+ isAdmin: { type: Boolean }
1295
+ },
1296
+ setup(__props) {
1297
+ const props = __props;
1298
+ const traceVisible = ref(false);
1299
+ const isVisible = computed(() => traceVisible.value);
1300
+ const shouldShow = computed(() => {
1301
+ if (Array.isArray(props.tracingData)) {
1302
+ return props.tracingData.some(
1303
+ (item) => item.visibility === "all" || item.visibility === "admin" && props.isAdmin
1304
+ );
1305
+ }
1306
+ return props.tracingData.visibility === "all" || props.tracingData.visibility === "admin" && props.isAdmin;
1307
+ });
1308
+ const tracingContent = computed(() => {
1309
+ if (Array.isArray(props.tracingData)) {
1310
+ return props.tracingData.map((item) => item.content || item.rawContent).join("\n\n");
1311
+ }
1312
+ return props.tracingData.content || props.tracingData.rawContent || "";
1313
+ });
1314
+ const toggleTrace = () => {
1315
+ traceVisible.value = !traceVisible.value;
1316
+ };
1317
+ return (_ctx, _cache) => {
1318
+ return shouldShow.value ? (openBlock(), createElementBlock("div", _hoisted_1$7, [
1319
+ createVNode(unref(VCard), {
1320
+ class: "trace-card",
1321
+ elevation: "2"
1322
+ }, {
1323
+ default: withCtx(() => [
1324
+ createElementVNode("div", _hoisted_2$4, [
1325
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "trace-header-content" }, [
1326
+ createElementVNode("div", { class: "trace-icon" }, [
1327
+ createElementVNode("svg", {
1328
+ width: "20",
1329
+ height: "20",
1330
+ viewBox: "0 0 24 24",
1331
+ fill: "none",
1332
+ stroke: "currentColor",
1333
+ "stroke-width": "2"
1334
+ }, [
1335
+ createElementVNode("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
1336
+ ])
1337
+ ]),
1338
+ createElementVNode("strong", { class: "trace-title" }, "Trace Log")
1339
+ ], -1)),
1340
+ createVNode(unref(VBtn), {
1341
+ size: "small",
1342
+ variant: "tonal",
1343
+ color: "primary",
1344
+ class: "trace-toggle-btn",
1345
+ onClick: toggleTrace
1346
+ }, {
1347
+ default: withCtx(() => [
1348
+ createTextVNode(toDisplayString(isVisible.value ? "Hide" : "Show"), 1)
1349
+ ]),
1350
+ _: 1
1351
+ })
1352
+ ]),
1353
+ createVNode(unref(VExpandTransition), null, {
1354
+ default: withCtx(() => [
1355
+ isVisible.value ? (openBlock(), createElementBlock("div", _hoisted_3$2, [
1356
+ createElementVNode("pre", _hoisted_4$1, toDisplayString(tracingContent.value), 1)
1357
+ ])) : createCommentVNode("", true)
1358
+ ]),
1359
+ _: 1
1360
+ })
1361
+ ]),
1362
+ _: 1
1363
+ })
1364
+ ])) : createCommentVNode("", true);
1365
+ };
1366
+ }
1367
+ });
1368
+ const OrcaTracing = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-69e262d5"]]);
1369
+ const _hoisted_1$6 = ["innerHTML"];
1370
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
1371
+ __name: "ContentElement",
1372
+ props: {
1373
+ element: {},
1374
+ disabledButton: { type: Boolean },
1375
+ visibility: {},
1376
+ isAdmin: { type: Boolean },
1377
+ mapboxToken: {}
1378
+ },
1379
+ emits: ["image-modal", "button-click"],
1380
+ setup(__props, { emit: __emit }) {
1381
+ const emit = __emit;
1382
+ const { render: renderText } = useMarkdown();
1383
+ const handleImageModal = (url) => {
1384
+ emit("image-modal", url);
1385
+ };
1386
+ const handleButtonClick = (button) => {
1387
+ emit("button-click", button);
1388
+ };
1389
+ return (_ctx, _cache) => {
1390
+ return openBlock(), createElementBlock("div", null, [
1391
+ __props.element.type === "text" ? (openBlock(), createElementBlock("div", {
1392
+ key: 0,
1393
+ class: "text-content",
1394
+ innerHTML: unref(renderText)(__props.element.content)
1395
+ }, null, 8, _hoisted_1$6)) : __props.element.type === "image" ? (openBlock(), createBlock(OrcaImage, {
1396
+ key: 1,
1397
+ url: __props.element.content,
1398
+ onOpenModal: handleImageModal
1399
+ }, null, 8, ["url"])) : __props.element.type === "video" ? (openBlock(), createBlock(OrcaVideo, {
1400
+ key: 2,
1401
+ url: __props.element.content
1402
+ }, null, 8, ["url"])) : __props.element.type === "youtube" ? (openBlock(), createBlock(OrcaYouTube, {
1403
+ key: 3,
1404
+ url: __props.element.content
1405
+ }, null, 8, ["url"])) : __props.element.type === "audio" ? (openBlock(), createBlock(OrcaAudio, {
1406
+ key: 4,
1407
+ "audio-items": __props.element.content
1408
+ }, null, 8, ["audio-items"])) : __props.element.type === "location" ? (openBlock(), createBlock(OrcaLocation, {
1409
+ key: 5,
1410
+ latitude: __props.element.content.latitude,
1411
+ longitude: __props.element.content.longitude,
1412
+ "mapbox-token": __props.mapboxToken
1413
+ }, null, 8, ["latitude", "longitude", "mapbox-token"])) : __props.element.type === "card" ? (openBlock(), createBlock(OrcaCardList, {
1414
+ key: 6,
1415
+ cards: __props.element.content
1416
+ }, null, 8, ["cards"])) : __props.element.type === "buttons" ? (openBlock(), createBlock(OrcaButtons, {
1417
+ key: 7,
1418
+ buttons: __props.element.content,
1419
+ disabled: __props.disabledButton,
1420
+ onButtonClick: handleButtonClick
1421
+ }, null, 8, ["buttons", "disabled"])) : __props.element.type === "tracing" ? (openBlock(), createBlock(OrcaTracing, {
1422
+ key: 8,
1423
+ "tracing-data": __props.element.content,
1424
+ visibility: __props.visibility,
1425
+ "is-admin": __props.isAdmin
1426
+ }, null, 8, ["tracing-data", "visibility", "is-admin"])) : createCommentVNode("", true)
1427
+ ]);
1428
+ };
1429
+ }
1430
+ });
1431
+ const _hoisted_1$5 = {
1432
+ key: 0,
1433
+ class: "general-loading-container"
1434
+ };
1435
+ const _hoisted_2$3 = { class: "loading-content" };
1436
+ const _hoisted_3$1 = { class: "loading-text" };
1437
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
1438
+ __name: "GeneralLoading",
1439
+ props: {
1440
+ isLoading: { type: Boolean },
1441
+ message: {}
1442
+ },
1443
+ setup(__props) {
1444
+ return (_ctx, _cache) => {
1445
+ return openBlock(), createBlock(Transition, {
1446
+ name: "fade",
1447
+ mode: "out-in"
1448
+ }, {
1449
+ default: withCtx(() => [
1450
+ __props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1$5, [
1451
+ createElementVNode("div", _hoisted_2$3, [
1452
+ createVNode(unref(VProgressCircular), {
1453
+ indeterminate: "",
1454
+ size: 24,
1455
+ width: 3,
1456
+ color: "primary",
1457
+ class: "loading-spinner"
1458
+ }),
1459
+ createElementVNode("span", _hoisted_3$1, toDisplayString(__props.message), 1)
1460
+ ])
1461
+ ])) : createCommentVNode("", true)
1462
+ ]),
1463
+ _: 1
1464
+ });
1465
+ };
1466
+ }
1467
+ });
1468
+ const GeneralLoading = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-ba70521a"]]);
1469
+ const _hoisted_1$4 = {
1470
+ key: 0,
1471
+ class: "image-loading-placeholder"
1472
+ };
1473
+ const _hoisted_2$2 = { class: "loading-skeleton-image" };
1474
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1475
+ __name: "ImageLoading",
1476
+ props: {
1477
+ isLoading: { type: Boolean }
1478
+ },
1479
+ setup(__props) {
1480
+ return (_ctx, _cache) => {
1481
+ return openBlock(), createBlock(Transition, {
1482
+ name: "fade",
1483
+ mode: "out-in"
1484
+ }, {
1485
+ default: withCtx(() => [
1486
+ __props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1$4, [
1487
+ createElementVNode("div", _hoisted_2$2, [
1488
+ createVNode(unref(VProgressCircular), {
1489
+ indeterminate: "",
1490
+ size: 48,
1491
+ width: 4,
1492
+ color: "primary",
1493
+ class: "loading-spinner-large"
1494
+ }),
1495
+ _cache[0] || (_cache[0] = createElementVNode("span", { class: "loading-skeleton-text" }, "🖼️ Loading image...", -1))
1496
+ ])
1497
+ ])) : createCommentVNode("", true)
1498
+ ]),
1499
+ _: 1
1500
+ });
1501
+ };
1502
+ }
1503
+ });
1504
+ const ImageLoading = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-39a596d3"]]);
1505
+ const _hoisted_1$3 = {
1506
+ key: 0,
1507
+ class: "video-loading-placeholder"
1508
+ };
1509
+ const _hoisted_2$1 = { class: "loading-skeleton-video" };
1510
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1511
+ __name: "VideoLoading",
1512
+ props: {
1513
+ isLoading: { type: Boolean }
1514
+ },
1515
+ setup(__props) {
1516
+ return (_ctx, _cache) => {
1517
+ return openBlock(), createBlock(Transition, {
1518
+ name: "fade",
1519
+ mode: "out-in"
1520
+ }, {
1521
+ default: withCtx(() => [
1522
+ __props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
1523
+ createElementVNode("div", _hoisted_2$1, [
1524
+ createVNode(unref(VProgressCircular), {
1525
+ indeterminate: "",
1526
+ size: 48,
1527
+ width: 4,
1528
+ color: "primary",
1529
+ class: "loading-spinner-large"
1530
+ }),
1531
+ _cache[0] || (_cache[0] = createElementVNode("div", { class: "loading-skeleton-text" }, "🎥 Loading video...", -1))
1532
+ ])
1533
+ ])) : createCommentVNode("", true)
1534
+ ]),
1535
+ _: 1
1536
+ });
1537
+ };
1538
+ }
1539
+ });
1540
+ const VideoLoading = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-0889a265"]]);
1541
+ const _hoisted_1$2 = {
1542
+ key: 0,
1543
+ class: "card-loading-placeholder"
1544
+ };
1545
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1546
+ __name: "CardLoading",
1547
+ props: {
1548
+ isLoading: { type: Boolean }
1549
+ },
1550
+ setup(__props) {
1551
+ const VSkeletonLoader = components.VSkeletonLoader;
1552
+ return (_ctx, _cache) => {
1553
+ return openBlock(), createBlock(Transition, {
1554
+ name: "fade",
1555
+ mode: "out-in"
1556
+ }, {
1557
+ default: withCtx(() => [
1558
+ __props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
1559
+ createVNode(unref(VSkeletonLoader), {
1560
+ class: "card-skeleton",
1561
+ width: "311",
1562
+ type: "image, article"
1563
+ }),
1564
+ _cache[0] || (_cache[0] = createElementVNode("span", { class: "loading-skeleton-text" }, "🃏 Loading cards...", -1))
1565
+ ])) : createCommentVNode("", true)
1566
+ ]),
1567
+ _: 1
1568
+ });
1569
+ };
1570
+ }
1571
+ });
1572
+ const CardLoading = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-2d326b15"]]);
1573
+ const _hoisted_1$1 = {
1574
+ key: 0,
1575
+ class: "map-loading-placeholder"
1576
+ };
1577
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1578
+ __name: "MapLoading",
1579
+ props: {
1580
+ isLoading: { type: Boolean }
1581
+ },
1582
+ setup(__props) {
1583
+ const VSkeletonLoader = components.VSkeletonLoader;
1584
+ return (_ctx, _cache) => {
1585
+ return openBlock(), createBlock(Transition, {
1586
+ name: "fade",
1587
+ mode: "out-in"
1588
+ }, {
1589
+ default: withCtx(() => [
1590
+ __props.isLoading ? (openBlock(), createElementBlock("div", _hoisted_1$1, [
1591
+ createVNode(unref(VSkeletonLoader), {
1592
+ class: "map-skeleton",
1593
+ width: "500",
1594
+ height: "300",
1595
+ type: "image"
1596
+ }),
1597
+ _cache[0] || (_cache[0] = createElementVNode("span", { class: "loading-skeleton-text" }, "🗺️ Loading map...", -1))
1598
+ ])) : createCommentVNode("", true)
1599
+ ]),
1600
+ _: 1
1601
+ });
1602
+ };
1603
+ }
1604
+ });
1605
+ const MapLoading = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-4bb3095a"]]);
1606
+ const _hoisted_1 = { class: "message-content" };
1607
+ const _hoisted_2 = {
1608
+ key: 0,
1609
+ class: "tw-flex tw-flex-wrap tw-gap-4 tw-mt-4 tw-mb-4"
1610
+ };
1611
+ const _hoisted_3 = ["src", "onClick"];
1612
+ const _hoisted_4 = { class: "modal-content" };
1613
+ const _sfc_main = /* @__PURE__ */ defineComponent({
1614
+ __name: "OrcaMarkdown",
1615
+ props: {
1616
+ description: {},
1617
+ role: {},
1618
+ images: {},
1619
+ fileAttachments: { default: () => [] },
1620
+ isLastMessage: { type: Boolean, default: false },
1621
+ storeIdentifier: {},
1622
+ visibility: { default: "all" }
1623
+ },
1624
+ emits: ["send-message"],
1625
+ setup(__props, { emit: __emit }) {
1626
+ const props = __props;
1627
+ const emit = __emit;
1628
+ const messageContentRef = ref(null);
1629
+ const { modalVisible, currentImage, openModal, closeModal } = useImageModal();
1630
+ const contentParts = useContentParser(computed(() => props.description));
1631
+ const {
1632
+ isLoading,
1633
+ isImageLoading,
1634
+ isVideoLoading,
1635
+ isCardLoading,
1636
+ isLocationLoading,
1637
+ getLoadingMessage
1638
+ } = useLoadingStates(computed(() => props.description));
1639
+ const imageFiles = computed(() => {
1640
+ return props.fileAttachments.filter((file) => file && isImageFile(file));
1641
+ });
1642
+ const nonImageFiles = computed(() => {
1643
+ return props.fileAttachments.filter((file) => file && !isImageFile(file));
1644
+ });
1645
+ const disabledButton = computed(() => {
1646
+ return props.role !== "assistant" || !props.isLastMessage || isAdminPage();
1647
+ });
1648
+ const isAdminPage = () => {
1649
+ return props.visibility === "admin";
1650
+ };
1651
+ const getActiveLoadingType = computed(() => {
1652
+ const desc = props.description || "";
1653
+ if (desc.includes("[orca.loading.thinking.start]") && !desc.includes("[orca.loading.thinking.end]")) {
1654
+ return "thinking-loading";
1655
+ }
1656
+ if (desc.includes("[orca.loading.searching.start]") && !desc.includes("[orca.loading.searching.end]")) {
1657
+ return "searching-loading";
1658
+ }
1659
+ if (desc.includes("[orca.loading.coding.start]") && !desc.includes("[orca.loading.coding.end]")) {
1660
+ return "coding-loading";
1661
+ }
1662
+ if (desc.includes("[orca.loading.analyzing.start]") && !desc.includes("[orca.loading.analyzing.end]")) {
1663
+ return "analyzing-loading";
1664
+ }
1665
+ if (desc.includes("[orca.loading.generating.start]") && !desc.includes("[orca.loading.generating.end]")) {
1666
+ return "generating-loading";
1667
+ }
1668
+ if (desc.includes("[orca.loading.custom.start]") && !desc.includes("[orca.loading.custom.end]")) {
1669
+ return "custom-loading";
1670
+ }
1671
+ if (desc.includes("[orca.loading.start]") && !desc.includes("[orca.loading.end]")) {
1672
+ return "general-loading";
1673
+ }
1674
+ return null;
1675
+ });
1676
+ const getCurrentLoadingMessage = computed(() => {
1677
+ if (isLoading.value) {
1678
+ const activeType = getActiveLoadingType.value;
1679
+ if (activeType) {
1680
+ return getLoadingMessage(activeType);
1681
+ }
1682
+ return "⏳ Loading...";
1683
+ }
1684
+ return "⏳ Loading...";
1685
+ });
1686
+ const { addCodeButtons } = useCodeButtons(
1687
+ messageContentRef,
1688
+ () => props.role !== "user"
1689
+ );
1690
+ watch(contentParts, () => {
1691
+ addCodeButtons();
1692
+ });
1693
+ const handleButtonClick = async (button) => {
1694
+ if (button.type === "action" && !disabledButton.value) {
1695
+ try {
1696
+ emit("send-message", {
1697
+ message: button.label,
1698
+ buttonData: button,
1699
+ type: "button-action"
1700
+ });
1701
+ } catch (error) {
1702
+ console.error("Error emitting button click:", error);
1703
+ }
1704
+ }
1705
+ };
1706
+ const handleImageModal = (url) => {
1707
+ openModal(url);
1708
+ };
1709
+ return (_ctx, _cache) => {
1710
+ return openBlock(), createElementBlock(Fragment, null, [
1711
+ createElementVNode("div", _hoisted_1, [
1712
+ createElementVNode("div", {
1713
+ ref_key: "messageContentRef",
1714
+ ref: messageContentRef,
1715
+ class: "content-wrapper"
1716
+ }, [
1717
+ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(contentParts), (part, index) => {
1718
+ return openBlock(), createElementBlock(Fragment, { key: index }, [
1719
+ !unref(isLoadingType)(part.type) ? (openBlock(), createBlock(_sfc_main$6, {
1720
+ key: 0,
1721
+ element: part,
1722
+ "disabled-button": disabledButton.value,
1723
+ visibility: props.visibility,
1724
+ "is-admin": isAdminPage(),
1725
+ onImageModal: handleImageModal,
1726
+ onButtonClick: handleButtonClick
1727
+ }, null, 8, ["element", "disabled-button", "visibility", "is-admin"])) : createCommentVNode("", true)
1728
+ ], 64);
1729
+ }), 128)),
1730
+ createVNode(GeneralLoading, {
1731
+ isLoading: unref(isLoading),
1732
+ message: getCurrentLoadingMessage.value
1733
+ }, null, 8, ["isLoading", "message"]),
1734
+ createVNode(ImageLoading, { isLoading: unref(isImageLoading) }, null, 8, ["isLoading"]),
1735
+ createVNode(VideoLoading, { isLoading: unref(isVideoLoading) }, null, 8, ["isLoading"]),
1736
+ createVNode(CardLoading, { isLoading: unref(isCardLoading) }, null, 8, ["isLoading"]),
1737
+ createVNode(MapLoading, { isLoading: unref(isLocationLoading) }, null, 8, ["isLoading"]),
1738
+ props.fileAttachments && props.fileAttachments.length > 0 && props.role === "user" ? (openBlock(), createElementBlock("div", _hoisted_2, [
1739
+ (openBlock(true), createElementBlock(Fragment, null, renderList(imageFiles.value, (file) => {
1740
+ return openBlock(), createElementBlock("img", {
1741
+ key: file,
1742
+ src: file,
1743
+ class: "tw-w-[300px] lg:tw-w-[303px] tw-h-[300px] lg:tw-h-[303px] tw-object-cover tw-rounded-lg tw-cursor-pointer",
1744
+ onClick: ($event) => unref(openModal)(file)
1745
+ }, null, 8, _hoisted_3);
1746
+ }), 128)),
1747
+ (openBlock(true), createElementBlock(Fragment, null, renderList(nonImageFiles.value, (file) => {
1748
+ return openBlock(), createBlock(unref(VBtn), {
1749
+ key: file,
1750
+ class: "text-center text-sm",
1751
+ variant: "tonal",
1752
+ color: "grey-500",
1753
+ href: file,
1754
+ target: "_blank",
1755
+ rel: "noopener noreferrer"
1756
+ }, {
1757
+ default: withCtx(() => [
1758
+ createTextVNode(toDisplayString(unref(getFileNameFromUrl)(file)), 1)
1759
+ ]),
1760
+ _: 2
1761
+ }, 1032, ["href"]);
1762
+ }), 128))
1763
+ ])) : createCommentVNode("", true)
1764
+ ], 512)
1765
+ ]),
1766
+ createVNode(unref(VDialog), {
1767
+ modelValue: unref(modalVisible),
1768
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => isRef(modalVisible) ? modalVisible.value = $event : null),
1769
+ fullscreen: "",
1770
+ class: "image-modal",
1771
+ scrim: "rgba(0, 0, 0, 0.85)",
1772
+ onClick: unref(closeModal),
1773
+ transition: "fade-transition"
1774
+ }, {
1775
+ default: withCtx(() => [
1776
+ createElementVNode("div", {
1777
+ class: "modal-close-btn",
1778
+ onClick: _cache[0] || (_cache[0] = withModifiers(
1779
+ //@ts-ignore
1780
+ (...args) => unref(closeModal) && unref(closeModal)(...args),
1781
+ ["stop"]
1782
+ ))
1783
+ }, [..._cache[2] || (_cache[2] = [
1784
+ createElementVNode("button", {
1785
+ class: "close-button",
1786
+ "aria-label": "Close image"
1787
+ }, [
1788
+ createElementVNode("svg", {
1789
+ width: "24",
1790
+ height: "24",
1791
+ viewBox: "0 0 24 24",
1792
+ fill: "none",
1793
+ stroke: "currentColor",
1794
+ "stroke-width": "2.5",
1795
+ "stroke-linecap": "round",
1796
+ "stroke-linejoin": "round"
1797
+ }, [
1798
+ createElementVNode("line", {
1799
+ x1: "18",
1800
+ y1: "6",
1801
+ x2: "6",
1802
+ y2: "18"
1803
+ }),
1804
+ createElementVNode("line", {
1805
+ x1: "6",
1806
+ y1: "6",
1807
+ x2: "18",
1808
+ y2: "18"
1809
+ })
1810
+ ])
1811
+ ], -1)
1812
+ ])]),
1813
+ createElementVNode("div", _hoisted_4, [
1814
+ createVNode(unref(VImg), {
1815
+ src: unref(currentImage),
1816
+ class: "modal-image",
1817
+ contain: ""
1818
+ }, null, 8, ["src"])
1819
+ ])
1820
+ ]),
1821
+ _: 1
1822
+ }, 8, ["modelValue", "onClick"])
1823
+ ], 64);
1824
+ };
1825
+ }
1826
+ });
1827
+ const OrcaMarkdown = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-619a1855"]]);
1828
+ const version = "1.0.1";
1829
+ const packageInfo = {
1830
+ name: "@orca-pt/orca-components",
1831
+ version: "1.0.1",
1832
+ description: "Orca native components for rendering special content markers",
1833
+ author: "Orca Team"
1834
+ };
1835
+ export {
1836
+ OrcaMarkdown,
1837
+ cleanOrcaMarkers,
1838
+ generateMapId,
1839
+ getAppendIconStyle,
1840
+ getFileNameFromUrl,
1841
+ getGroupedButtons,
1842
+ getOutlinedButtonStyle,
1843
+ getOutlinedButtonTextStyle,
1844
+ getVuetifyColor,
1845
+ getYouTubeId,
1846
+ hasLoadingMarkers,
1847
+ isImageFile,
1848
+ packageInfo,
1849
+ version
1850
+ };
1851
+ //# sourceMappingURL=orca-components.es.js.map