@8wave/ai-elements 0.119.0-beta.27 → 0.119.0-beta.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{PkChatbotFilePreview-DAhN8TyL.js → PkChatbotFilePreview-DiuzVVKH.js} +2 -2
- package/dist/_chunks/{PkChatbotFilePreview-DAhN8TyL.js.map → PkChatbotFilePreview-DiuzVVKH.js.map} +1 -1
- package/dist/_chunks/{PkStreamingMarkdown-BK9O_NLx.js → PkStreamingMarkdown-DKyHYHUN.js} +3 -3
- package/dist/_chunks/{PkStreamingMarkdown-BK9O_NLx.js.map → PkStreamingMarkdown-DKyHYHUN.js.map} +1 -1
- package/dist/_chunks/{PkToolEditSpreadsheet-D-RCfnrN.js → PkToolEditSpreadsheet-CfJ3BWMe.js} +2 -2
- package/dist/_chunks/{PkToolEditSpreadsheet-D-RCfnrN.js.map → PkToolEditSpreadsheet-CfJ3BWMe.js.map} +1 -1
- package/dist/_chunks/{PkToolRequestOAuthConnection-QYDJPUFF.js → PkToolRequestOAuthConnection-klmrRZWz.js} +2 -2
- package/dist/_chunks/{PkToolRequestOAuthConnection-QYDJPUFF.js.map → PkToolRequestOAuthConnection-klmrRZWz.js.map} +1 -1
- package/dist/_chunks/{PkToolShowArtifact-DGUj8f1k.js → PkToolShowArtifact-ChDm6ZEK.js} +2 -2
- package/dist/_chunks/{PkToolShowArtifact-DGUj8f1k.js.map → PkToolShowArtifact-ChDm6ZEK.js.map} +1 -1
- package/dist/_chunks/{PkToolShowCalendarEvent-BEjPZC1F.js → PkToolShowCalendarEvent-CRVtR3oP.js} +2 -2
- package/dist/_chunks/{PkToolShowCalendarEvent-BEjPZC1F.js.map → PkToolShowCalendarEvent-CRVtR3oP.js.map} +1 -1
- package/dist/_chunks/{PkToolShowContactForm-DXJI0MPZ.js → PkToolShowContactForm-CfCy-b8w.js} +3 -4
- package/dist/_chunks/PkToolShowContactForm-CfCy-b8w.js.map +1 -0
- package/dist/_chunks/{PkToolShowDiagram-C5mSqZDp.js → PkToolShowDiagram-JpRMa4Jj.js} +3 -3
- package/dist/_chunks/{PkToolShowDiagram-C5mSqZDp.js.map → PkToolShowDiagram-JpRMa4Jj.js.map} +1 -1
- package/dist/_chunks/{PkToolShowForm-UQo0Xdiq.js → PkToolShowForm-DnIwTGl4.js} +2 -2
- package/dist/_chunks/{PkToolShowForm-UQo0Xdiq.js.map → PkToolShowForm-DnIwTGl4.js.map} +1 -1
- package/dist/_chunks/{PkToolShowImageGallery-rZ3AtIEP.js → PkToolShowImageGallery-Ab8fJ9jY.js} +4 -4
- package/dist/_chunks/{PkToolShowImageGallery-rZ3AtIEP.js.map → PkToolShowImageGallery-Ab8fJ9jY.js.map} +1 -1
- package/dist/_chunks/{PkToolShowLocation-BOmxHZKd.js → PkToolShowLocation-D5d6bbP-.js} +2 -2
- package/dist/_chunks/{PkToolShowLocation-BOmxHZKd.js.map → PkToolShowLocation-D5d6bbP-.js.map} +1 -1
- package/dist/_chunks/{PkToolShowProductList-ByeSoIwq.js → PkToolShowProductList-DztzZVDd.js} +2 -2
- package/dist/_chunks/{PkToolShowProductList-ByeSoIwq.js.map → PkToolShowProductList-DztzZVDd.js.map} +1 -1
- package/dist/_chunks/{PkToolShowSources-q4XBOwJl.js → PkToolShowSources-Bvg3f3GC.js} +3 -3
- package/dist/_chunks/{PkToolShowSources-q4XBOwJl.js.map → PkToolShowSources-Bvg3f3GC.js.map} +1 -1
- package/dist/_chunks/{PkToolShowVideo-BmHHW4Ep.js → PkToolShowVideo-DdoYLl7R.js} +3 -3
- package/dist/_chunks/{PkToolShowVideo-BmHHW4Ep.js.map → PkToolShowVideo-DdoYLl7R.js.map} +1 -1
- package/dist/_chunks/{PkToolShowWeather-DfLsFayn.js → PkToolShowWeather-CnpPZCLm.js} +2 -2
- package/dist/_chunks/{PkToolShowWeather-DfLsFayn.js.map → PkToolShowWeather-CnpPZCLm.js.map} +1 -1
- package/dist/_chunks/{PkToolShowWebPages-BaapF0CC.js → PkToolShowWebPages-BooCEJrs.js} +3 -3
- package/dist/_chunks/{PkToolShowWebPages-BaapF0CC.js.map → PkToolShowWebPages-BooCEJrs.js.map} +1 -1
- package/dist/_chunks/{chatImagePolicy-CDNkMKdT.js → chatImagePolicy-CfJt8_9Z.js} +2 -2
- package/dist/_chunks/{chatImagePolicy-CDNkMKdT.js.map → chatImagePolicy-CfJt8_9Z.js.map} +1 -1
- package/dist/_chunks/{index.es-BrsciU25.js → index.es-oI6RqNZW.js} +2 -2
- package/dist/_chunks/{index.es-BrsciU25.js.map → index.es-oI6RqNZW.js.map} +1 -1
- package/dist/_chunks/{src-Dt4rhhPN.js → src-DL9TKN-Z.js} +2 -2
- package/dist/_chunks/src-DL9TKN-Z.js.map +1 -0
- package/dist/_chunks/{useLightbox-pPBe746W.js → useLightbox-1KKLemEE.js} +2 -2
- package/dist/_chunks/{useLightbox-pPBe746W.js.map → useLightbox-1KKLemEE.js.map} +1 -1
- package/dist/ai-elements.es.js +25 -25
- package/dist/ai-elements.es.js.map +1 -1
- package/dist-vue/PkChatbot.js +1 -1
- package/dist-vue/PkChatbotAudioTranscript.js +1 -1
- package/dist-vue/PkChatbotEmptyState.js +1 -1
- package/dist-vue/PkChatbotFilePreview.js +1 -1
- package/dist-vue/PkChatbotInput.js +1 -1
- package/dist-vue/PkChatbotMessages.js +1 -1
- package/dist-vue/PkChatbotStepPayload.js +1 -1
- package/dist-vue/PkChatbotStepToolDetail.js +1 -1
- package/dist-vue/PkChatbotSteps.js +1 -1
- package/dist-vue/PkChatbotViewChat.js +1 -1
- package/dist-vue/PkChatbotViewConversations.js +1 -1
- package/dist-vue/PkChatbotViewFiles.js +1 -1
- package/dist-vue/PkChatbotViewProfile.js +1 -1
- package/dist-vue/_chunks/{PkChatbot-D0BQ3VnX.js → PkChatbot-C18mnGJ9.js} +8 -8
- package/dist-vue/_chunks/{PkChatbot-D0BQ3VnX.js.map → PkChatbot-C18mnGJ9.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotAudioTranscript-BUxBHanA.js → PkChatbotAudioTranscript-0rvrhSRQ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotAudioTranscript-BUxBHanA.js.map → PkChatbotAudioTranscript-0rvrhSRQ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotEmptyState-CGjFcwwB.js → PkChatbotEmptyState-BKiyP0Ga.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotEmptyState-CGjFcwwB.js.map → PkChatbotEmptyState-BKiyP0Ga.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotFilePreview-DIP8KLkS.js → PkChatbotFilePreview-D5H-RIk2.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotFilePreview-DIP8KLkS.js.map → PkChatbotFilePreview-D5H-RIk2.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotInput-BVBQY0V5.js → PkChatbotInput-GvgsYsUw.js} +3 -3
- package/dist-vue/_chunks/{PkChatbotInput-BVBQY0V5.js.map → PkChatbotInput-GvgsYsUw.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotMessages-CK0lhcDj.js → PkChatbotMessages-CDLsj7qw.js} +21 -21
- package/dist-vue/_chunks/{PkChatbotMessages-CK0lhcDj.js.map → PkChatbotMessages-CDLsj7qw.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepPayload-l57qHqVf.js → PkChatbotStepPayload-Dm-HCHcG.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotStepPayload-l57qHqVf.js.map → PkChatbotStepPayload-Dm-HCHcG.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-ChrOa4W4.js → PkChatbotStepToolDetail-Bpd_cZEO.js} +3 -3
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-ChrOa4W4.js.map → PkChatbotStepToolDetail-Bpd_cZEO.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotSteps-DnU9r4XT.js → PkChatbotSteps-C4qBM3_t.js} +5 -5
- package/dist-vue/_chunks/{PkChatbotSteps-DnU9r4XT.js.map → PkChatbotSteps-C4qBM3_t.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewChat-DIx3nwEg.js → PkChatbotViewChat-By2TY72m.js} +8 -8
- package/dist-vue/_chunks/{PkChatbotViewChat-DIx3nwEg.js.map → PkChatbotViewChat-By2TY72m.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewConversations-DDWO1Ci_.js → PkChatbotViewConversations-CU5NfEO4.js} +4 -4
- package/dist-vue/_chunks/{PkChatbotViewConversations-DDWO1Ci_.js.map → PkChatbotViewConversations-CU5NfEO4.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewFiles-O9YjrGP0.js → PkChatbotViewFiles-CD-UZPT5.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewFiles-O9YjrGP0.js.map → PkChatbotViewFiles-CD-UZPT5.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewProfile-BoImMMj2.js → PkChatbotViewProfile-DPlb_Wca.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewProfile-BoImMMj2.js.map → PkChatbotViewProfile-DPlb_Wca.js.map} +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-JEkbkY5k.js → PkStreamingMarkdown-CsHzdW69.js} +3 -3
- package/dist-vue/_chunks/{PkStreamingMarkdown-JEkbkY5k.js.map → PkStreamingMarkdown-CsHzdW69.js.map} +1 -1
- package/dist-vue/_chunks/{PkSvgViewer-DrA4yi8Q.js → PkSvgViewer-D6DJ2jVO.js} +2 -2
- package/dist-vue/_chunks/{PkSvgViewer-DrA4yi8Q.js.map → PkSvgViewer-D6DJ2jVO.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolEditSpreadsheet-BX_h8Hut.js → PkToolEditSpreadsheet-D8Zp9gzW.js} +2 -2
- package/dist-vue/_chunks/{PkToolEditSpreadsheet-BX_h8Hut.js.map → PkToolEditSpreadsheet-D8Zp9gzW.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolRequestOAuthConnection-Bwj84qHq.js → PkToolRequestOAuthConnection-DosWR9I4.js} +2 -2
- package/dist-vue/_chunks/{PkToolRequestOAuthConnection-Bwj84qHq.js.map → PkToolRequestOAuthConnection-DosWR9I4.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowArtifact-BIvl5I2I.js → PkToolShowArtifact-BVofKJ7b.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowArtifact-BIvl5I2I.js.map → PkToolShowArtifact-BVofKJ7b.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowCalendarEvent-ve1I0xaV.js → PkToolShowCalendarEvent-u9O_Sl3-.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowCalendarEvent-ve1I0xaV.js.map → PkToolShowCalendarEvent-u9O_Sl3-.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowContactForm-CddxrLBZ.js → PkToolShowContactForm-BzdIFTnC.js} +3 -4
- package/dist-vue/_chunks/PkToolShowContactForm-BzdIFTnC.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowDiagram-DdR4x6pP.js → PkToolShowDiagram-CaoB4k6y.js} +4 -4
- package/dist-vue/_chunks/{PkToolShowDiagram-DdR4x6pP.js.map → PkToolShowDiagram-CaoB4k6y.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowForm-DiXcYws_.js → PkToolShowForm-vYuaPtu0.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowForm-DiXcYws_.js.map → PkToolShowForm-vYuaPtu0.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowImageGallery-COrJEjSv.js → PkToolShowImageGallery-ooygXk7j.js} +4 -4
- package/dist-vue/_chunks/{PkToolShowImageGallery-COrJEjSv.js.map → PkToolShowImageGallery-ooygXk7j.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowLocation-CHi_cONJ.js → PkToolShowLocation-DVMpFdRk.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowLocation-CHi_cONJ.js.map → PkToolShowLocation-DVMpFdRk.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowProductList-BIvJlpMT.js → PkToolShowProductList-D-HJ9a_h.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowProductList-BIvJlpMT.js.map → PkToolShowProductList-D-HJ9a_h.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowSources-CC-0Oh4K.js → PkToolShowSources-DJ35l3Z3.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowSources-CC-0Oh4K.js.map → PkToolShowSources-DJ35l3Z3.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowVideo-UUNkUlrg.js → PkToolShowVideo-xcg1gdIE.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowVideo-UUNkUlrg.js.map → PkToolShowVideo-xcg1gdIE.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowWeather-BOuNrvY2.js → PkToolShowWeather-DJxKxVp_.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowWeather-BOuNrvY2.js.map → PkToolShowWeather-DJxKxVp_.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowWebPages-CLYx_PgL.js → PkToolShowWebPages-BuaRjavD.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowWebPages-CLYx_PgL.js.map → PkToolShowWebPages-BuaRjavD.js.map} +1 -1
- package/dist-vue/_chunks/{createChatbotApiClient-BdmGCAQR.js → createChatbotApiClient-G3Tt1I67.js} +2 -2
- package/dist-vue/_chunks/{createChatbotApiClient-BdmGCAQR.js.map → createChatbotApiClient-G3Tt1I67.js.map} +1 -1
- package/dist-vue/_chunks/{mcpOAuthReport-BeZDTl87.js → mcpOAuthReport-3A9v_gW_.js} +2 -2
- package/dist-vue/_chunks/{mcpOAuthReport-BeZDTl87.js.map → mcpOAuthReport-3A9v_gW_.js.map} +1 -1
- package/dist-vue/_chunks/{src-DCfvejyT.js → src-DpkuiHam.js} +2 -2
- package/dist-vue/_chunks/src-DpkuiHam.js.map +1 -0
- package/dist-vue/_chunks/{useChatbotStore-BAv5K91p.js → useChatbotStore-C1sgxgD1.js} +4 -4
- package/dist-vue/_chunks/{useChatbotStore-BAv5K91p.js.map → useChatbotStore-C1sgxgD1.js.map} +1 -1
- package/dist-vue/_chunks/{useSafeLocalStorage-OwzVTZud.js → useSafeLocalStorage-DLIc8pkn.js} +2 -2
- package/dist-vue/_chunks/{useSafeLocalStorage-OwzVTZud.js.map → useSafeLocalStorage-DLIc8pkn.js.map} +1 -1
- package/dist-vue/_chunks/{utils-BqPJ6DJT.js → utils-DsnEcdW3.js} +2 -2
- package/dist-vue/_chunks/{utils-BqPJ6DJT.js.map → utils-DsnEcdW3.js.map} +1 -1
- package/dist-vue/api.js +1 -1
- package/dist-vue/composables.js +8 -8
- package/dist-vue/composables.js.map +1 -1
- package/dist-vue/index.js +3196 -3184
- package/dist-vue/index.js.map +1 -1
- package/dist-vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/PkToolShowContactForm-DXJI0MPZ.js.map +0 -1
- package/dist/_chunks/src-Dt4rhhPN.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowContactForm-CddxrLBZ.js.map +0 -1
- package/dist-vue/_chunks/src-DCfvejyT.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkToolShowCalendarEvent-ve1I0xaV.js","names":["$t","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","__unplugin_components_4","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_withCtx","_unref","_normalizeProps","_guardReactiveProps","_createTextVNode","_createCommentVNode","_sfc_main","__exportAll","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","PkToolShowCalendarEvent_vue_vue_type_script_setup_true_lang_default","props","__props","useClipboard","useI18n","toolPart","computed","dateDisplay","input","start","startDate","end","endDate","startDay","endDay","allDay","d","calendarStart","calendarDay","calendarMonth","toIcsDateTime","iso","escapeIcs","str","generateIcs","ics","title","location","additionalInfo","blob","url","a","openGoogleCalendar","params","openOutlook","copyEvent","lines","copy","_component_VvIcon","VvIcon","_component_VvButton","VvButtonLocalized","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","_component_VvButtonGroup","VvButtonGroup","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","_ctx","withCtx","unref","copied","normalizeProps","guardReactiveProps","_cache","createTextVNode","isSameSite","createCommentVNode","PkToolShowCalendarEvent_exports","PkToolShowCalendarEvent_default"],"sources":["../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue","../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center\">\n <div\n class=\"bg-brand px-8 py-2 text-brand-contrast text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center\">\n <div\n class=\"bg-brand px-8 py-2 text-brand-contrast text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PkToolShowCalendarEvent-u9O_Sl3-.js","names":["$t","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","__unplugin_components_4","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_withCtx","_unref","_normalizeProps","_guardReactiveProps","_createTextVNode","_createCommentVNode","_sfc_main","__exportAll","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","PkToolShowCalendarEvent_vue_vue_type_script_setup_true_lang_default","props","__props","useClipboard","useI18n","toolPart","computed","dateDisplay","input","start","startDate","end","endDate","startDay","endDay","allDay","d","calendarStart","calendarDay","calendarMonth","toIcsDateTime","iso","escapeIcs","str","generateIcs","ics","title","location","additionalInfo","blob","url","a","openGoogleCalendar","params","openOutlook","copyEvent","lines","copy","_component_VvIcon","VvIcon","_component_VvButton","VvButtonLocalized","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","_component_VvButtonGroup","VvButtonGroup","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","_ctx","withCtx","unref","copied","normalizeProps","guardReactiveProps","_cache","createTextVNode","isSameSite","createCommentVNode","PkToolShowCalendarEvent_exports","PkToolShowCalendarEvent_default"],"sources":["../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue","../../../../packages/components/src/chat/PkToolShowCalendarEvent.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center\">\n <div\n class=\"bg-brand px-8 py-2 text-brand-contrast text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useClipboard } from '@vueuse/core'\n import { isSameSite } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n const { d } = useI18n()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title: string\n startDate: string\n endDate: string\n location?: string\n additionalInfo?: string\n allDay?: boolean\n }\n }\n return part\n })\n\n const dateDisplay = computed(() => {\n const input = toolPart.value.input\n if (!input) {\n return ''\n }\n const { startDate, endDate, allDay } = input\n const start = new Date(startDate)\n const end = new Date(endDate)\n const startDay = startDate.slice(0, 10)\n const endDay = endDate.slice(0, 10)\n if (allDay) {\n if (startDay === endDay) {\n return d(start, 'date-medium')\n }\n return `${d(start, 'date-medium')} - ${d(end, 'date-medium')}`\n }\n if (startDay === endDay) {\n return `${d(start, 'date-time-medium')} - ${d(end, 'time')}`\n }\n return `${d(start, 'date-time-medium')} - ${d(end, 'date-time-medium')}`\n })\n\n const calendarStart = computed(() =>\n toolPart.value.input ? new Date(toolPart.value.input.startDate) : null,\n )\n\n const calendarDay = computed(\n () => calendarStart.value?.getDate().toString() ?? '',\n )\n\n const calendarMonth = computed(() =>\n calendarStart.value ? d(calendarStart.value, 'month-short') : '',\n )\n\n // Floating time: remove dashes/colons without converting to UTC\n const toIcsDateTime = (iso: string) =>\n iso.replace(/[-:]/g, '').replace(/\\.\\d{3}$/, '')\n\n const escapeIcs = (str: string) =>\n str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/;/g, '\\\\;')\n .replace(/,/g, '\\\\,')\n .replace(/\\n/g, '\\\\n')\n\n const generateIcs = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const ics = [\n 'BEGIN:VCALENDAR',\n 'VERSION:2.0',\n 'PRODID:-//8wave//8bot//EN',\n 'BEGIN:VEVENT',\n `DTSTART:${toIcsDateTime(startDate)}`,\n `DTEND:${toIcsDateTime(endDate)}`,\n `SUMMARY:${escapeIcs(title)}`,\n location ? `LOCATION:${escapeIcs(location)}` : '',\n additionalInfo ? `DESCRIPTION:${escapeIcs(additionalInfo)}` : '',\n `DTSTAMP:${new Date()\n .toISOString()\n .replace(/[-:]/g, '')\n .replace(/\\.\\d{3}/, '')}`,\n `UID:${crypto.randomUUID()}@8bot.ai`,\n 'END:VEVENT',\n 'END:VCALENDAR',\n ]\n .filter(Boolean)\n .join('\\r\\n')\n\n const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${title.replace(/[^a-zA-Z0-9\\s-]/g, '')}.ics`\n a.click()\n URL.revokeObjectURL(url)\n }\n\n const openGoogleCalendar = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const start = toIcsDateTime(startDate)\n const end = toIcsDateTime(endDate)\n const params = new URLSearchParams({\n action: 'TEMPLATE',\n text: title,\n dates: `${start}/${end}`,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('details', additionalInfo)\n }\n window.open(\n `https://calendar.google.com/calendar/render?${params.toString()}`,\n '_blank',\n )\n }\n\n const openOutlook = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const { title, startDate, endDate, location, additionalInfo } = input\n const params = new URLSearchParams({\n subject: title,\n startdt: startDate,\n enddt: endDate,\n })\n if (location) {\n params.set('location', location)\n }\n if (additionalInfo) {\n params.set('body', additionalInfo)\n }\n window.open(\n `https://outlook.office.com/calendar/0/action/compose?${params.toString()}`,\n '_blank',\n )\n }\n\n const copyEvent = () => {\n const input = toolPart.value.input\n if (!input) {\n return\n }\n const lines = [input.title, dateDisplay.value]\n if (input.location) {\n lines.push(input.location)\n }\n if (input.additionalInfo) {\n lines.push(input.additionalInfo)\n }\n copy(lines.join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:calendar-event-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.calendarEvent') }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyEvent\" />\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n icon=\"ri:calendar-line\"\n modifiers=\"action-quiet-small\"\n :label=\"$t('action.addToCalendar')\" />\n <template #items>\n <VvDropdownAction @click=\"openGoogleCalendar\">\n <VvIcon name=\"ri:google-line\" />\n Google Calendar\n </VvDropdownAction>\n <VvDropdownAction @click=\"openOutlook\">\n <VvIcon name=\"ri:microsoft-line\" />\n Outlook\n </VvDropdownAction>\n <VvDropdownAction @click=\"generateIcs\">\n <VvIcon name=\"ri:download-line\" />\n {{ $t('action.downloadIcs') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </VvButtonGroup>\n </div>\n <div class=\"p-sm flex gap-sm items-start\">\n <div\n class=\"shrink-0 w-44 rounded-xl overflow-hidden border border-surface-3 text-center\">\n <div\n class=\"bg-brand px-8 py-2 text-brand-contrast text-10 font-bold uppercase tracking-wide\">\n {{ calendarMonth }}\n </div>\n <div\n class=\"bg-surface-1 py-4 text-word-1 text-24 font-bold leading-none\">\n {{ calendarDay }}\n </div>\n </div>\n <div class=\"flex flex-col gap-4 min-w-0\">\n <p class=\"font-semibold text-word-1 text-14\">\n {{ toolPart.input.title }}\n </p>\n <div class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" class=\"text-14 shrink-0\" />\n <time :datetime=\"toolPart.input.startDate\">{{\n dateDisplay\n }}</time>\n </div>\n <div\n v-if=\"toolPart.input.location\"\n class=\"flex items-center gap-8 text-12 text-word-3\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-14 shrink-0\" />\n <a\n v-if=\"toolPart.input.location.startsWith('http')\"\n :href=\"toolPart.input.location\"\n :target=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : '_blank'\n \"\n :rel=\"\n isSameSite(toolPart.input.location)\n ? undefined\n : 'noopener noreferrer'\n \"\n class=\"underline truncate\">\n {{ toolPart.input.location }}\n </a>\n <span v-else>{{ toolPart.input.location }}</span>\n </div>\n <div\n v-if=\"toolPart.input.additionalInfo\"\n class=\"flex items-start gap-8 text-12 text-word-3\">\n <VvIcon\n name=\"ri:sticky-note-line\"\n class=\"text-14 shrink-0 mt-1\" />\n <span>{{ toolPart.input.additionalInfo }}</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
package/dist-vue/_chunks/{PkToolShowContactForm-CddxrLBZ.js → PkToolShowContactForm-BzdIFTnC.js}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
|
|
2
2
|
import { S as t, d as n, v as r } from "./schemas-Bu1lick6.js";
|
|
3
3
|
import { t as i } from "./VvButtonLocalized-BuzLsXp3.js";
|
|
4
|
-
import { t as a } from "./PkStreamingMarkdown-
|
|
5
|
-
import { t as o } from "./useSafeLocalStorage-
|
|
4
|
+
import { t as a } from "./PkStreamingMarkdown-CsHzdW69.js";
|
|
5
|
+
import { t as o } from "./useSafeLocalStorage-DLIc8pkn.js";
|
|
6
6
|
import { t as s } from "./useLocalizedString-PfaKjIQY.js";
|
|
7
7
|
import { t as c } from "./index.es-C1u3kP7i.js";
|
|
8
8
|
import { VvIcon as l } from "@volverjs/ui-vue/components";
|
|
@@ -98,7 +98,6 @@ var C = { class: "border border-surface-3 rounded-xl w-full overflow-hidden bg-s
|
|
|
98
98
|
class: "wysiwyg"
|
|
99
99
|
}, null, 8, ["markdown"])]), m(o, {
|
|
100
100
|
type: "submit",
|
|
101
|
-
modifiers: "primary",
|
|
102
101
|
loading: e.loading,
|
|
103
102
|
disabled: e.loading || e.readonly,
|
|
104
103
|
"icon-position": "right",
|
|
@@ -120,4 +119,4 @@ var C = { class: "border border-surface-3 rounded-xl w-full overflow-hidden bg-s
|
|
|
120
119
|
//#endregion
|
|
121
120
|
export { P as n, F as t };
|
|
122
121
|
|
|
123
|
-
//# sourceMappingURL=PkToolShowContactForm-
|
|
122
|
+
//# sourceMappingURL=PkToolShowContactForm-BzdIFTnC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkToolShowContactForm-BzdIFTnC.js","names":["z.object","z.string","z.email","useForm","__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_Transition","_withCtx","_isRef","PkStreamingMarkdown","_sfc_main","__exportAll","string","email","object","VvButtonLocalized","PkStreamingMarkdown_default","useSafeLocalStorage","useLocalizedString","Se","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","PkToolShowContactForm_vue_vue_type_script_setup_true_lang_default","__emit","$t","useI18n","props","__props","toolPart","computed","input","localSubmitted","LeadFormSchema","emit","watch","newInput","submitted","isSubmitted","submitLead","data","privacyNotice","_component_VvIcon","VvIcon","_component_VvButton","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","unref","Transition","withCtx","VvForm","formData","_cache","isRef","$event","VvFormField","PkToolShowContactForm_exports","PkToolShowContactForm_default"],"sources":["../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowContactForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <!-- The library's default button is the brand, and in\n the chat the brand is the agent's color, as on the\n rest of the card: `primary` drew it neutral dark -->\n <VvButton\n type=\"submit\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <!-- The library's default button is the brand, and in\n the chat the brand is the agent's color, as on the\n rest of the card: `primary` drew it neutral dark -->\n <VvButton\n type=\"submit\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as e } from "./VvButtonLocalized-BuzLsXp3.js";
|
|
2
|
-
import "./src-
|
|
3
|
-
import { P as t } from "./utils-
|
|
4
|
-
import { t as n } from "./PkSvgViewer-
|
|
2
|
+
import "./src-DpkuiHam.js";
|
|
3
|
+
import { P as t } from "./utils-DsnEcdW3.js";
|
|
4
|
+
import { t as n } from "./PkSvgViewer-D6DJ2jVO.js";
|
|
5
5
|
import { VvButtonGroup as r, VvIcon as i } from "@volverjs/ui-vue/components";
|
|
6
6
|
import { computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createVNode as u, defineComponent as d, onMounted as f, openBlock as p, ref as m, toDisplayString as h, unref as g, watch as _, withCtx as v } from "vue";
|
|
7
7
|
import { useI18n as y } from "vue-i18n";
|
|
@@ -120,4 +120,4 @@ var x = {
|
|
|
120
120
|
//#endregion
|
|
121
121
|
export { k as default };
|
|
122
122
|
|
|
123
|
-
//# sourceMappingURL=PkToolShowDiagram-
|
|
123
|
+
//# sourceMappingURL=PkToolShowDiagram-CaoB4k6y.js.map
|
package/dist-vue/_chunks/{PkToolShowDiagram-DdR4x6pP.js.map → PkToolShowDiagram-CaoB4k6y.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkToolShowDiagram-DdR4x6pP.js","names":["__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_withCtx","_createBlock","_createCommentVNode","PkSvgViewer","_sfc_main","VvButtonLocalized","toSnakeCase","PkSvgViewer_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","DiagramType","\"Sequence\"","\"Class\"","\"State\"","\"ER\"","\"XYChart\"","\"Flowchart\"","\"Graph\"","PkToolShowDiagram_default","defineComponent","props","__props","$t","$te","useI18n","useClipboard","toolPart","computed","svgError","ref","svgContent","diagramType","code","diagramTypeLabel","diagramTypeIcon","renderDiagram","theme","THEMES","renderMermaidSVG","watch","onMounted","downloadSvg","blob","url","anchor","copyCode","copy","_component_VvIcon","VvIcon","_component_VvButton","_component_VvButtonGroup","VvButtonGroup","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","unref","withCtx","copied","createBlock","createCommentVNode"],"sources":["../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;GAkCSwB,IAAL,yBAAA,GAAA;QACI,EAAAC,WAAA,mBACA,EAAAC,QAAA,gBACA,EAAAC,QAAA,gBACA,EAAAC,KAAA,aACA,EAAAC,UAAA,WACA,EAAAC,YAAA,aACA,EAAAC,QAAA;AACJ,EARKP,KAAA,CAAA,CAQL;;;;;;;EAnCA,IAAMU,IAAQC,GAKR,EAAE,GAAGC,GAAI,IAAIC,MAAQC,EAAQ,EAC/B,UAAU,SACd,CAAC,GAEK,EAAE,SAAM,cAAWC,EAAa,GAEhCC,IAAWC,QACAP,EAAM,IAQtB,GAEKQ,IAAWC,EAAI,EAAK,GAGpBC,IAAaD,EAAI,EAAE,GAYnBE,IAAcJ,QAAwC;GACxD,IAAMK,IAAON,EAAS,MAAM,OAAO,MAAM,UAAU;GACnD,IAAKM,GAIL,QADkBA,EAAK,MAAM,aAAa,CAAC,GAAG,IAC9C;IACI,KAAK,mBACD,OAAOtB,EAAY;IACvB,KAAK,gBACD,OAAOA,EAAY;IACvB,KAAK,gBACD,OAAOA,EAAY;IACvB,KAAK,aACD,OAAOA,EAAY;IACvB,KAAK,gBACD,OAAOA,EAAY;IACvB,KAAK,aACD,OAAOA,EAAY;IACvB,KAAK,SACD,OAAOA,EAAY;IACvB,SACI;GACR;EACJ,CAAC,GAEKuB,IAAmBN,QAChBI,EAAY,QAGVR,EAAI,WAAWQ,EAAY,OAAO,IACnCT,EAAG,WAAWS,EAAY,OAAO,IACjCA,EAAY,QAJP,EAKd,GAEKG,IAAkBP,QAAe;GACnC,QAAQI,EAAY,OAApB;IACI,KAAKrB,EAAY,UACb,OAAO;IACX,KAAKA,EAAY,OACb,OAAO;IACX,KAAKA,EAAY,OACb,OAAO;IACX,KAAKA,EAAY,IACb,OAAO;IACX,KAAKA,EAAY,SACb,OAAO;IACX,KAAKA,EAAY,WACb,OAAO;IACX,KAAKA,EAAY,OACb,OAAO;IACX,SACI,OAAO;GACf;EACJ,CAAC;EAED,eAAeyB,IAAgB;GAC3B,IAAMH,IAAON,EAAS,MAAM,OAAO;GACnC,IAAKM,GAIL;MAAS,QAAQ;IACjB,IAAI;KACA,IAAM,EAAE,qBAAkB,cACtB,MAAM,OAAO,sBACXI,IAAQhB,EAAM,SACdiB,EAAO,iBACPA,EAAO;KACb,EAAW,QAAQC,EAAiBN,GAAMI,CAAK;IACnD,QAAQ;KACJ,EAAS,QAAQ;IACrB;GAViB;EAWrB;EAGA,AADAG,EAAM,OAAOb,EAAS,MAAM,OAAO,YAAYN,EAAM,MAAM,GAAGe,CAAa,GAC3EK,EAAU,YAAY;GAClB,MAAML,EAAc;EACxB,CAAC;EAED,IAAMM,UAAoB;GACtB,IAAI,CAACX,EAAW,OACZ;GAEJ,IAAMY,IAAO,IAAI,KAAK,CAACZ,EAAW,KAAK,GAAG,EACtC,MAAM,8BACV,CAAC,GACKa,IAAM,IAAI,gBAAgBD,CAAI,GAC9BE,IAAS,SAAS,cAAc,GAAG;GAMzC,AALA,EAAO,OAAOD,GACd,EAAO,WAAW,GAAG1C,EAAYyB,EAAS,MAAM,OAAO,SAAS,SAAS,EAAE,OAC3E,SAAS,KAAK,YAAYkB,CAAM,GAChCA,EAAO,MAAM,GACb,SAAS,KAAK,YAAYA,CAAM,GAChC,IAAI,gBAAgBD,CAAG;EAC3B,GAEME,UAAiB;GACnB,IAAMb,IAAON,EAAS,MAAM,OAAO;GACnC,AAAIM,KACAc,EAAKd,CAAI;EAEjB;;;GAKU,OAAAN,EAAA,OAAU,OAAO,QAD3BrC,EAAA,GAAAC,EA2CM,OA3CNa,GA2CM;IAxCFZ,EAqBM,OArBNa,GAqBM;KAnBFZ,EAAkDuD,GAAA;MAAzC,MAAMb,EAAA;MAAiB,OAAM;;KACtC3C,EAIM,OAJNc,GAIM,CAHFd,EAEW,UAFXe,GAEWb,EADPwC,EAAA,SAAoBvC,EAAA4B,CAAA,CAAE,CAAA,eAAA,CAAA,GAAA,CAAA,CAAA,CAAA;KAG9B9B,EAYgB0D,GAAA;MAZD,WAAU;MAAU,OAAM;;MACrC,SAAAvD,QAIwB,CAJxBH,EAIwByD,GAAA;OAHpB,WAAU;OACT,MAAMvD,EAAAiE,CAAA,IAAM,kBAAA;OACZ,OAAOjE,EAAAiE,CAAA,IAASjE,EAAA4B,CAAA,CAAE,CAAA,eAAA,IAAoB5B,EAAA4B,CAAA,CAAE,CAAA,aAAA;OACxC,SAAOuB;MAEF,GAAA,MAAA,GAAA,CAAA,QAAA,OAAA,CAAA,GAAAf,EAAA,SADVzC,EAAA,GAAAO,EAK2BqD,GAAA;;OAHvB,WAAU;OACV,MAAK;OACJ,OAAOvD,EAAA4B,CAAA,CAAE,CAAA,iBAAA;OACT,SAAOmB;;;;;IAGTb,EAAA,SAAXvC,EAAA,GAAAC,EAEM,OAFNiB,GAEMd,EADCC,EAAA4B,CAAA,CAAE,CAAA,4BAAA,CAAA,GAAA,CAAA,KAGMQ,EAAA,SADfzC,EAAA,GAAAO,EAIqCE,GAAA;;KAFjC,OAAM;KACL,KAAKgC,EAAA;KACL,OAAOJ,EAAA,MAAS,OAAO;IAC5BrC,GAAAA,MAAAA,GAAAA,CAAAA,OAAAA,OAAAA,CAAAA,MAAAA,EAAA,GAAAC,EAIM,OAJNkB,GAIM,CADFhB,EAA4DuD,GAAA;KAApD,MAAK;KAAe,OAAM;;IAG5BrB,EAAA,MAAS,MAAM,WADzBrC,EAAA,GAAAC,EAIM,OAJNmB,GAIMhB,EADCiC,EAAA,MAAS,MAAM,OAAO,GAAA,CAAA,KAAAmC,EAAA,IAAA,EAAA"}
|
|
1
|
+
{"version":3,"file":"PkToolShowDiagram-CaoB4k6y.js","names":["__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_withCtx","_createBlock","_createCommentVNode","PkSvgViewer","_sfc_main","VvButtonLocalized","toSnakeCase","PkSvgViewer_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","DiagramType","\"Sequence\"","\"Class\"","\"State\"","\"ER\"","\"XYChart\"","\"Flowchart\"","\"Graph\"","PkToolShowDiagram_default","defineComponent","props","__props","$t","$te","useI18n","useClipboard","toolPart","computed","svgError","ref","svgContent","diagramType","code","diagramTypeLabel","diagramTypeIcon","renderDiagram","theme","THEMES","renderMermaidSVG","watch","onMounted","downloadSvg","blob","url","anchor","copyCode","copy","_component_VvIcon","VvIcon","_component_VvButton","_component_VvButtonGroup","VvButtonGroup","openBlock","createElementBlock","createElementVNode","createVNode","toDisplayString","unref","withCtx","copied","createBlock","createCommentVNode"],"sources":["../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
|
|
2
2
|
import { P as t } from "./Agent-DU1WWaHR.js";
|
|
3
3
|
import { t as n } from "./VvButtonLocalized-BuzLsXp3.js";
|
|
4
|
-
import { t as r } from "./PkStreamingMarkdown-
|
|
5
|
-
import { c as i, l as a } from "./utils-
|
|
4
|
+
import { t as r } from "./PkStreamingMarkdown-CsHzdW69.js";
|
|
5
|
+
import { c as i, l as a } from "./utils-DsnEcdW3.js";
|
|
6
6
|
import { VvCheckbox as o, VvCheckboxGroup as s, VvIcon as ee, VvInputText as te, VvRadio as c, VvRadioGroup as l } from "@volverjs/ui-vue/components";
|
|
7
7
|
import { Fragment as u, computed as d, createBlock as f, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createSlots as g, createTextVNode as _, createVNode as v, defineComponent as y, mergeModels as b, mergeProps as x, normalizeClass as ne, normalizeStyle as re, openBlock as S, reactive as ie, ref as C, renderList as w, renderSlot as T, toDisplayString as E, unref as D, useId as O, useModel as k, watch as A, withCtx as j, withKeys as ae, withModifiers as M } from "vue";
|
|
8
8
|
import { useI18n as oe } from "vue-i18n";
|
|
@@ -369,4 +369,4 @@ var N = /* @__PURE__ */ y({
|
|
|
369
369
|
//#endregion
|
|
370
370
|
export { N as i, L as n, P as r, R as t };
|
|
371
371
|
|
|
372
|
-
//# sourceMappingURL=PkToolShowForm-
|
|
372
|
+
//# sourceMappingURL=PkToolShowForm-vYuaPtu0.js.map
|