@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 @@
1
+ {"version":3,"file":"orca-components.umd.js","sources":["../src/utils/helpers.ts","../src/composables/parsing/markerDefinitions.ts","../src/composables/parsing/markerUtils.ts","../src/composables/parsing/markerOperations.ts","../src/composables/parsing/markerCleaner.ts","../src/composables/core/matchFinder.ts","../src/composables/parsers/baseParser.ts","../src/composables/parsers/parseCard.ts","../src/composables/parsers/parseButton.ts","../src/composables/parsers/parseAudio.ts","../src/composables/core/matchProcessor.ts","../src/composables/parsers/parseLocation.ts","../src/composables/parsers/parseTracing.ts","../src/composables/core/recursiveParser.ts","../src/composables/useContentParser.ts","../src/composables/useLoadingStates.ts","../src/composables/useCodeButtons.ts","../src/constants/loadingTypes.ts","../src/composables/useMarkdown.ts","../src/components/renderers/OrcaImage.vue","../src/components/renderers/OrcaVideo.vue","../src/components/renderers/OrcaYouTube.vue","../src/components/renderers/OrcaAudio.vue","../src/components/renderers/OrcaLocation.vue","../src/components/renderers/OrcaCardList.vue","../src/components/renderers/OrcaButtons.vue","../src/components/renderers/OrcaTracing.vue","../src/components/ContentElement.vue","../src/components/loading/GeneralLoading.vue","../src/components/loading/ImageLoading.vue","../src/components/loading/VideoLoading.vue","../src/components/loading/CardLoading.vue","../src/components/loading/MapLoading.vue","../src/components/OrcaMarkdown.vue","../src/composables/useImageModal.ts","../src/index.ts"],"sourcesContent":["import type { ButtonData } from \"../types\";\n\n/**\n * Utility functions for Orca Components\n */\n\n/**\n * بررسی اینکه آیا URL یک فایل تصویری است یا خیر\n */\nexport function isImageFile(url: string): boolean {\n const imageExtensions = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\",\n \".bmp\",\n \".svg\",\n ];\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname.toLowerCase();\n return imageExtensions.some((ext) => pathname.endsWith(ext));\n } catch (e) {\n return false;\n }\n}\n\n/**\n * استخراج نام فایل از URL\n */\nexport function getFileNameFromUrl(url: string): string | null {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const segments = pathname.split(\"/\");\n const encodedFileName = segments.pop() || \"\";\n return decodeURIComponent(encodedFileName);\n } catch (e) {\n return null;\n }\n}\n\n/**\n * استخراج YouTube ID از URL\n */\nexport function getYouTubeId(url: string): string {\n const regExp =\n /^.*((youtu.be\\/)|(v\\/)|(\\/u\\/\\w\\/)|(embed\\/)|(watch\\?))\\??v?=?([^#&?]*).*/;\n const match = url.match(regExp);\n return match && match[7].length === 11 ? match[7] : \"\";\n}\n\n/**\n * تبدیل نام رنگ Vuetify\n */\nexport function getVuetifyColor(colorName?: string): string {\n if (!colorName) return \"#1976D2\"; // primary blue\n\n // Map Vuetify color names to hex values\n const colorMap: Record<string, string> = {\n primary: \"#1976D2\",\n secondary: \"#424242\",\n success: \"#4CAF50\",\n info: \"#2196F3\",\n warning: \"#FB8C00\",\n error: \"#FF5252\",\n accent: \"#82B1FF\",\n };\n\n // If it's a Vuetify color name, return the hex value\n if (colorMap[colorName.toLowerCase()]) {\n return colorMap[colorName.toLowerCase()];\n }\n\n // If it's already a hex color or other valid CSS color, return it\n return colorName;\n}\n\n/**\n * گروه‌بندی دکمه‌ها بر اساس ردیف\n */\nexport function getGroupedButtons(buttons: ButtonData[]): ButtonData[][] {\n const rows: Record<number, ButtonData[]> = {};\n\n buttons.forEach((button) => {\n const row = button.row || 1;\n if (!rows[row]) {\n rows[row] = [];\n }\n rows[row].push(button);\n });\n\n // تبدیل به آرایه و مرتب‌سازی\n return Object.keys(rows)\n .sort((a, b) => parseInt(a) - parseInt(b))\n .map((row) => rows[parseInt(row)]);\n}\n\n/**\n * تولید ID یکتا برای container نقشه\n */\nexport function generateMapId(index: number): string {\n return `map-container-${index}-${Date.now()}-${Math.random()\n .toString(36)\n .substr(2, 9)}`;\n}\n\n/**\n * پاک کردن marker های orca از متن\n */\nexport function cleanOrcaMarkers(text: string): string {\n return text.replace(/\\[orca\\..*?\\]/g, \"\").trim();\n}\n\n/**\n * بررسی اینکه آیا محتوا loading marker دارد یا خیر\n */\nexport function hasLoadingMarkers(content: string): boolean {\n return /\\[orca\\.(?:loading|image\\.loading|loading\\.image)\\.start\\]/.test(\n content\n );\n}\n\n/**\n * استخراج style برای دکمه‌های outlined\n */\nexport function getOutlinedButtonStyle(color?: string): Record<string, string> {\n if (!color) return {};\n const hexColor = getVuetifyColor(color);\n return {\n border: `1px solid ${hexColor}`,\n color: hexColor,\n \"background-color\": \"transparent\",\n };\n}\n\n/**\n * استخراج style برای متن دکمه‌های outlined\n */\nexport function getOutlinedButtonTextStyle(\n color?: string\n): Record<string, string> {\n if (!color) return {};\n const hexColor = getVuetifyColor(color);\n return {\n color: hexColor,\n \"background-color\": \"transparent\",\n };\n}\n\n/**\n * استخراج style برای آیکون append\n */\nexport function getAppendIconStyle(color?: string): Record<string, string> {\n if (!color) return {};\n const hexColor = getVuetifyColor(color);\n return {\n color: hexColor,\n fill: hexColor,\n };\n}\n","import type { ContentPartType } from \"../../types\";\n\n/**\n * Marker Types - Pure Data\n * No logic, just type definitions\n */\n\nexport type MarkerConfig = {\n type: ContentPartType;\n start: string;\n end: string;\n};\n\n/**\n * All marker definitions - Single Source of Truth\n * ONLY data, no functions\n */\nexport const MARKERS: MarkerConfig[] = [\n // Loading markers (general)\n {\n type: \"general-loading\",\n start: \"[orca.loading.start]\",\n end: \"[orca.loading.end]\",\n },\n {\n type: \"thinking-loading\",\n start: \"[orca.loading.thinking.start]\",\n end: \"[orca.loading.thinking.end]\",\n },\n {\n type: \"searching-loading\",\n start: \"[orca.loading.searching.start]\",\n end: \"[orca.loading.searching.end]\",\n },\n {\n type: \"coding-loading\",\n start: \"[orca.loading.coding.start]\",\n end: \"[orca.loading.coding.end]\",\n },\n {\n type: \"analyzing-loading\",\n start: \"[orca.loading.analyzing.start]\",\n end: \"[orca.loading.analyzing.end]\",\n },\n {\n type: \"generating-loading\",\n start: \"[orca.loading.generating.start]\",\n end: \"[orca.loading.generating.end]\",\n },\n {\n type: \"custom-loading\",\n start: \"[orca.loading.custom.start]\",\n end: \"[orca.loading.custom.end]\",\n },\n\n // Loading markers (content-specific)\n {\n type: \"image-loading\",\n start: \"[orca.loading.image.start]\",\n end: \"[orca.loading.image.end]\",\n },\n {\n type: \"video-loading\",\n start: \"[orca.loading.video.start]\",\n end: \"[orca.loading.video.end]\",\n },\n {\n type: \"youtube-loading\",\n start: \"[orca.loading.youtube.start]\",\n end: \"[orca.loading.youtube.end]\",\n },\n {\n type: \"card-loading\",\n start: \"[orca.loading.card.list.start]\",\n end: \"[orca.loading.card.list.end]\",\n },\n {\n type: \"map-loading\",\n start: \"[orca.loading.map.start]\",\n end: \"[orca.loading.map.end]\",\n },\n\n // Content markers\n { type: \"image\", start: \"[orca.image.start]\", end: \"[orca.image.end]\" },\n { type: \"video\", start: \"[orca.video.start]\", end: \"[orca.video.end]\" },\n {\n type: \"youtube\",\n start: \"[orca.youtube.start]\",\n end: \"[orca.youtube.end]\",\n },\n {\n type: \"card\",\n start: \"[orca.list.card.start]\",\n end: \"[orca.list.card.end]\",\n },\n {\n type: \"location\",\n start: \"[orca.location.start]\",\n end: \"[orca.location.end]\",\n },\n {\n type: \"buttons\",\n start: \"[orca.buttons.start]\",\n end: \"[orca.buttons.end]\",\n },\n {\n type: \"tracing\",\n start: \"[orca.tracing.start]\",\n end: \"[orca.tracing.end]\",\n },\n { type: \"audio\", start: \"[orca.audio.start]\", end: \"[orca.audio.end]\" },\n];\n\n/**\n * General loading type names - Derived from MARKERS\n * Single source of truth for general loading types\n */\nexport const GENERAL_LOADING_TYPES = [\n \"general-loading\",\n \"thinking-loading\",\n \"searching-loading\",\n \"coding-loading\",\n \"analyzing-loading\",\n \"generating-loading\",\n \"custom-loading\",\n] as const;\n","import type { ContentPartType } from \"../../types\";\nimport {\n MARKERS,\n GENERAL_LOADING_TYPES,\n type MarkerConfig,\n} from \"./markerDefinitions\";\n\n/**\n * Marker Utilities - Pure Functions\n * No side effects, stateless\n */\n\n/**\n * Escape special regex characters\n */\nexport function escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Create regex pattern from marker config\n */\nexport function createMarkerPattern(config: MarkerConfig): RegExp {\n const start = escapeRegex(config.start);\n const end = escapeRegex(config.end);\n return new RegExp(`${start}(.*?)${end}`, \"s\");\n}\n\n/**\n * Pattern definition for matching\n */\nexport type PatternDefinition = {\n type: ContentPartType;\n regex: RegExp;\n};\n\n/**\n * Generate patterns from markers\n */\nexport function generatePatterns(markers: MarkerConfig[]): PatternDefinition[] {\n return markers.map((marker) => ({\n type: marker.type,\n regex: createMarkerPattern(marker),\n }));\n}\n\n/**\n * Auto-generated patterns from marker configs\n */\nexport const CONTENT_PATTERNS: PatternDefinition[] = generatePatterns(MARKERS);\n\n/**\n * Filter markers by predicate\n */\nexport function filterMarkers(\n markers: MarkerConfig[],\n predicate: (marker: MarkerConfig) => boolean\n): MarkerConfig[] {\n return markers.filter(predicate);\n}\n\n/**\n * Get marker config by type\n */\nexport function getMarkerByType(\n markers: MarkerConfig[],\n type: ContentPartType\n): MarkerConfig | undefined {\n return markers.find((m) => m.type === type);\n}\n\n/**\n * Check if type is loading type\n */\nexport function isLoadingType(type: ContentPartType): boolean {\n return type.includes(\"-loading\");\n}\n\n/**\n * Check if type is general loading type\n * Uses the centralized list from markerDefinitions\n */\nexport function isGeneralLoadingType(type: ContentPartType): boolean {\n return GENERAL_LOADING_TYPES.includes(type as any);\n}\n\n/**\n * Get markers by category\n */\nexport function getMarkersByCategory(\n markers: MarkerConfig[],\n category: \"loading\" | \"content\"\n): MarkerConfig[] {\n if (category === \"loading\") {\n return filterMarkers(markers, (m) => isLoadingType(m.type));\n }\n return filterMarkers(markers, (m) => !isLoadingType(m.type));\n}\n\n/**\n * Get general loading markers\n */\nexport function getGeneralLoadingMarkers(\n markers: MarkerConfig[]\n): MarkerConfig[] {\n return filterMarkers(markers, (m) => isGeneralLoadingType(m.type));\n}\n\n/**\n * Get content markers (non-loading)\n */\nexport function getContentMarkers(markers: MarkerConfig[]): MarkerConfig[] {\n return filterMarkers(markers, (m) => !isLoadingType(m.type));\n}\n","/**\n * Marker Cleaner - Pure Operations\n * All functions are pure, stateless, and composable\n */\n\nimport type { MarkerConfig } from \"./markerDefinitions\";\nimport { createMarkerPattern } from \"./markerUtils\";\n\n/**\n * Remove markers from content using pattern\n * @param content - Content to clean\n * @param pattern - Regex pattern to match\n * @param preserveContent - Keep matched content (group 1) or remove entirely\n */\nfunction removeByPattern(\n content: string,\n pattern: RegExp,\n preserveContent: boolean\n): string {\n return content.replace(pattern, preserveContent ? \"$1\" : \"\");\n}\n\n/**\n * Remove markers from content\n * @param content - Content to clean\n * @param markers - Markers to remove\n * @param preserveContent - Keep content between markers or remove entirely\n */\nexport function removeMarkers(\n content: string,\n markers: MarkerConfig[],\n preserveContent: boolean = false\n): string {\n let cleaned = content;\n\n for (const marker of markers) {\n const pattern = createMarkerPattern(marker);\n cleaned = removeByPattern(cleaned, pattern, preserveContent);\n }\n\n return cleaned;\n}\n\n/**\n * Remove only loading markers (preserves content between them)\n */\nexport function removeLoadingMarkers(\n content: string,\n loadingMarkers: MarkerConfig[]\n): string {\n return removeMarkers(content, loadingMarkers, true);\n}\n\n/**\n * Remove content markers (removes everything)\n */\nexport function removeContentMarkers(\n content: string,\n contentMarkers: MarkerConfig[]\n): string {\n return removeMarkers(content, contentMarkers, false);\n}\n\n/**\n * Remove all markers with different strategies\n * @param content - Content to clean\n * @param loadingMarkers - Loading markers (preserve content)\n * @param contentMarkers - Content markers (remove everything)\n */\nexport function removeAllMarkers(\n content: string,\n loadingMarkers: MarkerConfig[],\n contentMarkers: MarkerConfig[]\n): string {\n // First remove loading markers (preserve content)\n let cleaned = removeLoadingMarkers(content, loadingMarkers);\n\n // Then remove content markers (remove everything)\n cleaned = removeContentMarkers(cleaned, contentMarkers);\n\n return cleaned;\n}\n","/**\n * Marker Cleaner Facade\n * Provides convenient API using pure functions from markerOperations\n */\n\nimport { MARKERS } from \"./markerDefinitions\";\nimport { getGeneralLoadingMarkers, getContentMarkers } from \"./markerUtils\";\nimport { removeLoadingMarkers, removeAllMarkers } from \"./markerOperations\";\n\n/**\n * Pre-computed marker sets for performance\n */\nconst GENERAL_LOADING_MARKERS = getGeneralLoadingMarkers(MARKERS);\nconst CONTENT_MARKERS = getContentMarkers(MARKERS);\n\n/**\n * Remove only loading markers (preserves content between them)\n * Used when processing complete loading blocks\n */\nexport function removeOnlyLoadingMarkers(content: string): string {\n return removeLoadingMarkers(content, GENERAL_LOADING_MARKERS);\n}\n\n/**\n * Remove complete markers (with both start and end)\n * Preserves incomplete loading markers (only start, no end)\n * Used for cleaning text before matches\n */\nexport function removeCompleteMarkers(content: string): string {\n return removeAllMarkers(content, GENERAL_LOADING_MARKERS, CONTENT_MARKERS);\n}\n","import type { ContentPartType } from \"../../types\";\nimport { CONTENT_PATTERNS } from \"../parsing\";\n\nexport type MatchCandidate = {\n type: ContentPartType;\n match: RegExpMatchArray | null;\n index: number;\n};\n\nexport type ValidMatch = MatchCandidate & { match: RegExpMatchArray };\n\n/**\n * Find all matches in content\n */\nexport function findMatches(content: string): ValidMatch[] {\n const matches: MatchCandidate[] = CONTENT_PATTERNS.map(({ type, regex }) => {\n const match = content.match(regex);\n return {\n type,\n match,\n index: match ? content.indexOf(match[0]) : Infinity,\n };\n });\n\n return matches.filter(\n (m): m is ValidMatch => m.match !== null && m.index !== Infinity\n );\n}\n","/**\n * Base Parser Utilities\n * Common logic for all YAML-like parsers\n */\n\n/**\n * Field definition for parsing\n */\nexport type FieldDef = {\n name: string;\n type?: \"string\" | \"number\";\n required?: boolean;\n defaultValue?: any; // Default value if extraction fails\n};\n\n/**\n * Create a regex pattern to extract a field value\n * Uses lookahead to match until next field or end\n * Handles multi-line values with indentation and zero-width spaces\n */\nfunction createFieldPattern(\n fieldName: string,\n allFieldNames: string[]\n): RegExp {\n // Create lookahead for all other fields\n const otherFields = allFieldNames\n .filter((f) => f !== fieldName)\n .map((f) => `${f}:`)\n .join(\"|\");\n\n // Pattern that:\n // 1. Matches fieldName:\n // 2. Captures value (including spaces, zero-width spaces, newlines with indentation)\n // 3. Stops at next field (at start of line or after spaces) or end of block\n\n // Match value until we see another field at any position or end of string\n const pattern = `${fieldName}:\\\\s*([\\\\s\\\\S]*?)(?=\\\\s*(?:${otherFields})|$)`;\n return new RegExp(pattern, \"m\");\n}\n\n/**\n * Extract field value from block using regex\n * Cleans zero-width spaces and trims whitespace\n */\nfunction extractField(\n block: string,\n fieldName: string,\n allFieldNames: string[]\n): string {\n const pattern = createFieldPattern(fieldName, allFieldNames);\n const match = block.match(pattern);\n\n if (!match || !match[1]) {\n return \"\";\n }\n\n let value = match[1];\n\n // Remove zero-width spaces (\\u200b)\n value = value.replace(/\\u200b/g, \"\");\n\n // For single-line fields, get only the first line\n const firstLine = value.split(\"\\n\")[0];\n\n return firstLine.trim();\n}\n\n/**\n * Parse YAML-like list format into array of objects\n *\n * @example\n * ```\n * - field1: value1\n * field2: value2\n * - field1: value3 field2: value4\n * ```\n */\nexport function parseYamlList<T>(\n payload: string,\n fields: FieldDef[],\n mapper: (extracted: Record<string, any>) => T\n): T[] {\n const fieldNames = fields.map((f) => f.name);\n\n const blocks = payload\n .split(\"- \")\n .map((block) => block.trim())\n .filter((block) => block);\n\n const results = blocks.map((block) => {\n const extracted: Record<string, any> = {};\n\n // Extract all fields\n for (const field of fields) {\n const value = extractField(block, field.name, fieldNames);\n\n // Type conversion with fallback to default\n if (field.type === \"number\") {\n const num = parseInt(value, 10);\n extracted[field.name] = Number.isFinite(num)\n ? num\n : field.defaultValue !== undefined\n ? field.defaultValue\n : undefined;\n } else {\n // Use extracted value, or default value, or empty string for required, or undefined\n extracted[field.name] =\n value ||\n (field.defaultValue !== undefined\n ? field.defaultValue\n : field.required\n ? \"\"\n : undefined);\n }\n }\n\n // Map to final type\n return mapper(extracted);\n });\n\n return results;\n}\n\n/**\n * Parse simple key-value format\n *\n * @example\n * ```\n * key1: value1\n * key2: value2\n * ```\n */\nexport function parseKeyValue(\n payload: string,\n fields: string[]\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const field of fields) {\n const pattern = createFieldPattern(field, fields);\n const match = payload.match(pattern);\n result[field] = match?.[1]?.trim() || \"\";\n }\n\n return result;\n}\n","import type { CardData } from \"../../types\";\nimport { parseYamlList, type FieldDef } from \"./baseParser\";\n\n/**\n * Parse card data from YAML-like format\n *\n * @template\n * - photo: https://example.com/image.jpg\n * header: Card Title\n * subheader: Card Subtitle\n */\nconst CARD_FIELDS: FieldDef[] = [\n {\n name: \"photo\",\n required: true,\n defaultValue: \"https://via.placeholder.com/300x200\",\n },\n { name: \"header\", required: true, defaultValue: \"Card Title\" },\n { name: \"subheader\", defaultValue: \"\" },\n];\n\nexport function parseCard(payload: string): CardData[] {\n return parseYamlList(payload, CARD_FIELDS, (data) => ({\n photo: data.photo || \"\",\n header: data.header || \"\",\n subheader: data.subheader || \"\",\n }));\n}\n","import type { ButtonData } from \"../../types\";\nimport { parseYamlList, type FieldDef } from \"./baseParser\";\n\n/**\n * Parse button data from YAML-like format\n *\n * @template\n * - type: action\n * label: Get More Info\n * id: 1\n * row: 1\n * color: blue\n */\nconst BUTTON_FIELDS: FieldDef[] = [\n { name: \"type\", required: true, defaultValue: \"action\" },\n { name: \"label\", required: true, defaultValue: \"Button\" },\n { name: \"url\", defaultValue: undefined },\n { name: \"id\", type: \"number\", defaultValue: undefined },\n { name: \"color\", defaultValue: \"primary\" },\n { name: \"row\", type: \"number\", defaultValue: 1 },\n];\n\nexport function parseButton(payload: string): ButtonData[] {\n const result = parseYamlList(payload, BUTTON_FIELDS, (data) => {\n const type: ButtonData[\"type\"] = data.type === \"link\" ? \"link\" : \"action\";\n\n return {\n type,\n label: data.label || \"\",\n url: data.url,\n id: data.id,\n color: data.color,\n row: data.row,\n };\n });\n\n return result;\n}\n","import type { AudioData } from \"../../types\";\nimport { parseYamlList, type FieldDef } from \"./baseParser\";\n\n/**\n * Parse audio data from YAML-like format\n *\n * @template\n * - label: Sample Audio 1\n * url: https://example.com/audio1.mp3\n * type: audio/mpeg\n */\nconst AUDIO_FIELDS: FieldDef[] = [\n { name: \"label\", required: true, defaultValue: \"Audio Track\" },\n { name: \"url\", required: true, defaultValue: \"\" },\n { name: \"type\", required: true, defaultValue: \"audio/mpeg\" },\n];\n\nexport function parseAudio(payload: string): AudioData[] {\n return parseYamlList(payload, AUDIO_FIELDS, (data) => ({\n label: data.label || \"\",\n url: data.url || \"\",\n type: data.type || \"\",\n }));\n}\n","import type { ContentPart, ContentPartType } from \"../../types\";\nimport {\n parseCard,\n parseButton,\n parseAudio,\n parseLocation,\n parseTracing,\n} from \"../parsers\";\n\n/**\n * Check if content type is loading type\n * Based on naming convention: all loading types end with \"-loading\"\n */\nfunction isLoadingType(type: ContentPartType): boolean {\n return type.includes(\"-loading\");\n}\n\n/**\n * Content Type Categories\n */\nconst SIMPLE_CONTENT_TYPES = [\"image\", \"video\", \"youtube\"] as const;\n\ntype SimpleContentType = (typeof SIMPLE_CONTENT_TYPES)[number];\n\n/**\n * Parser mapping for complex content types\n */\nconst PARSER_MAP: Record<string, (payload: string) => any> = {\n card: parseCard,\n location: parseLocation,\n buttons: parseButton,\n tracing: parseTracing,\n audio: parseAudio,\n};\n\n/**\n * Process match and return content part\n *\n * @param type - Content type to process\n * @param payload - Content payload\n * @returns ContentPart or null for loading types\n */\nexport function processMatch(\n type: ContentPartType,\n payload: string\n): ContentPart | null {\n // All loading types are handled separately (return null)\n if (isLoadingType(type)) {\n return null;\n }\n\n // Simple content types (URL strings)\n if (SIMPLE_CONTENT_TYPES.includes(type as SimpleContentType)) {\n return { type, content: payload } as ContentPart;\n }\n\n // Complex content types (use parser)\n const parser = PARSER_MAP[type];\n if (parser) {\n const content = parser(payload);\n return { type, content };\n }\n return null;\n}\n","import type { LocationData } from \"../../types\";\n\n/**\n * Parse location data from comma-separated coordinates\n *\n * @template\n * 35.6892, 51.3890\n *\n * @example\n * \"35.6892, 51.3890\" -> { latitude: 35.6892, longitude: 51.3890 }\n */\nexport function parseLocation(payload: string): LocationData {\n const [latitude, longitude] = payload.split(\",\").map((coord) => coord.trim());\n const parsedLatitude = parseFloat(latitude);\n const parsedLongitude = parseFloat(longitude);\n return {\n latitude: Number.isFinite(parsedLatitude) ? parsedLatitude : 0,\n longitude: Number.isFinite(parsedLongitude) ? parsedLongitude : 0,\n };\n}\n","import type { TracingData } from \"../../types\";\n\n/**\n * Parse tracing data from YAML-like format\n *\n * @template\n * visibility: all\n * content: {\"request_id\": \"req_123\", \"status\": \"success\"}\n */\nexport function parseTracing(payload: string): TracingData {\n // Extract visibility (single line)\n const visibilityMatch = payload.match(/visibility:\\s*(\\w+)/);\n const visibility =\n (visibilityMatch?.[1] as TracingData[\"visibility\"]) || \"all\";\n\n // Extract content (everything after \"content:\")\n const contentMatch = payload.match(/content:\\s*([\\s\\S]*)/);\n const content = contentMatch?.[1]?.trim() || payload;\n\n return {\n visibility,\n content,\n rawContent: payload,\n };\n}\n","import type { ContentPart, ContentPartType } from \"../../types\";\nimport { removeCompleteMarkers } from \"../parsing\";\nimport { GENERAL_LOADING_TYPES } from \"../parsing/markerDefinitions\";\nimport { findMatches } from \"./matchFinder\";\nimport { processMatch } from \"./matchProcessor\";\n\n/**\n * Check if type is a general loading type\n * Uses the centralized list from parsing/markerDefinitions\n */\nfunction isGeneralLoadingType(type: ContentPartType): boolean {\n return GENERAL_LOADING_TYPES.includes(type as any);\n}\n\n/**\n * Parse content recursively to extract all parts\n * Used when extracting content from inside loading markers\n */\nexport function parseContentRecursively(content: string): ContentPart[] {\n const parts: ContentPart[] = [];\n let remainingContent = content;\n let iteration = 0;\n const maxIterations = 100;\n\n while (remainingContent.length > 0 && iteration < maxIterations) {\n iteration++;\n const matches = findMatches(remainingContent);\n\n if (matches.length === 0) {\n const cleanText = removeCompleteMarkers(remainingContent).trim();\n if (cleanText) {\n parts.push({ type: \"text\", content: cleanText });\n }\n break;\n }\n\n const firstMatch = matches.reduce((prev, current) =>\n prev.index < current.index ? prev : current\n );\n\n const shouldSkip = isGeneralLoadingType(firstMatch.type);\n\n const textBefore = remainingContent.substring(0, firstMatch.index);\n const cleanTextBefore = removeCompleteMarkers(textBefore).trim();\n if (cleanTextBefore) {\n parts.push({ type: \"text\", content: cleanTextBefore });\n }\n\n if (!shouldSkip) {\n const matchPayload = (firstMatch.match[1] ?? \"\").trim();\n const part = processMatch(firstMatch.type, matchPayload);\n if (part) {\n parts.push(part);\n }\n }\n\n const matchEnd = firstMatch.index + firstMatch.match[0].length;\n remainingContent = remainingContent.substring(matchEnd);\n }\n\n return parts;\n}\n","import { computed, unref, type ComputedRef, type MaybeRef } from \"vue\";\nimport type { ContentPart } from \"../types\";\nimport { removeCompleteMarkers, removeOnlyLoadingMarkers } from \"./parsing\";\nimport { findMatches, processMatch, parseContentRecursively } from \"./core\";\n\n/**\n * Composable for parsing Orca content markers\n * Supports both reactive and non-reactive values for streaming compatibility\n */\nexport function useContentParser(\n description: MaybeRef<string>\n): ComputedRef<ContentPart[]> {\n return computed<ContentPart[]>(() => {\n const content = unref(description);\n return parseContent(content || \"\");\n });\n}\n\n/**\n * Parse content into parts\n * Extracted for testability\n */\nexport function parseContent(content: string): ContentPart[] {\n const parts: ContentPart[] = [];\n let remainingContent = content;\n let iteration = 0;\n const MAX_ITERATIONS = 100;\n\n while (remainingContent.length > 0 && iteration < MAX_ITERATIONS) {\n iteration++;\n\n const matches = findMatches(remainingContent);\n\n // No matches: add remaining text and exit\n if (matches.length === 0) {\n addCleanTextIfExists(parts, remainingContent);\n break;\n }\n\n // Get earliest match\n const firstMatch = matches.reduce((prev, current) =>\n prev.index < current.index ? prev : current\n );\n\n // Add text before match\n const textBefore = remainingContent.substring(0, firstMatch.index);\n addCleanTextIfExists(parts, textBefore);\n\n // Process the match\n processMatchAndAddParts(parts, firstMatch);\n\n // Move to next section\n const matchEnd = firstMatch.index + firstMatch.match[0].length;\n remainingContent = remainingContent.substring(matchEnd);\n }\n\n return parts;\n}\n\n/**\n * Add cleaned text to parts if it exists\n */\nfunction addCleanTextIfExists(parts: ContentPart[], text: string): void {\n const cleanText = removeCompleteMarkers(text).trim();\n if (cleanText) {\n parts.push({ type: \"text\", content: cleanText });\n }\n}\n\n/**\n * Process match and add resulting parts\n */\nfunction processMatchAndAddParts(\n parts: ContentPart[],\n match: { type: any; match: RegExpMatchArray; index: number }\n): void {\n const matchPayload = (match.match[1] ?? \"\").trim();\n const isLoadingType = match.type.includes(\"-loading\");\n\n // Empty loading marker - skip\n if (isLoadingType && !matchPayload) {\n return;\n }\n\n // Loading marker with content - parse recursively\n if (isLoadingType && matchPayload) {\n const cleanPayload = removeOnlyLoadingMarkers(matchPayload);\n if (cleanPayload.trim()) {\n const nestedParts = parseContentRecursively(cleanPayload);\n parts.push(...nestedParts);\n }\n return;\n }\n\n // Regular content type\n const part = processMatch(match.type, matchPayload);\n if (part) {\n parts.push(part);\n }\n}\n","import { computed, ref, unref, watch, type MaybeRef } from \"vue\";\n\n/**\n * Loading marker patterns for detection\n */\nconst LOADING_PATTERNS = {\n general: {\n start: \"[orca.loading.start]\",\n end: \"[orca.loading.end]\",\n },\n thinking: {\n start: \"[orca.loading.thinking.start]\",\n end: \"[orca.loading.thinking.end]\",\n },\n searching: {\n start: \"[orca.loading.searching.start]\",\n end: \"[orca.loading.searching.end]\",\n },\n coding: {\n start: \"[orca.loading.coding.start]\",\n end: \"[orca.loading.coding.end]\",\n },\n analyzing: {\n start: \"[orca.loading.analyzing.start]\",\n end: \"[orca.loading.analyzing.end]\",\n },\n generating: {\n start: \"[orca.loading.generating.start]\",\n end: \"[orca.loading.generating.end]\",\n },\n custom: {\n start: \"[orca.loading.custom.start]\",\n end: \"[orca.loading.custom.end]\",\n },\n image: {\n start: \"[orca.loading.image.start]\",\n end: \"[orca.loading.image.end]\",\n actual: /\\[orca\\.image\\.start\\](.*?)\\[orca\\.image\\.end\\]/s,\n },\n video: {\n start: \"[orca.loading.video.start]\",\n end: \"[orca.loading.video.end]\",\n actual: /\\[orca\\.video\\.start\\](.*?)\\[orca\\.video\\.end\\]/s,\n },\n youtube: {\n start: \"[orca.loading.youtube.start]\",\n end: \"[orca.loading.youtube.end]\",\n actual: /\\[orca\\.youtube\\.start\\](.*?)\\[orca\\.youtube\\.end\\]/s,\n },\n card: {\n start: \"[orca.loading.card.start]\",\n end: \"[orca.loading.card.end]\",\n actual: /\\[orca\\.list\\.card\\.start\\](.*?)\\[orca\\.list\\.card\\.end\\]/s,\n },\n map: {\n start: \"[orca.loading.map.start]\",\n end: \"[orca.loading.map.end]\",\n actual: /\\[orca\\.location\\.start\\](.*?)\\[orca\\.location\\.end\\]/s,\n },\n} as const;\n\n/**\n * Loading messages for different types\n */\nconst LOADING_MESSAGES: Record<string, string> = {\n \"general-loading\": \"⏳ Loading...\",\n \"thinking-loading\": \"🤔 Thinking...\",\n \"searching-loading\": \"🔍 Searching...\",\n \"coding-loading\": \"💻 Coding...\",\n \"analyzing-loading\": \"📊 Analyzing...\",\n \"generating-loading\": \"✨ Generating...\",\n \"custom-loading\": \"⏳ Processing...\",\n \"image-loading\": \"🖼️ Loading image...\",\n \"video-loading\": \"🎥 Loading video...\",\n \"youtube-loading\": \"📺 Loading YouTube video...\",\n \"card-loading\": \"🃏 Loading cards...\",\n \"map-loading\": \"🗺️ Loading map...\",\n} as const;\n\n/**\n * Check if a loading state is active (start exists, end doesn't exist)\n */\nfunction isActiveLoading(\n content: string,\n startPattern: string,\n endPattern: string\n): boolean {\n const hasStart = content.includes(startPattern);\n const hasEnd = content.includes(endPattern);\n return hasStart && !hasEnd;\n}\n\n/**\n * Check if a content-specific loading state is active\n */\nfunction isActiveContentLoading(\n content: string,\n startPattern: string,\n endPattern: string,\n actualPattern?: RegExp\n): boolean {\n const hasStart = content.includes(startPattern);\n const hasEnd = content.includes(endPattern);\n const hasActual = actualPattern ? actualPattern.test(content) : false;\n return hasStart && !hasEnd && !hasActual;\n}\n\n/**\n * Composable for managing loading states\n * Optimized with computed properties and memoization\n */\nexport function useLoadingStates(description: MaybeRef<string>) {\n const isLoading = ref(false);\n const isImageLoading = ref(false);\n const isVideoLoading = ref(false);\n const isCardLoading = ref(false);\n const isLocationLoading = ref(false);\n\n // Memoized computed for description value\n const descriptionValue = computed(() => {\n return unref(description);\n });\n\n // Watch for general and semantic loading states\n watch(\n descriptionValue,\n (val) => {\n if (!val) {\n isLoading.value = false;\n return;\n }\n\n // Check all semantic loading types\n const hasActiveLoading =\n isActiveLoading(\n val,\n LOADING_PATTERNS.general.start,\n LOADING_PATTERNS.general.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.thinking.start,\n LOADING_PATTERNS.thinking.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.searching.start,\n LOADING_PATTERNS.searching.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.coding.start,\n LOADING_PATTERNS.coding.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.analyzing.start,\n LOADING_PATTERNS.analyzing.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.generating.start,\n LOADING_PATTERNS.generating.end\n ) ||\n isActiveLoading(\n val,\n LOADING_PATTERNS.custom.start,\n LOADING_PATTERNS.custom.end\n );\n\n isLoading.value = hasActiveLoading;\n },\n { immediate: true }\n );\n\n // Watch for image loading\n watch(\n descriptionValue,\n (val) => {\n isImageLoading.value = isActiveContentLoading(\n val,\n LOADING_PATTERNS.image.start,\n LOADING_PATTERNS.image.end,\n LOADING_PATTERNS.image.actual\n );\n },\n { immediate: true }\n );\n\n // Watch for video loading (includes YouTube)\n watch(\n descriptionValue,\n (val) => {\n const videoLoading = isActiveContentLoading(\n val,\n LOADING_PATTERNS.video.start,\n LOADING_PATTERNS.video.end,\n LOADING_PATTERNS.video.actual\n );\n const youtubeLoading = isActiveContentLoading(\n val,\n LOADING_PATTERNS.youtube.start,\n LOADING_PATTERNS.youtube.end,\n LOADING_PATTERNS.youtube.actual\n );\n isVideoLoading.value = videoLoading || youtubeLoading;\n },\n { immediate: true }\n );\n\n // Watch for card loading\n watch(\n descriptionValue,\n (val) => {\n isCardLoading.value = isActiveContentLoading(\n val,\n LOADING_PATTERNS.card.start,\n LOADING_PATTERNS.card.end,\n LOADING_PATTERNS.card.actual\n );\n },\n { immediate: true }\n );\n\n // Watch for location/map loading\n watch(\n descriptionValue,\n (val) => {\n isLocationLoading.value = isActiveContentLoading(\n val,\n LOADING_PATTERNS.map.start,\n LOADING_PATTERNS.map.end,\n LOADING_PATTERNS.map.actual\n );\n },\n { immediate: true }\n );\n\n /**\n * Get loading message for a specific type\n */\n const getLoadingMessage = (loadingType: string): string => {\n return LOADING_MESSAGES[loadingType] || LOADING_MESSAGES[\"general-loading\"];\n };\n\n return {\n isLoading,\n isImageLoading,\n isVideoLoading,\n isCardLoading,\n isLocationLoading,\n getLoadingMessage,\n };\n}\n","import { nextTick, onMounted, type Ref } from \"vue\";\n\n/**\n * SVG icons for code buttons\n */\nconst COPY_ICON = `\n <div class=\"d-flex align-center\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <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\"/>\n <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\"/>\n </svg>\n <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>\n </div>\n`;\n\nconst COPIED_ICON = `\n <div class=\"d-flex align-center\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <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\"/>\n </svg>\n <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>\n </div>\n`;\n\nconst COLLAPSE_ICON = `\n <div class=\"d-flex align-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <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\"/>\n <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\"/>\n </svg>\n <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>\n </div>\n`;\n\nconst EXPAND_ICON = `\n <div class=\"d-flex align-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <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\"/>\n <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\"/>\n </svg>\n <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>\n </div>\n`;\n\n/**\n * Copy code to clipboard with visual feedback\n */\nasync function copyToClipboard(\n text: string,\n button: HTMLElement\n): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n button.innerHTML = COPIED_ICON;\n setTimeout(() => {\n button.innerHTML = COPY_ICON;\n }, 2000);\n } catch (error) {\n console.error(\"Failed to copy code:\", error);\n }\n}\n\n/**\n * Toggle code block collapse/expand\n */\nfunction toggleCodeBlock(wrapper: HTMLElement, button: HTMLElement): void {\n const isCollapsed = wrapper.classList.contains(\"collapsed\");\n if (isCollapsed) {\n wrapper.classList.remove(\"collapsed\");\n wrapper.style.maxHeight = \"\";\n wrapper.style.overflow = \"\";\n button.innerHTML = COLLAPSE_ICON;\n } else {\n wrapper.classList.add(\"collapsed\");\n const height = wrapper.scrollHeight;\n wrapper.style.maxHeight = `${height}px`;\n // Force reflow\n wrapper.offsetHeight;\n wrapper.style.maxHeight = \"0px\";\n wrapper.style.overflow = \"hidden\";\n button.innerHTML = EXPAND_ICON;\n }\n}\n\n/**\n * Create and attach code buttons to a code block\n */\nfunction attachCodeButtons(block: Element): void {\n if (block.closest(\".code-container\")) return;\n\n const codeContainer = document.createElement(\"div\");\n codeContainer.className = \"code-container\";\n\n const codeWrapper = document.createElement(\"div\");\n codeWrapper.className = \"code-wrapper\";\n codeWrapper.style.transition = \"max-height 0.3s ease, opacity 0.3s ease\";\n codeWrapper.style.overflow = \"hidden\";\n codeWrapper.appendChild(block.cloneNode(true));\n\n const buttonsContainer = document.createElement(\"div\");\n buttonsContainer.className = \"buttons-container\";\n\n // Copy button\n const copyButton = document.createElement(\"button\");\n copyButton.innerHTML = COPY_ICON;\n copyButton.className = \"copy-btn\";\n copyButton.onclick = () => {\n const code = block.querySelector(\"code\")?.innerText || \"\";\n copyToClipboard(code, copyButton);\n };\n\n // Collapse button\n const collapseButton = document.createElement(\"button\");\n collapseButton.innerHTML = COLLAPSE_ICON;\n collapseButton.className = \"collapse-btn\";\n collapseButton.onclick = () => {\n toggleCodeBlock(codeWrapper, collapseButton);\n };\n\n buttonsContainer.appendChild(collapseButton);\n buttonsContainer.appendChild(copyButton);\n codeContainer.appendChild(buttonsContainer);\n codeContainer.appendChild(codeWrapper);\n block.replaceWith(codeContainer);\n}\n\n/**\n * Composable for managing code block copy/collapse buttons\n * Optimized with debouncing and efficient DOM manipulation\n */\nexport function useCodeButtons(\n containerRef: Ref<HTMLElement | null>,\n shouldAddButtons: () => boolean\n) {\n /**\n * Add copy and collapse buttons to all code blocks\n */\n const addCodeButtons = () => {\n nextTick(() => {\n if (!containerRef.value || !shouldAddButtons()) return;\n\n const codeBlocks = containerRef.value.querySelectorAll(\"pre\");\n codeBlocks.forEach((block) => {\n attachCodeButtons(block);\n });\n });\n };\n\n // Initialize on mount\n onMounted(() => {\n addCodeButtons();\n });\n\n return {\n addCodeButtons,\n };\n}\n","/**\n * Loading content part types that should be filtered out\n * These are handled separately in the loading indicators section\n */\nexport const LOADING_CONTENT_TYPES = [\n \"general-loading\",\n \"thinking-loading\",\n \"searching-loading\",\n \"coding-loading\",\n \"analyzing-loading\",\n \"generating-loading\",\n \"custom-loading\",\n \"image-loading\",\n \"video-loading\",\n \"youtube-loading\",\n \"card-loading\",\n \"map-loading\",\n] as const;\n\n/**\n * Type guard to check if a content part is a loading type\n */\nexport function isLoadingType(\n type: string\n): type is (typeof LOADING_CONTENT_TYPES)[number] {\n return LOADING_CONTENT_TYPES.includes(type as any);\n}\n","import MarkdownIt from \"markdown-it\";\nimport hljs from \"highlight.js\";\nimport markdownItLinkAttributes from \"markdown-it-link-attributes\";\nimport markdownItKatex from \"markdown-it-katex\";\nimport \"highlight.js/styles/stackoverflow-light.css\";\nimport \"katex/dist/katex.min.css\";\n\n// Simple HTML escape function\nconst escapeCodeHtml = (value: string): string => {\n const map: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#039;\",\n };\n return value.replace(/[&<>\"']/g, (m) => map[m]);\n};\n\n// Initialize markdown parser once\nconst md = new MarkdownIt({\n html: false,\n linkify: true,\n typographer: true,\n highlight: (str, lang) => {\n if (lang && hljs.getLanguage(lang)) {\n try {\n return `<pre><code class=\"hljs\">${\n hljs.highlight(str, { language: lang }).value\n }</code></pre>`;\n } catch {\n // Fallback to escaped HTML\n }\n }\n return `<pre><code class=\"hljs\">${escapeCodeHtml(str)}</code></pre>`;\n },\n})\n .use(markdownItKatex)\n .use(markdownItLinkAttributes, {\n pattern: /^https?:\\/\\//,\n attrs: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n });\n\n/**\n * Composable for rendering markdown with KaTeX support\n */\nexport function useMarkdown() {\n /**\n * Render markdown text to HTML\n * @param text - Markdown text to render\n * @returns Rendered HTML\n */\n const render = (text: string): string => {\n const cleanText = text.replace(/\\[orca\\..*?\\]/g, \"\").trim();\n return cleanText ? md.render(cleanText) : \"\";\n };\n\n return { render };\n}\n","<template>\n <div class=\"image-container tw-my-4\">\n <div class=\"image-wrapper\">\n <img\n :src=\"url\"\n alt=\"Generated image\"\n class=\"orca-image\"\n loading=\"lazy\"\n @click=\"openModal\"\n />\n <div class=\"image-overlay\">\n <div class=\"zoom-icon\">\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.35-4.35\"></path>\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\"></line>\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"></line>\n </svg>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * OrcaImage - Renders image content\n * Displays images with modal zoom functionality and modern UI\n */\nconst props = defineProps<{\n url: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-modal\", url: string): void;\n}>();\n\nconst openModal = () => {\n emit(\"open-modal\", props.url);\n};\n</script>\n\n<style scoped>\n.image-container {\n display: inline-block;\n}\n\n.image-wrapper {\n position: relative;\n display: inline-block;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n cursor: pointer;\n}\n\n.image-wrapper:hover {\n transform: translateY(-4px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n}\n\n.orca-image {\n width: 300px;\n height: 300px;\n object-fit: cover;\n display: block;\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.image-wrapper:hover .orca-image {\n transform: scale(1.05);\n}\n\n.image-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.3s ease;\n pointer-events: none;\n}\n\n.image-wrapper:hover .image-overlay {\n background: rgba(0, 0, 0, 0.3);\n}\n\n.zoom-icon {\n color: white;\n opacity: 0;\n transform: scale(0.8);\n transition: all 0.3s ease;\n}\n\n.image-wrapper:hover .zoom-icon {\n opacity: 1;\n transform: scale(1);\n}\n\n@media (min-width: 1024px) {\n .orca-image {\n width: 303px;\n height: 303px;\n }\n}\n</style>\n","<template>\n <div class=\"orca-video-container\">\n <div class=\"video-wrapper\">\n <video-player\n :options=\"{\n ...videoOptions,\n sources: [\n {\n type: 'video/mp4',\n src: url,\n },\n ],\n }\"\n class=\"video-player-custom\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from \"vue\";\nimport { VideoPlayer } from \"@videojs-player/vue\";\nimport \"video.js/dist/video-js.css\";\nimport type { VideoPlayerOptions } from \"../../types\";\n\n/**\n * OrcaVideo - Renders video content using Video.js\n * Provides professional video playback with controls\n */\nconst props = defineProps<{\n url: string;\n}>();\n\nconst videoOptions = ref<VideoPlayerOptions>({\n autoplay: false,\n controls: true,\n responsive: true,\n fluid: true,\n sources: [\n {\n type: \"video/mp4\",\n src: \"\",\n },\n ],\n});\n</script>\n\n<style scoped>\n.orca-video-container {\n margin: 24px 0;\n}\n\n.video-wrapper {\n width: 100%;\n max-width: 500px;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n background: #000;\n}\n\n.video-wrapper:hover {\n transform: translateY(-4px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.15),\n 0 10px 10px -5px rgba(0, 0, 0, 0.06);\n}\n\n.video-player-custom {\n width: 100%;\n max-width: 100%;\n border-radius: 16px;\n overflow: hidden;\n}\n</style>\n","<template>\n <div class=\"orca-youtube-container\">\n <div class=\"youtube-wrapper\">\n <iframe\n width=\"100%\"\n height=\"100%\"\n :src=\"embedUrl\"\n frameborder=\"0\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowfullscreen\n class=\"youtube-iframe\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { getYouTubeId } from \"../../utils/helpers\";\n\n/**\n * OrcaYouTube - Renders YouTube video embed\n * Converts YouTube URLs to embed format and displays in iframe\n */\nconst props = defineProps<{\n url: string;\n}>();\n\nconst embedUrl = computed(() => {\n const videoId = getYouTubeId(props.url);\n return `https://www.youtube.com/embed/${videoId}`;\n});\n</script>\n\n<style scoped>\n.orca-youtube-container {\n margin: 24px 0;\n}\n\n.youtube-wrapper {\n width: 100%;\n max-width: 500px;\n height: 300px;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n background: #000;\n}\n\n.youtube-wrapper:hover {\n transform: translateY(-4px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.15),\n 0 10px 10px -5px rgba(0, 0, 0, 0.06);\n}\n\n.youtube-iframe {\n border-radius: 16px;\n display: block;\n}\n\n@media (min-width: 1024px) {\n .youtube-wrapper {\n height: 350px;\n }\n}\n</style>\n","<template>\n <div class=\"orca-audio-container\">\n <div class=\"audio-list\">\n <div\n v-for=\"(audio, audioIndex) in audioItems\"\n :key=\"audioIndex\"\n class=\"audio-item\"\n >\n <div class=\"audio-icon-wrapper\">\n <svg\n class=\"audio-icon\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n 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\"\n />\n </svg>\n </div>\n <div class=\"audio-content\">\n <p class=\"audio-label\">{{ audio.label }}</p>\n <audio controls class=\"audio-player\" :type=\"audio.type\">\n <source :src=\"audio.url\" :type=\"audio.type\" />\n Your browser does not support the audio element.\n </audio>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { AudioData } from \"../../types\";\n\n/**\n * OrcaAudio - Renders audio player content\n * Displays multiple audio tracks with modern UI design\n */\ndefineProps<{\n audioItems: AudioData[];\n}>();\n</script>\n\n<style scoped>\n.orca-audio-container {\n margin: 24px 0;\n}\n\n.audio-list {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.audio-item {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n padding: 16px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-radius: 12px;\n border: 1px solid rgba(0, 0, 0, 0.06);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.audio-item:hover {\n background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n border-color: rgba(0, 0, 0, 0.1);\n}\n\n.audio-icon-wrapper {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n border-radius: 12px;\n box-shadow: 0 4px 6px rgba(59, 130, 246, 0.3);\n}\n\n.audio-icon {\n width: 24px;\n height: 24px;\n color: white;\n}\n\n.audio-content {\n flex: 1;\n min-width: 0;\n}\n\n.audio-label {\n font-size: 14px;\n font-weight: 600;\n color: #1f2937;\n margin-bottom: 12px;\n line-height: 1.4;\n}\n\n.audio-player {\n width: 100%;\n height: 40px;\n border-radius: 8px;\n outline: none;\n}\n\n.audio-player::-webkit-media-controls-panel {\n background-color: white;\n border-radius: 8px;\n}\n\n.audio-player::-webkit-media-controls-play-button {\n background-color: #3b82f6;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"orca-location-container\">\n <div class=\"map-wrapper\">\n <div\n :ref=\"(el) => onMapContainerReady(el)\"\n class=\"map-container\"\n :key=\"`map-${latitude}-${longitude}`\"\n />\n </div>\n <div class=\"location-info\">\n <div class=\"location-icon\">\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\" />\n <circle cx=\"12\" cy=\"10\" r=\"3\" />\n </svg>\n </div>\n <span class=\"location-text\">\n {{ latitude.toFixed(6) }}, {{ longitude.toFixed(6) }}\n </span>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, onUnmounted, ref, type ComponentPublicInstance } from \"vue\";\nimport mapboxgl from \"mapbox-gl\";\nimport \"mapbox-gl/dist/mapbox-gl.css\";\n\n/**\n * OrcaLocation - Renders map/location content using Mapbox GL JS\n * Displays interactive map with marker and navigation controls\n */\nconst props = defineProps<{\n latitude: number;\n longitude: number;\n mapboxToken?: string;\n}>();\n\nconst mapInstance = ref<mapboxgl.Map | null>(null);\nconst mapLoading = ref(false);\n\nconst onMapContainerReady = (el: Element | ComponentPublicInstance | null) => {\n const htmlEl = el && \"tagName\" in el ? (el as HTMLElement) : null;\n if (!htmlEl) return;\n if (!el) return;\n\n mapLoading.value = true;\n\n nextTick(() => {\n try {\n // Mapbox token - can be passed as prop or from env\n mapboxgl.accessToken =\n props.mapboxToken ||\n \"pk.eyJ1IjoicG91cnlhYnpwIiwiYSI6ImNsZ3Vuanl4YzF2NXkzZW1tcnR0MTlxNXEifQ.I3RdtfiL0ObnXbWVKxW1gQ\";\n\n // Remove existing map if any\n if (mapInstance.value) {\n mapInstance.value.remove();\n mapInstance.value = null;\n }\n\n const containerId = `map-${props.latitude}-${props.longitude}`;\n htmlEl.id = containerId;\n\n const newMap = new mapboxgl.Map({\n container: htmlEl,\n style: \"mapbox://styles/mapbox/streets-v11\",\n center: [props.longitude, props.latitude],\n zoom: 12,\n attributionControl: false,\n });\n\n mapInstance.value = newMap;\n\n newMap.on(\"load\", () => {\n new mapboxgl.Marker({\n color: \"#0D5FD6\",\n })\n .setLngLat([props.longitude, props.latitude])\n .addTo(newMap);\n\n newMap.addControl(new mapboxgl.NavigationControl());\n\n setTimeout(() => {\n newMap.resize();\n }, 100);\n\n mapLoading.value = false;\n });\n\n newMap.on(\"error\", (e) => {\n console.error(\"Mapbox error:\", e);\n mapLoading.value = false;\n });\n\n newMap.on(\"render\", () => {\n newMap.resize();\n });\n } catch (error) {\n console.error(\"Error initializing map:\", error);\n mapLoading.value = false;\n }\n });\n};\n\nonUnmounted(() => {\n if (mapInstance.value) {\n mapInstance.value.remove();\n mapInstance.value = null;\n }\n});\n</script>\n\n<style scoped>\n.orca-location-container {\n margin: 24px 0;\n}\n\n.map-wrapper {\n width: 100%;\n max-width: 500px;\n height: 300px;\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n border: 1px solid rgba(0, 0, 0, 0.08);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n background: #f5f5f5;\n}\n\n.map-wrapper:hover {\n transform: translateY(-4px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.15),\n 0 10px 10px -5px rgba(0, 0, 0, 0.06);\n border-color: rgba(0, 0, 0, 0.12);\n}\n\n.map-container {\n width: 100%;\n height: 100%;\n border-radius: 16px;\n}\n\n.location-info {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n padding: 8px 12px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-radius: 8px;\n width: fit-content;\n border: 1px solid rgba(0, 0, 0, 0.06);\n}\n\n.location-icon {\n width: 16px;\n height: 16px;\n color: #3b82f6;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.location-text {\n font-size: 13px;\n font-weight: 500;\n color: #4b5563;\n font-family: \"Monaco\", \"Menlo\", \"Ubuntu Mono\", monospace;\n}\n</style>\n","<template>\n <div class=\"orca-card-container\">\n <VCard v-for=\"(card, i) in cards\" :key=\"i\" class=\"orca-card\" elevation=\"2\">\n <div v-if=\"card.photo\" class=\"card-image-wrapper\">\n <VImg :src=\"card.photo\" height=\"223\" cover class=\"card-image\" />\n </div>\n <VCardItem class=\"card-content\">\n <VCardTitle v-if=\"card.header\" class=\"card-header\">\n {{ card.header }}\n </VCardTitle>\n <span v-if=\"card.subheader\" class=\"card-subheader\">{{\n card.subheader\n }}</span>\n <p v-if=\"card.text\" class=\"card-text\">\n {{ card.text }}\n </p>\n </VCardItem>\n </VCard>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { VCard, VCardItem, VCardTitle, VImg } from \"vuetify/components\";\nimport type { CardData } from \"../../types\";\n\n/**\n * OrcaCardList - Renders card list content\n * Displays multiple cards in a responsive grid layout with modern UI\n */\ndefineProps<{\n cards: CardData[];\n}>();\n</script>\n\n<style scoped>\n.orca-card-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 20px;\n margin: 24px 0;\n}\n\n@media (min-width: 1024px) {\n .orca-card-container {\n grid-template-columns: repeat(auto-fill, minmax(311px, 1fr));\n }\n}\n\n.orca-card {\n width: 100%;\n border-radius: 16px;\n overflow: hidden;\n background: white;\n border: 1px solid rgba(0, 0, 0, 0.08);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n cursor: pointer;\n}\n\n.orca-card:hover {\n transform: translateY(-6px);\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),\n 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n border-color: rgba(0, 0, 0, 0.12);\n}\n\n.card-image-wrapper {\n overflow: hidden;\n background: #f5f5f5;\n}\n\n.card-image {\n transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 16px;\n border-radius: 8px;\n}\n\n.orca-card:hover .card-image {\n transform: scale(1.05);\n}\n\n.card-content {\n padding: 16px;\n}\n\n.card-header {\n font-weight: 600;\n font-size: 16px;\n color: #1f2937;\n margin-bottom: 4px;\n line-height: 1.4;\n}\n\n.card-subheader {\n display: block;\n color: #6b7280;\n font-size: 14px;\n margin-bottom: 8px;\n line-height: 1.5;\n}\n\n.card-text {\n color: #4b5563;\n font-size: 14px;\n margin-top: 8px;\n line-height: 1.6;\n}\n</style>\n","<template>\n <div class=\"orca-buttons-container tw-my-4\">\n <div\n v-for=\"(row, rowIndex) in groupedButtons\"\n :key=\"rowIndex\"\n class=\"button-row\"\n >\n <VBtn\n :disabled=\"disabled\"\n v-for=\"(button, index) in row\"\n :key=\"index\"\n :class=\"['orca-button', 'custom-outlined-button']\"\n :style=\"getOutlinedButtonStyle(button.color)\"\n variant=\"text\"\n rounded=\"xl\"\n :target=\"button.type === 'link' ? '_blank' : undefined\"\n :href=\"button.type === 'link' ? button.url : undefined\"\n @click=\"handleButtonClick(button)\"\n >\n <template #append v-if=\"button.type === 'link'\">\n <VIcon\n icon=\"tabler-external-link\"\n :style=\"getAppendIconStyle(button.color)\"\n size=\"small\"\n />\n </template>\n <span :style=\"getOutlinedButtonTextStyle(button.color)\">{{\n button.label\n }}</span>\n </VBtn>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { VBtn, VIcon } from \"vuetify/components\";\nimport type { ButtonData } from \"../../types\";\nimport {\n getGroupedButtons,\n getOutlinedButtonStyle,\n getOutlinedButtonTextStyle,\n getAppendIconStyle,\n} from \"../../utils/helpers\";\n\n/**\n * OrcaButtons - Renders interactive buttons\n * Supports both action buttons (emit events) and link buttons (open URLs)\n */\nconst props = defineProps<{\n buttons: ButtonData[];\n disabled?: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"button-click\", button: ButtonData): void;\n}>();\n\nconst groupedButtons = computed(() => getGroupedButtons(props.buttons));\n\nconst handleButtonClick = (button: ButtonData) => {\n if (button.type === \"action\" && !props.disabled) {\n emit(\"button-click\", button);\n }\n};\n</script>\n\n<style scoped>\n.orca-buttons-container {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.button-row {\n display: flex;\n gap: 10px;\n flex-wrap: wrap;\n width: fit-content;\n}\n\n.orca-button {\n position: relative;\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-weight: 500;\n letter-spacing: 0.01em;\n min-height: 40px;\n padding: 0 20px;\n}\n\n.orca-button:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n.orca-button:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.orca-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n@media (max-width: 640px) {\n .button-row {\n flex-direction: column;\n width: 100%;\n }\n\n .orca-button {\n width: 100%;\n justify-content: center;\n }\n}\n</style>\n","<template>\n <div v-if=\"shouldShow\" class=\"orca-trace-container\">\n <VCard class=\"trace-card\" elevation=\"2\">\n <!-- Header -->\n <div class=\"trace-header\">\n <div class=\"trace-header-content\">\n <div class=\"trace-icon\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path\n d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"\n />\n </svg>\n </div>\n <strong class=\"trace-title\">Trace Log</strong>\n </div>\n <VBtn\n size=\"small\"\n variant=\"tonal\"\n color=\"primary\"\n class=\"trace-toggle-btn\"\n @click=\"toggleTrace\"\n >\n {{ isVisible ? \"Hide\" : \"Show\" }}\n </VBtn>\n </div>\n\n <!-- Body -->\n <VExpandTransition>\n <div v-if=\"isVisible\" class=\"trace-content\">\n <pre class=\"trace-pre\">{{ tracingContent }}</pre>\n </div>\n </VExpandTransition>\n </VCard>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from \"vue\";\nimport { VBtn, VCard, VExpandTransition } from \"vuetify/components\";\nimport type { TracingData } from \"../../types\";\n\n/**\n * OrcaTracing - Renders tracing/debug log content\n * Displays trace logs with expand/collapse functionality\n */\nconst props = defineProps<{\n tracingData: TracingData | TracingData[];\n visibility?: \"all\" | \"admin\";\n isAdmin?: boolean;\n}>();\n\nconst traceVisible = ref(false);\n\nconst isVisible = computed(() => traceVisible.value);\n\nconst shouldShow = computed(() => {\n if (Array.isArray(props.tracingData)) {\n return props.tracingData.some(\n (item) =>\n item.visibility === \"all\" ||\n (item.visibility === \"admin\" && props.isAdmin)\n );\n }\n\n return (\n props.tracingData.visibility === \"all\" ||\n (props.tracingData.visibility === \"admin\" && props.isAdmin)\n );\n});\n\nconst tracingContent = computed(() => {\n if (Array.isArray(props.tracingData)) {\n return props.tracingData\n .map((item) => item.content || item.rawContent)\n .join(\"\\n\\n\");\n }\n\n return props.tracingData.content || props.tracingData.rawContent || \"\";\n});\n\nconst toggleTrace = () => {\n traceVisible.value = !traceVisible.value;\n};\n</script>\n\n<style scoped>\n.orca-trace-container {\n margin: 24px 0;\n}\n\n.trace-card {\n border-radius: 12px;\n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, 0.08);\n max-width: 100%;\n}\n\n@media (min-width: 768px) {\n .trace-card {\n max-width: 600px;\n }\n}\n\n.trace-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n}\n\n.trace-header-content {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.trace-icon {\n width: 24px;\n height: 24px;\n color: #3b82f6;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.trace-title {\n font-size: 13px;\n font-weight: 600;\n color: #1f2937;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.trace-toggle-btn {\n font-weight: 500;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.trace-content {\n padding: 16px;\n background: #fafafa;\n}\n\n.trace-pre {\n white-space: pre-wrap;\n font-family: \"Monaco\", \"Menlo\", \"Ubuntu Mono\", \"Consolas\", \"source-code-pro\",\n monospace;\n font-size: 12px;\n line-height: 1.6;\n color: #374151;\n margin: 0;\n padding: 12px;\n background: white;\n border-radius: 8px;\n border: 1px solid rgba(0, 0, 0, 0.06);\n overflow-x: auto;\n}\n</style>\n","<template>\n <div>\n <!-- Text Content -->\n <div\n v-if=\"element.type === 'text'\"\n class=\"text-content\"\n v-html=\"renderText(element.content)\"\n />\n\n <!-- Image -->\n <OrcaImage\n v-else-if=\"element.type === 'image'\"\n :url=\"element.content\"\n @open-modal=\"handleImageModal\"\n />\n\n <!-- Video -->\n <OrcaVideo v-else-if=\"element.type === 'video'\" :url=\"element.content\" />\n\n <!-- YouTube -->\n <OrcaYouTube\n v-else-if=\"element.type === 'youtube'\"\n :url=\"element.content\"\n />\n\n <!-- Audio -->\n <OrcaAudio\n v-else-if=\"element.type === 'audio'\"\n :audio-items=\"element.content\"\n />\n\n <!-- Location -->\n <OrcaLocation\n v-else-if=\"element.type === 'location'\"\n :latitude=\"element.content.latitude\"\n :longitude=\"element.content.longitude\"\n :mapbox-token=\"mapboxToken\"\n />\n\n <!-- Card List -->\n <OrcaCardList\n v-else-if=\"element.type === 'card'\"\n :cards=\"element.content\"\n />\n\n <!-- Buttons -->\n <OrcaButtons\n v-else-if=\"element.type === 'buttons'\"\n :buttons=\"element.content\"\n :disabled=\"disabledButton\"\n @button-click=\"handleButtonClick\"\n />\n\n <!-- Tracing -->\n <OrcaTracing\n v-else-if=\"element.type === 'tracing'\"\n :tracing-data=\"element.content\"\n :visibility=\"visibility\"\n :is-admin=\"isAdmin\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useMarkdown } from \"../composables/useMarkdown\";\nimport OrcaImage from \"./renderers/OrcaImage.vue\";\nimport OrcaVideo from \"./renderers/OrcaVideo.vue\";\nimport OrcaYouTube from \"./renderers/OrcaYouTube.vue\";\nimport OrcaAudio from \"./renderers/OrcaAudio.vue\";\nimport OrcaLocation from \"./renderers/OrcaLocation.vue\";\nimport OrcaCardList from \"./renderers/OrcaCardList.vue\";\nimport OrcaButtons from \"./renderers/OrcaButtons.vue\";\nimport OrcaTracing from \"./renderers/OrcaTracing.vue\";\nimport type { ContentPart, ButtonData } from \"../types\";\n\n/**\n * ContentElement - Router component for different content types\n * Automatically renders the appropriate component based on element type\n */\nconst props = defineProps<{\n element: ContentPart;\n disabledButton?: boolean;\n visibility?: \"all\" | \"admin\";\n isAdmin?: boolean;\n mapboxToken?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"image-modal\", url: string): void;\n (e: \"button-click\", button: ButtonData): void;\n}>();\n\nconst { render: renderText } = useMarkdown();\n\nconst handleImageModal = (url: string) => {\n emit(\"image-modal\", url);\n};\n\nconst handleButtonClick = (button: ButtonData) => {\n emit(\"button-click\", button);\n};\n</script>\n","<template>\n <Transition name=\"fade\" mode=\"out-in\">\n <div v-if=\"isLoading\" class=\"general-loading-container\">\n <div class=\"loading-content\">\n <VProgressCircular\n indeterminate\n :size=\"24\"\n :width=\"3\"\n color=\"primary\"\n class=\"loading-spinner\"\n />\n <span class=\"loading-text\">\n {{ message }}\n </span>\n </div>\n </div>\n </Transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { VProgressCircular } from \"vuetify/components\";\n\n/**\n * GeneralLoading - Displays general loading indicator\n * Positioned inline in the chat flow\n */\ndefineProps<{\n isLoading: boolean;\n message: string;\n}>();\n</script>\n\n<style scoped>\n.general-loading-container {\n padding: 14px 20px;\n margin: 24px 0;\n background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);\n border-radius: 12px;\n display: inline-flex;\n align-items: center;\n border: 1px solid rgba(0, 0, 0, 0.08);\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n pointer-events: none;\n}\n\n.loading-content {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.loading-spinner {\n flex-shrink: 0;\n}\n\n.loading-text {\n color: #4b5563;\n font-size: 14px;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: nowrap;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n</style>\n","<template>\n <Transition name=\"fade\" mode=\"out-in\">\n <div v-if=\"isLoading\" class=\"image-loading-placeholder\">\n <div class=\"loading-skeleton-image\">\n <VProgressCircular\n indeterminate\n :size=\"48\"\n :width=\"4\"\n color=\"primary\"\n class=\"loading-spinner-large\"\n />\n <span class=\"loading-skeleton-text\">🖼️ Loading image...</span>\n </div>\n </div>\n </Transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { VProgressCircular } from \"vuetify/components\";\n\n/**\n * ImageLoading - Displays image loading placeholder\n */\ndefineProps<{\n isLoading: boolean;\n}>();\n</script>\n\n<style scoped>\n.image-loading-placeholder {\n width: 300px;\n height: 300px;\n border-radius: 16px;\n overflow: hidden;\n margin: 24px 0;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n@media (min-width: 1024px) {\n .image-loading-placeholder {\n width: 303px;\n height: 303px;\n }\n}\n\n.loading-skeleton-image {\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n}\n\n.loading-spinner-large {\n flex-shrink: 0;\n}\n\n.loading-skeleton-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n</style>\n","<template>\n <Transition name=\"fade\" mode=\"out-in\">\n <div v-if=\"isLoading\" class=\"video-loading-placeholder\">\n <div class=\"loading-skeleton-video\">\n <VProgressCircular\n indeterminate\n :size=\"48\"\n :width=\"4\"\n color=\"primary\"\n class=\"loading-spinner-large\"\n />\n <div class=\"loading-skeleton-text\">🎥 Loading video...</div>\n </div>\n </div>\n </Transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { VProgressCircular } from \"vuetify/components\";\n\n/**\n * VideoLoading - Displays video loading placeholder\n */\ndefineProps<{\n isLoading: boolean;\n}>();\n</script>\n\n<style scoped>\n.video-loading-placeholder {\n margin: 24px 0;\n}\n\n.loading-skeleton-video {\n width: 100%;\n max-width: 500px;\n height: 300px;\n border-radius: 16px;\n overflow: hidden;\n background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n@media (min-width: 1024px) {\n .loading-skeleton-video {\n height: 350px;\n }\n}\n\n.loading-spinner-large {\n flex-shrink: 0;\n}\n\n.loading-skeleton-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n</style>\n","<template>\n <Transition name=\"fade\" mode=\"out-in\">\n <div v-if=\"isLoading\" class=\"card-loading-placeholder\">\n <VSkeletonLoader\n class=\"card-skeleton\"\n width=\"311\"\n type=\"image, article\"\n ></VSkeletonLoader>\n <span class=\"loading-skeleton-text\">🃏 Loading cards...</span>\n </div>\n </Transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { components as vuetifyLabsComponents } from \"vuetify/dist/vuetify-labs.esm.js\";\nconst VSkeletonLoader = vuetifyLabsComponents.VSkeletonLoader;\n\n/**\n * CardLoading - Displays card loading placeholder\n */\ndefineProps<{\n isLoading: boolean;\n}>();\n</script>\n\n<style scoped>\n.card-loading-placeholder {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin: 24px 0;\n}\n\n.card-skeleton {\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.loading-skeleton-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n</style>\n","<template>\n <Transition name=\"fade\" mode=\"out-in\">\n <div v-if=\"isLoading\" class=\"map-loading-placeholder\">\n <VSkeletonLoader\n class=\"map-skeleton\"\n width=\"500\"\n height=\"300\"\n type=\"image\"\n ></VSkeletonLoader>\n <span class=\"loading-skeleton-text\">🗺️ Loading map...</span>\n </div>\n </Transition>\n</template>\n\n<script setup lang=\"ts\">\nimport { components as vuetifyLabsComponents } from \"vuetify/dist/vuetify-labs.esm.js\";\nconst VSkeletonLoader = vuetifyLabsComponents.VSkeletonLoader;\n\n/**\n * MapLoading - Displays map loading placeholder\n */\ndefineProps<{\n isLoading: boolean;\n}>();\n</script>\n\n<style scoped>\n.map-loading-placeholder {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin: 24px 0;\n}\n\n.map-skeleton {\n border-radius: 16px;\n overflow: hidden;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\n.loading-skeleton-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n</style>\n","<script lang=\"ts\" setup>\nimport { computed, ref, watch } from \"vue\";\nimport \"highlight.js/styles/stackoverflow-light.css\";\nimport \"katex/dist/katex.min.css\";\nimport { VDialog, VImg, VBtn } from \"vuetify/components\";\nimport \"../styles/tailwind.css\";\nimport type {\n ButtonData,\n OrcaMarkdownEmits,\n OrcaMarkdownProps,\n} from \"../types\";\nimport { isImageFile, getFileNameFromUrl } from \"../utils/helpers\";\nimport { useContentParser } from \"../composables/useContentParser\";\nimport { useLoadingStates } from \"../composables/useLoadingStates\";\nimport { useCodeButtons } from \"../composables/useCodeButtons\";\nimport { useImageModal } from \"../composables/useImageModal\";\nimport { isLoadingType } from \"../constants/loadingTypes\";\nimport ContentElement from \"./ContentElement.vue\";\nimport GeneralLoading from \"./loading/GeneralLoading.vue\";\nimport ImageLoading from \"./loading/ImageLoading.vue\";\nimport VideoLoading from \"./loading/VideoLoading.vue\";\nimport CardLoading from \"./loading/CardLoading.vue\";\nimport MapLoading from \"./loading/MapLoading.vue\";\n\nconst props = withDefaults(defineProps<OrcaMarkdownProps>(), {\n fileAttachments: () => [],\n isLastMessage: false,\n visibility: \"all\",\n});\n\nconst emit = defineEmits<OrcaMarkdownEmits>();\n\n// Refs\nconst messageContentRef = ref<HTMLElement | null>(null);\n\n// Composables\nconst { modalVisible, currentImage, openModal, closeModal } = useImageModal();\nconst contentParts = useContentParser(computed(() => props.description));\nconst {\n isLoading,\n isImageLoading,\n isVideoLoading,\n isCardLoading,\n isLocationLoading,\n getLoadingMessage,\n} = useLoadingStates(computed(() => props.description));\n\n// Computed properties\nconst imageFiles = computed(() => {\n return props.fileAttachments.filter((file) => file && isImageFile(file));\n});\n\nconst nonImageFiles = computed(() => {\n return props.fileAttachments.filter((file) => file && !isImageFile(file));\n});\n\nconst disabledButton = computed(() => {\n return props.role !== \"assistant\" || !props.isLastMessage || isAdminPage();\n});\n\nconst isAdminPage = () => {\n return props.visibility === \"admin\";\n};\n\n// Get active loading type and message\nconst getActiveLoadingType = computed(() => {\n const desc = props.description || \"\";\n\n // Check each loading type to see which one is active\n if (\n desc.includes(\"[orca.loading.thinking.start]\") &&\n !desc.includes(\"[orca.loading.thinking.end]\")\n ) {\n return \"thinking-loading\";\n }\n if (\n desc.includes(\"[orca.loading.searching.start]\") &&\n !desc.includes(\"[orca.loading.searching.end]\")\n ) {\n return \"searching-loading\";\n }\n if (\n desc.includes(\"[orca.loading.coding.start]\") &&\n !desc.includes(\"[orca.loading.coding.end]\")\n ) {\n return \"coding-loading\";\n }\n if (\n desc.includes(\"[orca.loading.analyzing.start]\") &&\n !desc.includes(\"[orca.loading.analyzing.end]\")\n ) {\n return \"analyzing-loading\";\n }\n if (\n desc.includes(\"[orca.loading.generating.start]\") &&\n !desc.includes(\"[orca.loading.generating.end]\")\n ) {\n return \"generating-loading\";\n }\n if (\n desc.includes(\"[orca.loading.custom.start]\") &&\n !desc.includes(\"[orca.loading.custom.end]\")\n ) {\n return \"custom-loading\";\n }\n if (\n desc.includes(\"[orca.loading.start]\") &&\n !desc.includes(\"[orca.loading.end]\")\n ) {\n return \"general-loading\";\n }\n\n return null;\n});\n\n// Get current loading message\nconst getCurrentLoadingMessage = computed(() => {\n if (isLoading.value) {\n const activeType = getActiveLoadingType.value;\n if (activeType) {\n return getLoadingMessage(activeType);\n }\n return \"⏳ Loading...\";\n }\n return \"⏳ Loading...\";\n});\n\n// Code buttons composable\nconst { addCodeButtons } = useCodeButtons(\n messageContentRef,\n () => props.role !== \"user\"\n);\n\n// Watch content parts to update code buttons\nwatch(contentParts, () => {\n addCodeButtons();\n});\n\n/**\n * Handle button click - emit event to parent component\n */\nconst handleButtonClick = async (button: ButtonData) => {\n if (button.type === \"action\" && !disabledButton.value) {\n try {\n emit(\"send-message\", {\n message: button.label,\n buttonData: button,\n type: \"button-action\",\n });\n } catch (error) {\n console.error(\"Error emitting button click:\", error);\n }\n }\n};\n\n/**\n * Handle image modal open\n */\nconst handleImageModal = (url: string) => {\n openModal(url);\n};\n</script>\n\n<template>\n <div class=\"message-content\">\n <div ref=\"messageContentRef\" class=\"content-wrapper\">\n <!-- Process content parts sequentially -->\n <template v-for=\"(part, index) in contentParts\" :key=\"index\">\n <!-- Skip loading parts - they're handled separately -->\n <ContentElement\n v-if=\"!isLoadingType(part.type)\"\n :element=\"part\"\n :disabled-button=\"disabledButton\"\n :visibility=\"props.visibility as 'all' | 'admin' | undefined\"\n :is-admin=\"isAdminPage()\"\n @image-modal=\"handleImageModal\"\n @button-click=\"handleButtonClick\"\n />\n </template>\n\n <!-- Content-specific loading placeholders -->\n <GeneralLoading\n :isLoading=\"isLoading\"\n :message=\"getCurrentLoadingMessage\"\n />\n <ImageLoading :isLoading=\"isImageLoading\" />\n <VideoLoading :isLoading=\"isVideoLoading\" />\n <CardLoading :isLoading=\"isCardLoading\" />\n <MapLoading :isLoading=\"isLocationLoading\" />\n\n <!-- File Attachments Section -->\n <div\n v-if=\"\n props.fileAttachments &&\n props.fileAttachments.length > 0 &&\n props.role === 'user'\n \"\n class=\"tw-flex tw-flex-wrap tw-gap-4 tw-mt-4 tw-mb-4\"\n >\n <!-- Image files -->\n <img\n v-for=\"file in imageFiles\"\n :key=\"file\"\n :src=\"file\"\n class=\"tw-w-[300px] lg:tw-w-[303px] tw-h-[300px] lg:tw-h-[303px] tw-object-cover tw-rounded-lg tw-cursor-pointer\"\n @click=\"openModal(file)\"\n />\n\n <!-- Non-image files -->\n <VBtn\n v-for=\"file in nonImageFiles\"\n :key=\"file\"\n class=\"text-center text-sm\"\n variant=\"tonal\"\n color=\"grey-500\"\n :href=\"file\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {{ getFileNameFromUrl(file) }}\n </VBtn>\n </div>\n </div>\n </div>\n\n <VDialog\n v-model=\"modalVisible\"\n fullscreen\n class=\"image-modal\"\n scrim=\"rgba(0, 0, 0, 0.85)\"\n @click=\"closeModal\"\n transition=\"fade-transition\"\n >\n <div class=\"modal-close-btn\" @click.stop=\"closeModal\">\n <button class=\"close-button\" aria-label=\"Close image\">\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n <div class=\"modal-content\">\n <VImg :src=\"currentImage\" class=\"modal-image\" contain />\n </div>\n </VDialog>\n</template>\n\n<style lang=\"scss\" scoped>\n.message-content {\n width: 100%;\n position: relative;\n}\n\n.content-wrapper {\n position: relative;\n min-height: 60px;\n}\n\n.text-content {\n width: 100%;\n margin-bottom: 0.5rem;\n}\n\nimg.zoom-image {\n max-width: 300px;\n max-height: 300px;\n width: auto;\n height: auto;\n object-fit: contain;\n border-radius: 16px;\n cursor: zoom-in;\n transition: transform 0.2s ease;\n margin: 0.5rem 0;\n\n &:hover {\n transform: scale(1.02);\n }\n\n @media (min-width: 1024px) {\n max-width: 303px;\n max-height: 303px;\n }\n}\n\n.image-loading-placeholder {\n width: 300px;\n height: 300px;\n border-radius: 16px;\n background: linear-gradient(135deg, #fff 0%, #e3e8f0 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 1rem;\n color: #666;\n margin: 0.5rem 0;\n\n @media (min-width: 1024px) {\n width: 303px;\n height: 303px;\n }\n\n .loading-spinner {\n width: 40px;\n height: 40px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #007bff;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n}\n\n.image-container {\n display: inline-block;\n vertical-align: top;\n margin: 0.5rem 0;\n}\n\n.modal-image {\n max-width: 100%;\n max-height: 100%;\n}\n\n::v-deep(.close-btn) {\n position: absolute;\n top: 10px;\n right: 10px;\n background-color: #fff;\n border: none;\n padding: 5px;\n cursor: pointer;\n}\n\n::v-deep(.code-container) {\n padding: 0;\n border: unset !important;\n margin: 1.5rem 0;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04);\n background: #ffffff;\n border: 1px solid #e5e7eb;\n transition: box-shadow 0.3s ease;\n}\n\n::v-deep(.code-container:hover) {\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06);\n}\n\n::v-deep(.buttons-container) {\n display: flex;\n padding: 12px 16px;\n justify-content: flex-end;\n align-items: center;\n gap: 10px;\n background: linear-gradient(135deg, #fafbfc 0%, #f8f9fa 100%);\n border-bottom: 1px solid #e5e7eb;\n backdrop-filter: blur(8px);\n}\n\n::v-deep(.copy-btn),\n::v-deep(.collapse-btn) {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n background: #ffffff;\n color: #374151;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", sans-serif;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n user-select: none;\n}\n\n::v-deep(.copy-btn:hover),\n::v-deep(.collapse-btn:hover) {\n background: #f9fafb;\n border-color: #9ca3af;\n transform: translateY(-1px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);\n color: #111827;\n}\n\n::v-deep(.copy-btn:active),\n::v-deep(.collapse-btn:active) {\n transform: translateY(0);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n background: #f3f4f6;\n}\n\n::v-deep(.message-content) {\n pre {\n position: relative;\n margin: 0;\n padding: 0;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 16px;\n }\n}\n\n::v-deep(.code-container) {\n .code-wrapper {\n background: #0f172a;\n transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;\n overflow: hidden;\n position: relative;\n\n &.collapsed {\n opacity: 0.85;\n }\n\n pre {\n margin: 0;\n padding: 20px;\n background: #0f172a;\n border-radius: 0;\n overflow-x: auto;\n position: relative;\n\n /* Custom scrollbar */\n &::-webkit-scrollbar {\n height: 8px;\n }\n\n &::-webkit-scrollbar-track {\n background: #1e293b;\n border-radius: 4px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: #475569;\n border-radius: 4px;\n }\n\n &::-webkit-scrollbar-thumb:hover {\n background: #64748b;\n }\n }\n\n code {\n border: none;\n background: transparent;\n color: #e2e8f0;\n font-family: \"Fira Code\", \"JetBrains Mono\", \"Consolas\", \"Monaco\",\n \"Courier New\", monospace;\n font-size: 14px;\n line-height: 1.7;\n padding: 0;\n display: block;\n white-space: pre;\n tab-size: 2;\n letter-spacing: 0.01em;\n }\n\n .hljs {\n background: #0f172a;\n color: #e2e8f0;\n\n /* Syntax highlighting improvements */\n .hljs-keyword,\n .hljs-selector-tag,\n .hljs-built_in,\n .hljs-name,\n .hljs-tag {\n color: #c792ea;\n font-weight: 500;\n }\n\n .hljs-string,\n .hljs-title,\n .hljs-section,\n .hljs-attribute,\n .hljs-literal,\n .hljs-template-tag,\n .hljs-template-variable,\n .hljs-type,\n .hljs-addition {\n color: #c3e88d;\n }\n\n .hljs-comment,\n .hljs-quote,\n .hljs-deletion,\n .hljs-meta {\n color: #546e7a;\n font-style: italic;\n }\n\n .hljs-number,\n .hljs-regexp,\n .hljs-symbol,\n .hljs-variable,\n .hljs-template-variable,\n .hljs-link,\n .hljs-selector-attr,\n .hljs-selector-pseudo {\n color: #f78c6c;\n }\n\n .hljs-function,\n .hljs-title.function_ {\n color: #82aaff;\n }\n\n .hljs-class,\n .hljs-title.class_ {\n color: #ffcb6b;\n }\n }\n }\n}\n\n::v-deep(table) {\n width: 100%;\n margin-bottom: 16px;\n\n th,\n td {\n border: 1px solid #dcdcdc;\n padding: 12px;\n text-align: left;\n }\n\n tr {\n background: #ffffff;\n }\n\n th {\n background: #f2f2f2;\n }\n\n th:first-child {\n border-top-left-radius: 16px;\n }\n\n th:last-child {\n border-top-right-radius: 16px;\n }\n\n tbody > tr:last-child {\n td:first-child {\n border-bottom-left-radius: 16px;\n }\n\n td:last-child {\n border-bottom-right-radius: 16px;\n }\n }\n\n tr:nth-child(even) {\n background-color: #f8f9fa !important;\n }\n}\n\n::v-deep(ol, ul) {\n padding-left: 40px;\n margin: 8px 0;\n li {\n margin-bottom: 6px;\n }\n}\n\n::v-deep(p) {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n::v-deep(h2, h3, h1, h4, h5, h6) {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n::v-deep(hr) {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n\n::v-deep(ul) {\n li {\n margin-top: 0.5rem;\n }\n}\n::v-deep(h1, h2, h3, h4, h5, h6) {\n margin: 1rem 0;\n font-weight: 600;\n line-height: 1.2;\n color: #111;\n font-family: inherit;\n}\n\n::v-deep(h1) {\n font-size: 2.5rem;\n}\n::v-deep(h2) {\n font-size: 2rem;\n}\n::v-deep(h3) {\n font-size: 1.75rem;\n}\n::v-deep(h4) {\n font-size: 1.5rem;\n}\n::v-deep(h5) {\n font-size: 1.25rem;\n}\n::v-deep(h6) {\n font-size: 1rem;\n}\n\n::v-deep(ul) {\n list-style: disc;\n}\n::v-deep(ol) {\n list-style: decimal;\n}\n::v-deep(a) {\n color: blue !important;\n}\n\n.image-modal {\n backdrop-filter: blur(12px);\n}\n\n.modal-close-btn {\n position: absolute;\n top: 20px;\n right: 20px;\n z-index: 10;\n}\n\n.close-button {\n background: rgba(255, 255, 255, 0.98) !important;\n backdrop-filter: blur(12px);\n border-radius: 50%;\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n cursor: pointer;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n color: #1f2937 !important;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);\n padding: 0;\n margin: 0;\n}\n\n.close-button:hover {\n background: rgba(255, 255, 255, 1) !important;\n transform: scale(1.08) rotate(90deg);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.1);\n color: #111827 !important;\n}\n\n.close-button:active {\n transform: scale(1.05) rotate(90deg);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n}\n\n.close-button svg {\n width: 20px;\n height: 20px;\n}\n\n.modal-content {\n height: 100%;\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 40px;\n}\n\n.modal-image {\n max-height: 90vh;\n max-width: 90vw;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);\n transition: transform 0.3s ease;\n}\n\n.modal-image:hover {\n transform: scale(1.02);\n}\n\n.video-container,\n.youtube-container {\n margin: 1rem 0;\n}\n\n.video-player-custom {\n border-radius: 12px;\n overflow: hidden;\n}\n\n::v-deep(.video-js) {\n width: 100%;\n height: 100%;\n border-radius: 12px;\n}\n\n.card-container {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n justify-content: flex-start;\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.buttons {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 16px 0;\n}\n\n.button-row {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.action-button {\n flex: 1;\n min-width: 120px;\n white-space: nowrap;\n}\n\n@media (max-width: 600px) {\n .button-row {\n flex-direction: column;\n }\n\n .action-button {\n width: 100%;\n }\n}\n\n/* Fade transitions for loading states */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n\n.fade-enter-from {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n.fade-leave-to {\n opacity: 0;\n transform: translateY(-10px);\n}\n\n/* Smooth transitions for content */\n.message-content {\n animation: fadeIn 0.3s ease-in;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n</style>\n","import { ref } from \"vue\";\n\n/**\n * Composable for managing image modal state\n * Provides clean API for opening/closing image modals\n */\nexport function useImageModal() {\n const modalVisible = ref(false);\n const currentImage = ref(\"\");\n\n /**\n * Open modal with specified image URL\n */\n const openModal = (imageUrl: string) => {\n currentImage.value = imageUrl;\n modalVisible.value = true;\n };\n\n /**\n * Close modal\n */\n const closeModal = () => {\n modalVisible.value = false;\n // Clear image after animation completes\n setTimeout(() => {\n currentImage.value = \"\";\n }, 300);\n };\n\n return {\n modalVisible,\n currentImage,\n openModal,\n closeModal,\n };\n}\n","/**\n * Orca Components\n * Native components for rendering special content markers\n * @packageDocumentation\n */\n\n// Import Tailwind CSS\nimport \"./styles/tailwind.css\";\n\n// Export main component\nexport { default as OrcaMarkdown } from \"./components/OrcaMarkdown.vue\";\n\n// Export types\nexport type {\n AudioData,\n ButtonData,\n CardData,\n ContentPart,\n ContentPartType,\n GetFileNameFromUrlFn,\n GetYouTubeIdFn,\n IsImageFileFn,\n OrcaMarkdownEmits,\n OrcaMarkdownProps,\n LocationData,\n MapboxConfig,\n SendMessageData,\n TracingData,\n VideoPlayerOptions,\n} from \"./types\";\n\n// Export utility functions\nexport {\n cleanOrcaMarkers,\n generateMapId,\n getAppendIconStyle,\n getFileNameFromUrl,\n getGroupedButtons,\n getOutlinedButtonStyle,\n getOutlinedButtonTextStyle,\n getVuetifyColor,\n getYouTubeId,\n hasLoadingMarkers,\n isImageFile,\n} from \"./utils/helpers\";\n\n// Package version\nexport const version = \"1.0.1\";\n\n// Package info\nexport const packageInfo = {\n name: \"@orca-pt/orca-components\",\n version: \"1.0.1\",\n description: \"Orca native components for rendering special content markers\",\n author: \"Orca Team\",\n};\n"],"names":["isImageFile","url","imageExtensions","pathname","URL","toLowerCase","some","ext","endsWith","e","getFileNameFromUrl","encodedFileName","split","pop","decodeURIComponent","getYouTubeId","match","length","getVuetifyColor","colorName","colorMap","primary","secondary","success","info","warning","error","accent","getGroupedButtons","buttons","rows","forEach","button","row","push","Object","keys","sort","a","b","parseInt","map","getOutlinedButtonStyle","color","hexColor","border","getOutlinedButtonTextStyle","getAppendIconStyle","fill","MARKERS","type","start","end","GENERAL_LOADING_TYPES","escapeRegex","str","replace","createMarkerPattern","config","RegExp","CONTENT_PATTERNS","marker","regex","filterMarkers","markers","predicate","filter","removeByPattern","content","pattern","preserveContent","removeMarkers","cleaned","removeLoadingMarkers","loadingMarkers","removeAllMarkers","contentMarkers","removeContentMarkers","GENERAL_LOADING_MARKERS","m","isGeneralLoadingType","includes","getGeneralLoadingMarkers","CONTENT_MARKERS","getContentMarkers","removeCompleteMarkers","findMatches","index","indexOf","Infinity","extractField","block","fieldName","allFieldNames","otherFields","f","join","createFieldPattern","value","trim","parseYamlList","payload","fields","mapper","fieldNames","name","extracted","field","num","Number","isFinite","defaultValue","required","CARD_FIELDS","BUTTON_FIELDS","AUDIO_FIELDS","SIMPLE_CONTENT_TYPES","PARSER_MAP","card","data","photo","header","subheader","location","latitude","longitude","coord","parsedLatitude","parseFloat","parsedLongitude","label","id","tracing","visibilityMatch","visibility","contentMatch","_a","rawContent","audio","processMatch","isLoadingType","parser","useContentParser","description","computed","parts","remainingContent","iteration","MAX_ITERATIONS","matches","addCleanTextIfExists","firstMatch","reduce","prev","current","substring","processMatchAndAddParts","matchEnd","parseContent","unref","text","cleanText","matchPayload","cleanPayload","nestedParts","shouldSkip","cleanTextBefore","part","parseContentRecursively","LOADING_PATTERNS","actual","LOADING_MESSAGES","isActiveLoading","startPattern","endPattern","hasStart","hasEnd","isActiveContentLoading","actualPattern","hasActual","test","COPY_ICON","COLLAPSE_ICON","attachCodeButtons","closest","codeContainer","document","createElement","className","codeWrapper","style","transition","overflow","appendChild","cloneNode","buttonsContainer","copyButton","innerHTML","onclick","async","navigator","clipboard","writeText","setTimeout","copyToClipboard","querySelector","innerText","collapseButton","wrapper","classList","contains","remove","maxHeight","add","height","scrollHeight","offsetHeight","toggleCodeBlock","replaceWith","LOADING_CONTENT_TYPES","md","MarkdownIt","html","linkify","typographer","highlight","lang","hljs","getLanguage","language","escapeCodeHtml","use","markdownItKatex","markdownItLinkAttributes","attrs","target","rel","props","__props","emit","__emit","openModal","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","src","alt","class","loading","onClick","videoOptions","ref","autoplay","controls","responsive","fluid","sources","_createVNode","_unref","VideoPlayer","options","embedUrl","width","frameborder","allow","allowfullscreen","_Fragment","_renderList","audioItems","audioIndex","key","stroke","viewBox","d","_hoisted_3","_hoisted_4","_toDisplayString","mapInstance","mapLoading","onUnmounted","el","htmlEl","nextTick","mapboxgl","accessToken","mapboxToken","containerId","newMap","Map","container","center","zoom","attributionControl","on","Marker","setLngLat","addTo","addControl","NavigationControl","resize","onMapContainerReady","cx","cy","r","toFixed","cards","i","_createBlock","VCard","elevation","VImg","cover","VCardItem","VCardTitle","_createTextVNode","groupedButtons","rowIndex","VBtn","disabled","_normalizeStyle","variant","rounded","href","$event","handleButtonClick","VIcon","icon","size","traceVisible","isVisible","shouldShow","Array","isArray","tracingData","item","isAdmin","tracingContent","toggleTrace","VExpandTransition","render","renderText","handleImageModal","element","OrcaImage","onOpenModal","OrcaVideo","OrcaYouTube","OrcaAudio","OrcaLocation","OrcaCardList","OrcaButtons","disabledButton","onButtonClick","OrcaTracing","_Transition","mode","isLoading","VProgressCircular","indeterminate","message","_cache","VSkeletonLoader","vuetifyLabsComponents","messageContentRef","modalVisible","currentImage","closeModal","imageUrl","useImageModal","contentParts","isImageLoading","isVideoLoading","isCardLoading","isLocationLoading","getLoadingMessage","descriptionValue","watch","val","hasActiveLoading","immediate","videoLoading","youtubeLoading","loadingType","useLoadingStates","imageFiles","fileAttachments","file","nonImageFiles","role","isLastMessage","isAdminPage","getActiveLoadingType","desc","getCurrentLoadingMessage","activeType","addCodeButtons","containerRef","shouldAddButtons","querySelectorAll","onMounted","useCodeButtons","buttonData","ContentElement","onImageModal","GeneralLoading","ImageLoading","VideoLoading","CardLoading","MapLoading","VDialog","fullscreen","scrim","_withModifiers","args","x1","y1","x2","y2","contain","Date","now","Math","random","toString","substr","version","author"],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Orca Components Type Definitions
3
+ */
4
+ export interface OrcaMarkdownProps {
5
+ /** محتوای اصلی با Orca markers */
6
+ description: string;
7
+ /** نقش فرستنده پیام */
8
+ role: "user" | "assistant" | string;
9
+ /** تصاویر اضافی */
10
+ images?: Record<string, any>;
11
+ /** فایل‌های ضمیمه شده */
12
+ fileAttachments?: string[];
13
+ /** آیا این آخرین پیام است؟ */
14
+ isLastMessage?: boolean;
15
+ /** شناسه store برای مدیریت پیام‌ها */
16
+ storeIdentifier?: string;
17
+ /** سطح دسترسی نمایش */
18
+ visibility?: "all" | "admin" | string;
19
+ }
20
+ export interface OrcaMarkdownEmits {
21
+ /** رویداد ارسال پیام */
22
+ (e: "send-message", data: SendMessageData): void;
23
+ }
24
+ export interface SendMessageData {
25
+ /** محتوای پیام */
26
+ message: string;
27
+ /** اطلاعات دکمه (در صورت کلیک روی دکمه) */
28
+ buttonData?: ButtonData;
29
+ /** نوع پیام */
30
+ type?: "text" | "button-action" | "button-link";
31
+ }
32
+ export interface ButtonData {
33
+ type: "action" | "link";
34
+ label: string;
35
+ id?: number;
36
+ color?: string;
37
+ row?: number;
38
+ url?: string;
39
+ }
40
+ export interface CardData {
41
+ photo: string;
42
+ header: string;
43
+ subheader: string;
44
+ text?: string;
45
+ }
46
+ export interface LocationData {
47
+ latitude: number;
48
+ longitude: number;
49
+ }
50
+ export interface AudioData {
51
+ label: string;
52
+ url: string;
53
+ type: string;
54
+ }
55
+ export interface TracingData {
56
+ visibility: "all" | "admin";
57
+ content: string;
58
+ rawContent?: string;
59
+ }
60
+ export type ContentPartType = "text" | "image" | "video" | "youtube" | "card" | "location" | "buttons" | "audio" | "tracing" | "general-loading" | "thinking-loading" | "searching-loading" | "coding-loading" | "analyzing-loading" | "generating-loading" | "custom-loading" | "image-loading" | "video-loading" | "youtube-loading" | "card-loading" | "map-loading";
61
+ export type TextContentPart = {
62
+ type: "text";
63
+ content: string;
64
+ };
65
+ export type ImageContentPart = {
66
+ type: "image";
67
+ content: string;
68
+ };
69
+ export type VideoContentPart = {
70
+ type: "video";
71
+ content: string;
72
+ };
73
+ export type YoutubeContentPart = {
74
+ type: "youtube";
75
+ content: string;
76
+ };
77
+ export type CardContentPart = {
78
+ type: "card";
79
+ content: CardData[];
80
+ };
81
+ export type LocationContentPart = {
82
+ type: "location";
83
+ content: LocationData;
84
+ };
85
+ export type ButtonsContentPart = {
86
+ type: "buttons";
87
+ content: ButtonData[];
88
+ };
89
+ export type AudioContentPart = {
90
+ type: "audio";
91
+ content: AudioData[];
92
+ };
93
+ export type TracingContentPart = {
94
+ type: "tracing";
95
+ content: TracingData;
96
+ };
97
+ export type LoadingContentPart = {
98
+ type: "general-loading" | "thinking-loading" | "searching-loading" | "coding-loading" | "analyzing-loading" | "generating-loading" | "custom-loading" | "image-loading" | "video-loading" | "youtube-loading" | "card-loading" | "map-loading";
99
+ content: string;
100
+ };
101
+ export type ContentPart = TextContentPart | ImageContentPart | VideoContentPart | YoutubeContentPart | CardContentPart | LocationContentPart | ButtonsContentPart | AudioContentPart | TracingContentPart | LoadingContentPart;
102
+ /**
103
+ * Helper function types
104
+ */
105
+ export type IsImageFileFn = (url: string) => boolean;
106
+ export type GetFileNameFromUrlFn = (url: string) => string | null;
107
+ export type GetYouTubeIdFn = (url: string) => string;
108
+ /**
109
+ * Mapbox configuration
110
+ */
111
+ export interface MapboxConfig {
112
+ accessToken: string;
113
+ style?: string;
114
+ zoom?: number;
115
+ }
116
+ /**
117
+ * Video player options
118
+ */
119
+ export interface VideoPlayerOptions {
120
+ autoplay?: boolean;
121
+ controls?: boolean;
122
+ responsive?: boolean;
123
+ fluid?: boolean;
124
+ sources: Array<{
125
+ type: string;
126
+ src: string;
127
+ }>;
128
+ }
@@ -0,0 +1,48 @@
1
+ import type { ButtonData } from "../types";
2
+ /**
3
+ * Utility functions for Orca Components
4
+ */
5
+ /**
6
+ * بررسی اینکه آیا URL یک فایل تصویری است یا خیر
7
+ */
8
+ export declare function isImageFile(url: string): boolean;
9
+ /**
10
+ * استخراج نام فایل از URL
11
+ */
12
+ export declare function getFileNameFromUrl(url: string): string | null;
13
+ /**
14
+ * استخراج YouTube ID از URL
15
+ */
16
+ export declare function getYouTubeId(url: string): string;
17
+ /**
18
+ * تبدیل نام رنگ Vuetify
19
+ */
20
+ export declare function getVuetifyColor(colorName?: string): string;
21
+ /**
22
+ * گروه‌بندی دکمه‌ها بر اساس ردیف
23
+ */
24
+ export declare function getGroupedButtons(buttons: ButtonData[]): ButtonData[][];
25
+ /**
26
+ * تولید ID یکتا برای container نقشه
27
+ */
28
+ export declare function generateMapId(index: number): string;
29
+ /**
30
+ * پاک کردن marker های orca از متن
31
+ */
32
+ export declare function cleanOrcaMarkers(text: string): string;
33
+ /**
34
+ * بررسی اینکه آیا محتوا loading marker دارد یا خیر
35
+ */
36
+ export declare function hasLoadingMarkers(content: string): boolean;
37
+ /**
38
+ * استخراج style برای دکمه‌های outlined
39
+ */
40
+ export declare function getOutlinedButtonStyle(color?: string): Record<string, string>;
41
+ /**
42
+ * استخراج style برای متن دکمه‌های outlined
43
+ */
44
+ export declare function getOutlinedButtonTextStyle(color?: string): Record<string, string>;
45
+ /**
46
+ * استخراج style برای آیکون append
47
+ */
48
+ export declare function getAppendIconStyle(color?: string): Record<string, string>;
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@orca-pt/orca-components",
3
+ "version": "1.0.1",
4
+ "description": "Orca native components for rendering special content markers in Vue applications",
5
+ "type": "module",
6
+ "main": "./dist/orca-components.umd.js",
7
+ "module": "./dist/orca-components.es.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/orca-components.es.js",
18
+ "require": "./dist/orca-components.umd.cjs"
19
+ },
20
+ "./style.css": "./dist/orca-components.css"
21
+ },
22
+ "scripts": {
23
+ "dev": "vite",
24
+ "build": "vite build && npm run build:types",
25
+ "build:types": "vue-tsc --project tsconfig.build.json",
26
+ "preview": "vite preview",
27
+ "type-check": "vue-tsc --noEmit",
28
+ "test": "vitest",
29
+ "test:ui": "vitest --ui",
30
+ "test:run": "vitest run",
31
+ "test:coverage": "vitest run --coverage",
32
+ "version:sync": "node -e \"const fs=require('fs');const pkg=JSON.parse(fs.readFileSync('package.json'));const index=fs.readFileSync('src/index.ts','utf8');const updated=index.replace(/version: \\\"[\\d.]+\\\"/,`version: \\\"${pkg.version}\\\"`);fs.writeFileSync('src/index.ts',updated);console.log('✅ Synced version to',pkg.version);\"",
33
+ "version:patch": "npm version patch --no-git-tag-version && npm run version:sync",
34
+ "version:minor": "npm version minor --no-git-tag-version && npm run version:sync",
35
+ "version:major": "npm version major --no-git-tag-version && npm run version:sync",
36
+ "dev:install": "npm run build && npm pack && cd ../teams/gptclone-panel && pnpm remove @orcapt/orca-components && pnpm add ../../lexia-components-package/orca-orca-components-1.0.0.tgz",
37
+ "quick-deploy": "npm run build && npm pack && cd ../teams/gptclone-panel && pnpm remove @orcapt/orca-components && pnpm add ../../lexia-components-package/orca-orca-components-1.0.0.tgz && echo '✅ Package deployed successfully!'"
38
+ },
39
+ "peerDependencies": {
40
+ "pinia": "^3.0.0",
41
+ "vue": "^3.5.0",
42
+ "vue-router": "^4.2.0",
43
+ "vuetify": "^3.8.0"
44
+ },
45
+ "dependencies": {
46
+ "@videojs-player/vue": "^1.0.0",
47
+ "highlight.js": "^11.11.1",
48
+ "katex": "^0.16.22",
49
+ "mapbox-gl": "^3.15.0",
50
+ "markdown-it": "^14.1.0",
51
+ "markdown-it-katex": "^2.0.3",
52
+ "markdown-it-link-attributes": "^4.0.1",
53
+ "video.js": "^7.21.7"
54
+ },
55
+ "devDependencies": {
56
+ "@types/markdown-it": "^13.0.7",
57
+ "@types/node": "^20.10.0",
58
+ "@vitejs/plugin-vue": "^5.0.0",
59
+ "@vitest/ui": "^4.0.16",
60
+ "@vue/tsconfig": "^0.5.0",
61
+ "autoprefixer": "^10.4.16",
62
+ "happy-dom": "^20.0.11",
63
+ "sass": "^1.69.5",
64
+ "tailwindcss": "^3.4.0",
65
+ "terser": "^5.44.1",
66
+ "typescript": "^5.3.3",
67
+ "vite": "^6.2.2",
68
+ "vitest": "^4.0.16",
69
+ "vue": "^3.5.13",
70
+ "vue-tsc": "^3.1.8",
71
+ "vuetify": "^3.8.1"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "postcss": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "license": "MIT",
79
+ "publishConfig": {
80
+ "registry": "https://registry.npmjs.org",
81
+ "access": "public"
82
+ }
83
+ }