@8wave/ai-elements 0.90.0 → 0.91.0
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/{Document-BajUssb0.js → Document-OYsMoc9f.js} +46 -9
- package/dist/_chunks/Document-OYsMoc9f.js.map +1 -0
- package/dist/_chunks/{PkToolShowSources-CZWBpBBV.js → PkToolShowSources-BHLHRoy2.js} +2 -2
- package/dist/_chunks/{PkToolShowSources-CZWBpBBV.js.map → PkToolShowSources-BHLHRoy2.js.map} +1 -1
- package/dist/_chunks/{PkToolShowSuggestedReply-1j4lOkRj.js → PkToolShowSuggestedReply-CUk_SK-9.js} +2 -2
- package/dist/_chunks/PkToolShowSuggestedReply-CUk_SK-9.js.map +1 -0
- package/dist/ai-elements.es.js +4099 -3985
- package/dist/ai-elements.es.js.map +1 -1
- package/dist-vue/PkChatbot.js +1 -1
- package/dist-vue/PkChatbotAuth.js +1 -1
- package/dist-vue/PkChatbotEmptyState.js +1 -1
- package/dist-vue/PkChatbotFeedbackForm.js +1 -1
- package/dist-vue/PkChatbotFilePreview.js +1 -1
- package/dist-vue/PkChatbotInput.js +1 -1
- package/dist-vue/PkChatbotMessageFeedback.js +1 -1
- package/dist-vue/PkChatbotMessages.js +1 -1
- package/dist-vue/PkChatbotOutlineRail.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/{Document-Dvf2nw6v.js → Document-c1tATTDs.js} +46 -9
- package/dist-vue/_chunks/{Document-Dvf2nw6v.js.map → Document-c1tATTDs.js.map} +1 -1
- package/dist-vue/_chunks/{PkAvatar-Dv3e4aUl.js → PkAvatar-Bpf6cD4N.js} +1 -1
- package/dist-vue/_chunks/{PkAvatar-Dv3e4aUl.js.map → PkAvatar-Bpf6cD4N.js.map} +1 -1
- package/dist-vue/_chunks/PkChatbot-DpfxBVue.js +237 -0
- package/dist-vue/_chunks/PkChatbot-DpfxBVue.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotAuth-CFqcYxj9.js → PkChatbotAuth-uAPZRV6N.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotAuth-CFqcYxj9.js.map → PkChatbotAuth-uAPZRV6N.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotEmptyState-C70aTfG-.js → PkChatbotEmptyState-JTlPPXdI.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotEmptyState-C70aTfG-.js.map → PkChatbotEmptyState-JTlPPXdI.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotFeedbackForm-Ds2-nOaU.js → PkChatbotFeedbackForm-CHXxzWqQ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotFeedbackForm-Ds2-nOaU.js.map → PkChatbotFeedbackForm-CHXxzWqQ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotFilePreview-DG887KhT.js → PkChatbotFilePreview-Bf1bdZn8.js} +61 -54
- package/dist-vue/_chunks/PkChatbotFilePreview-Bf1bdZn8.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotInput-BTszEUj2.js → PkChatbotInput-DWS7vqC5.js} +152 -124
- package/dist-vue/_chunks/PkChatbotInput-DWS7vqC5.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotMessageFeedback-Cp0zzCP8.js → PkChatbotMessageFeedback-DAqlgPrz.js} +1 -1
- package/dist-vue/_chunks/{PkChatbotMessageFeedback-Cp0zzCP8.js.map → PkChatbotMessageFeedback-DAqlgPrz.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotMessages-DLP7utmG.js → PkChatbotMessages-BR5JUybd.js} +208 -212
- package/dist-vue/_chunks/PkChatbotMessages-BR5JUybd.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotOutlineRail-CAIfj2dI.js → PkChatbotOutlineRail-BXrdMIrA.js} +1 -1
- package/dist-vue/_chunks/{PkChatbotOutlineRail-CAIfj2dI.js.map → PkChatbotOutlineRail-BXrdMIrA.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-C-ucv_wp.js → PkChatbotStepToolDetail-C2nWevnD.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-C-ucv_wp.js.map → PkChatbotStepToolDetail-C2nWevnD.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotSteps-CBOhYZ10.js → PkChatbotSteps-5Ahr-zpZ.js} +4 -4
- package/dist-vue/_chunks/{PkChatbotSteps-CBOhYZ10.js.map → PkChatbotSteps-5Ahr-zpZ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewChat-BZ9IH-sz.js → PkChatbotViewChat-C_t6qEEV.js} +64 -55
- package/dist-vue/_chunks/PkChatbotViewChat-C_t6qEEV.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotViewConversations-q5KPJt_D.js → PkChatbotViewConversations-CEaEsnBy.js} +4 -4
- package/dist-vue/_chunks/{PkChatbotViewConversations-q5KPJt_D.js.map → PkChatbotViewConversations-CEaEsnBy.js.map} +1 -1
- package/dist-vue/_chunks/PkChatbotViewFiles-Bzcn8AEo.js +114 -0
- package/dist-vue/_chunks/PkChatbotViewFiles-Bzcn8AEo.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotViewProfile-DTbQlkVL.js → PkChatbotViewProfile-CfFeqjse.js} +4 -4
- package/dist-vue/_chunks/{PkChatbotViewProfile-DTbQlkVL.js.map → PkChatbotViewProfile-CfFeqjse.js.map} +1 -1
- package/dist-vue/_chunks/{PkRelativeTime-D72zYq42.js → PkRelativeTime-2HoOjv_T.js} +1 -1
- package/dist-vue/_chunks/{PkRelativeTime-D72zYq42.js.map → PkRelativeTime-2HoOjv_T.js.map} +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-CVAsbuWi.js → PkStreamingMarkdown-C_LQOTVJ.js} +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-CVAsbuWi.js.map → PkStreamingMarkdown-C_LQOTVJ.js.map} +1 -1
- package/dist-vue/_chunks/{PkSvgViewer-CTYxVK7q.js → PkSvgViewer-Dtx4uluo.js} +2 -2
- package/dist-vue/_chunks/{PkSvgViewer-CTYxVK7q.js.map → PkSvgViewer-Dtx4uluo.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowArtifact-Csjfo9Xl.js → PkToolShowArtifact-CoYM3_A3.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowArtifact-Csjfo9Xl.js.map → PkToolShowArtifact-CoYM3_A3.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowCalendarEvent-B2tHaoqo.js → PkToolShowCalendarEvent-BZYdRwid.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowCalendarEvent-B2tHaoqo.js.map → PkToolShowCalendarEvent-BZYdRwid.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowComparison-BLDtjv3w.js → PkToolShowComparison-C4OP5c1t.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowComparison-BLDtjv3w.js.map → PkToolShowComparison-C4OP5c1t.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowContactForm-CdgD4fd8.js → PkToolShowContactForm-DjX9G8CD.js} +5 -5
- package/dist-vue/_chunks/{PkToolShowContactForm-CdgD4fd8.js.map → PkToolShowContactForm-DjX9G8CD.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowDiagram-DGYQjjGj.js → PkToolShowDiagram-DHwAckwN.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowDiagram-DGYQjjGj.js.map → PkToolShowDiagram-DHwAckwN.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowEmail-D42WDTO9.js → PkToolShowEmail-5waUO5cm.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowEmail-D42WDTO9.js.map → PkToolShowEmail-5waUO5cm.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowForm-BhVSPIAR.js → PkToolShowForm-C7bOdRse.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowForm-BhVSPIAR.js.map → PkToolShowForm-C7bOdRse.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowImageGallery-WANi2hA0.js → PkToolShowImageGallery-D3bqInQn.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowImageGallery-WANi2hA0.js.map → PkToolShowImageGallery-D3bqInQn.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowLocation-RVbaQoU5.js → PkToolShowLocation-DE-dbJEw.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowLocation-RVbaQoU5.js.map → PkToolShowLocation-DE-dbJEw.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowMessage-D8UbJcas.js → PkToolShowMessage-DCbW7AYl.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowMessage-D8UbJcas.js.map → PkToolShowMessage-DCbW7AYl.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowProductList-BQts3MBy.js → PkToolShowProductList-Blsv3Cio.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowProductList-BQts3MBy.js.map → PkToolShowProductList-Blsv3Cio.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowQrCode-BybXCt5e.js → PkToolShowQrCode-BbMTgOW3.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowQrCode-BybXCt5e.js.map → PkToolShowQrCode-BbMTgOW3.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowSources-DRewYfe-.js → PkToolShowSources-B9d3iLVk.js} +5 -5
- package/dist-vue/_chunks/{PkToolShowSources-DRewYfe-.js.map → PkToolShowSources-B9d3iLVk.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowSuggestedReply-DKiYUsaZ.js → PkToolShowSuggestedReply-B516t3Nb.js} +2 -2
- package/dist-vue/_chunks/PkToolShowSuggestedReply-B516t3Nb.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowWebPages-IV3OzwJe.js → PkToolShowWebPages-BF2aHJGK.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowWebPages-IV3OzwJe.js.map → PkToolShowWebPages-BF2aHJGK.js.map} +1 -1
- package/dist-vue/_chunks/{PkUrl-a6l-l4Au.js → PkUrl-DA-6t_2f.js} +1 -1
- package/dist-vue/_chunks/{PkUrl-a6l-l4Au.js.map → PkUrl-DA-6t_2f.js.map} +1 -1
- package/dist-vue/_chunks/{chatbotProfileContext-R95aQ5bH.js → chatbotProfileContext-R1zi561l.js} +1 -1
- package/dist-vue/_chunks/{chatbotProfileContext-R95aQ5bH.js.map → chatbotProfileContext-R1zi561l.js.map} +1 -1
- package/dist-vue/_chunks/{constants-DpYDYnZU.js → constants-CWT3GgSb.js} +2 -2
- package/dist-vue/_chunks/constants-CWT3GgSb.js.map +1 -0
- package/dist-vue/_chunks/{createChatbotApiClient-DXmWtu3b.js → createChatbotApiClient-kU7rCKwN.js} +13 -5
- package/dist-vue/_chunks/createChatbotApiClient-kU7rCKwN.js.map +1 -0
- package/dist-vue/_chunks/{dist-BbAXqaCM.js → dist-0LxfGh4q.js} +2 -2
- package/dist-vue/_chunks/{dist-BbAXqaCM.js.map → dist-0LxfGh4q.js.map} +1 -1
- package/dist-vue/_chunks/{dist-BU1gMaJv.js → dist-46HfWmpr.js} +2 -2
- package/dist-vue/_chunks/{dist-BU1gMaJv.js.map → dist-46HfWmpr.js.map} +1 -1
- package/dist-vue/_chunks/{dist-CpoLpTWk.js → dist-8YCZENrl.js} +3 -3
- package/dist-vue/_chunks/{dist-CpoLpTWk.js.map → dist-8YCZENrl.js.map} +1 -1
- package/dist-vue/_chunks/{dist-l7mimsz6.js → dist-B34dY8rD.js} +2 -2
- package/dist-vue/_chunks/{dist-l7mimsz6.js.map → dist-B34dY8rD.js.map} +1 -1
- package/dist-vue/_chunks/{dist-CYrZgvgZ.js → dist-BfbUNalO.js} +4 -4
- package/dist-vue/_chunks/{dist-CYrZgvgZ.js.map → dist-BfbUNalO.js.map} +1 -1
- package/dist-vue/_chunks/{dist-Begygip9.js → dist-BmRGnWn9.js} +3 -3
- package/dist-vue/_chunks/{dist-Begygip9.js.map → dist-BmRGnWn9.js.map} +1 -1
- package/dist-vue/_chunks/{dist-BGl_mYmF.js → dist-BoaZDzxm.js} +4 -4
- package/dist-vue/_chunks/{dist-BGl_mYmF.js.map → dist-BoaZDzxm.js.map} +1 -1
- package/dist-vue/_chunks/{dist-DEyUvwtq.js → dist-Bq9kJLlA.js} +3 -3
- package/dist-vue/_chunks/{dist-DEyUvwtq.js.map → dist-Bq9kJLlA.js.map} +1 -1
- package/dist-vue/_chunks/{dist-nZs6UeVS.js → dist-Bs-QG-km.js} +1 -1
- package/dist-vue/_chunks/{dist-nZs6UeVS.js.map → dist-Bs-QG-km.js.map} +1 -1
- package/dist-vue/_chunks/{dist-DinYvSmw.js → dist-BxqLQ_dy.js} +2 -2
- package/dist-vue/_chunks/{dist-DinYvSmw.js.map → dist-BxqLQ_dy.js.map} +1 -1
- package/dist-vue/_chunks/{dist-Dj7rLAD9.js → dist-Cc0Lyhoq.js} +3 -3
- package/dist-vue/_chunks/{dist-Dj7rLAD9.js.map → dist-Cc0Lyhoq.js.map} +1 -1
- package/dist-vue/_chunks/{dist-Jh4J_VuU.js → dist-CiYFTV6m.js} +3 -3
- package/dist-vue/_chunks/{dist-Jh4J_VuU.js.map → dist-CiYFTV6m.js.map} +1 -1
- package/dist-vue/_chunks/{dist-BzsV0Mzp.js → dist-CrcvoPSj.js} +2 -2
- package/dist-vue/_chunks/{dist-BzsV0Mzp.js.map → dist-CrcvoPSj.js.map} +1 -1
- package/dist-vue/_chunks/{dist-CABEM3v-.js → dist-DK5UPLjU.js} +4 -4
- package/dist-vue/_chunks/{dist-CABEM3v-.js.map → dist-DK5UPLjU.js.map} +1 -1
- package/dist-vue/_chunks/{dist-uvKhW3hB.js → dist-Da4-ZEZn.js} +3 -3
- package/dist-vue/_chunks/{dist-uvKhW3hB.js.map → dist-Da4-ZEZn.js.map} +1 -1
- package/dist-vue/_chunks/{dist-SbwxxzT7.js → dist-Dc77ClI_.js} +3 -3
- package/dist-vue/_chunks/{dist-SbwxxzT7.js.map → dist-Dc77ClI_.js.map} +1 -1
- package/dist-vue/_chunks/{dist-t9ZGnt-g.js → dist-LN9oA4PR.js} +2 -2
- package/dist-vue/_chunks/{dist-t9ZGnt-g.js.map → dist-LN9oA4PR.js.map} +1 -1
- package/dist-vue/_chunks/{dist-DKzsFjYx.js → dist-gx9K9AtO.js} +5 -5
- package/dist-vue/_chunks/{dist-DKzsFjYx.js.map → dist-gx9K9AtO.js.map} +1 -1
- package/dist-vue/_chunks/{dist-Bnrde8nq.js → dist-iDVEgNgZ.js} +3 -3
- package/dist-vue/_chunks/{dist-Bnrde8nq.js.map → dist-iDVEgNgZ.js.map} +1 -1
- package/dist-vue/_chunks/{dist-Byr8BhEG.js → dist-m2_O1KGc.js} +3 -3
- package/dist-vue/_chunks/{dist-Byr8BhEG.js.map → dist-m2_O1KGc.js.map} +1 -1
- package/dist-vue/_chunks/{dist-C08Qizu9.js → dist-qArLqzVS.js} +2 -2
- package/dist-vue/_chunks/{dist-C08Qizu9.js.map → dist-qArLqzVS.js.map} +1 -1
- package/dist-vue/_chunks/{dist-6gaEFVNT.js → dist-qJLUge9r.js} +2 -2
- package/dist-vue/_chunks/{dist-6gaEFVNT.js.map → dist-qJLUge9r.js.map} +1 -1
- package/dist-vue/_chunks/{index.es-ChKj3bPm.js → index.es-W-WNHB7-.js} +1 -1
- package/dist-vue/_chunks/{index.es-ChKj3bPm.js.map → index.es-W-WNHB7-.js.map} +1 -1
- package/dist-vue/_chunks/{useChatbotStore-GEO6rQ74.js → useChatbotStore-WPRS7mhR.js} +855 -832
- package/dist-vue/_chunks/{useChatbotStore-GEO6rQ74.js.map → useChatbotStore-WPRS7mhR.js.map} +1 -1
- package/dist-vue/_chunks/{useLocalizedString-DPX1ED4p.js → useLocalizedString-BQzGZyu0.js} +1 -1
- package/dist-vue/_chunks/{useLocalizedString-DPX1ED4p.js.map → useLocalizedString-BQzGZyu0.js.map} +1 -1
- package/dist-vue/_chunks/utils-BDNQaNua.js +101 -0
- package/dist-vue/_chunks/utils-BDNQaNua.js.map +1 -0
- package/dist-vue/api.js +1 -1
- package/dist-vue/composables.js +4 -4
- package/dist-vue/index.js +105 -80
- package/dist-vue/index.js.map +1 -1
- package/dist-vue/locales.js +10 -2
- package/dist-vue/packages/components/src/chat/PkChatbotInput.d.ts +7 -3
- package/dist-vue/packages/components/src/chat/PkMessageParts.d.ts +3 -0
- package/dist-vue/packages/components/src/chat/constants.d.ts +1 -1
- package/dist-vue/packages/components/src/chat/useChatScroll.d.ts +0 -7
- package/dist-vue/packages/components/src/table/PkTableSortable.d.ts +4 -0
- package/dist-vue/packages/composable/src/chatbot/api/createChatbotApiClient.d.ts +1 -0
- package/dist-vue/packages/composable/src/chatbot/useChatbotStore.d.ts +42 -3
- package/dist-vue/packages/composable/src/index.d.ts +1 -0
- package/dist-vue/packages/composable/src/useFileRow.d.ts +24 -0
- package/dist-vue/packages/models/src/schema/Agent.d.ts +1 -0
- package/dist-vue/packages/models/src/schema/Document.d.ts +12 -0
- package/dist-vue/packages/models/src/schema/Platform.d.ts +6 -0
- package/dist-vue/packages/models/src/schema/constants.d.ts +7 -2
- package/dist-vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/Document-BajUssb0.js.map +0 -1
- package/dist/_chunks/PkToolShowSuggestedReply-1j4lOkRj.js.map +0 -1
- package/dist-vue/_chunks/PkChatbot-q_W4cKsy.js +0 -237
- package/dist-vue/_chunks/PkChatbot-q_W4cKsy.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotFilePreview-DG887KhT.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotInput-BTszEUj2.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotMessages-DLP7utmG.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotViewChat-BZ9IH-sz.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotViewFiles-B0FNE1Kk.js +0 -86
- package/dist-vue/_chunks/PkChatbotViewFiles-B0FNE1Kk.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowSuggestedReply-DKiYUsaZ.js.map +0 -1
- package/dist-vue/_chunks/constants-DpYDYnZU.js.map +0 -1
- package/dist-vue/_chunks/createChatbotApiClient-DXmWtu3b.js.map +0 -1
- package/dist-vue/_chunks/utils-BBAveXy4.js +0 -101
- package/dist-vue/_chunks/utils-BBAveXy4.js.map +0 -1
package/dist-vue/_chunks/{PkChatbotFilePreview-DG887KhT.js → PkChatbotFilePreview-Bf1bdZn8.js}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { C as e } from "./src-BCYjA3mm.js";
|
|
2
2
|
import { VvIcon as t } from "@volverjs/ui-vue/components";
|
|
3
|
-
import { Fragment as n, computed as r, createBlock as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, createVNode as l, defineComponent as u, normalizeClass as d, normalizeStyle as f, onBeforeUnmount as p, onMounted as m, openBlock as h, ref as g, shallowRef as _, toDisplayString as v,
|
|
3
|
+
import { Fragment as n, computed as r, createBlock as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, createVNode as l, defineComponent as u, normalizeClass as d, normalizeStyle as f, onBeforeUnmount as p, onMounted as m, openBlock as h, ref as g, shallowRef as _, toDisplayString as v, vShow as y, withDirectives as b, withModifiers as x } from "vue";
|
|
4
4
|
//#region ../../packages/components/src/composables/useLightbox.ts
|
|
5
|
-
var
|
|
5
|
+
var S = "https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css", C = {
|
|
6
6
|
width: 1200,
|
|
7
7
|
height: 800
|
|
8
8
|
};
|
|
9
|
-
function
|
|
9
|
+
function w(t) {
|
|
10
10
|
let { gallery: n, children: r = "a[data-pswp-src]", loop: i = !0, downloadable: a = !0, openInNewTab: o = !0 } = t, s = _(null);
|
|
11
11
|
return p(() => {
|
|
12
12
|
s.value?.destroy(), s.value = null;
|
|
@@ -14,7 +14,7 @@ function C(t) {
|
|
|
14
14
|
lightbox: s,
|
|
15
15
|
init: async () => {
|
|
16
16
|
if (!n.value) return;
|
|
17
|
-
e(
|
|
17
|
+
e(S), j();
|
|
18
18
|
let { default: t } = await import("photoswipe/lightbox");
|
|
19
19
|
s.value = new t({
|
|
20
20
|
gallery: n.value,
|
|
@@ -34,7 +34,7 @@ function C(t) {
|
|
|
34
34
|
html: "<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm11-3v8h-2V6.413l-7.793 7.794l-1.414-1.414L17.585 5H13V3z\"/></svg>",
|
|
35
35
|
title: "Open in new tab",
|
|
36
36
|
onClick: (e, t, n) => {
|
|
37
|
-
let r =
|
|
37
|
+
let r = E(n);
|
|
38
38
|
r && window.open(r, "_blank", "noopener,noreferrer");
|
|
39
39
|
}
|
|
40
40
|
}), a && e.registerElement({
|
|
@@ -44,15 +44,15 @@ function C(t) {
|
|
|
44
44
|
html: "<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M3 19h18v2H3zm10-5.828L19.071 7.1l1.414 1.414L12 17L3.515 8.515L4.929 7.1L11 13.173V2h2z\"/></svg>",
|
|
45
45
|
title: "Download",
|
|
46
46
|
onClick: (e, t, n) => {
|
|
47
|
-
let r =
|
|
48
|
-
r &&
|
|
47
|
+
let r = E(n);
|
|
48
|
+
r && D(r);
|
|
49
49
|
}
|
|
50
50
|
}));
|
|
51
51
|
}), s.value.init();
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function T() {
|
|
56
56
|
let e = g(/* @__PURE__ */ new Map());
|
|
57
57
|
return {
|
|
58
58
|
preload: (t) => {
|
|
@@ -73,20 +73,20 @@ function w() {
|
|
|
73
73
|
}, t.src = n.url;
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
|
-
getSize: (t) => e.value.get(t) ??
|
|
76
|
+
getSize: (t) => e.value.get(t) ?? C
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
function T(e) {
|
|
80
|
-
return e.currSlide?.data?.src ?? e.currSlide?.data?.element?.querySelector("img")?.getAttribute("src") ?? e.currSlide?.data?.element?.querySelector("source")?.getAttribute("srcset") ?? e.currSlide?.data?.element?.getAttribute("src") ?? void 0;
|
|
81
|
-
}
|
|
82
79
|
function E(e) {
|
|
83
|
-
|
|
84
|
-
n.href = t, n.target = "_blank", n.rel = "noopener noreferrer", n.download = O(e), document.body.appendChild(n), n.click(), document.body.removeChild(n);
|
|
80
|
+
return e.currSlide?.data?.src ?? e.currSlide?.data?.element?.querySelector("img")?.getAttribute("src") ?? e.currSlide?.data?.element?.querySelector("source")?.getAttribute("srcset") ?? e.currSlide?.data?.element?.getAttribute("src") ?? void 0;
|
|
85
81
|
}
|
|
86
82
|
function D(e) {
|
|
87
|
-
|
|
83
|
+
let t = O(e), n = document.createElement("a");
|
|
84
|
+
n.href = t, n.target = "_blank", n.rel = "noopener noreferrer", n.download = k(e), document.body.appendChild(n), n.click(), document.body.removeChild(n);
|
|
88
85
|
}
|
|
89
86
|
function O(e) {
|
|
87
|
+
return e.replace(/\/view(\?|$)/, "/download$1");
|
|
88
|
+
}
|
|
89
|
+
function k(e) {
|
|
90
90
|
if (e.startsWith("data:image/svg+xml")) return "diagram.svg";
|
|
91
91
|
if (e.startsWith("data:")) return `image.${e.split(":")[1].split(";")[0].split("/")[1] || "bin"}`;
|
|
92
92
|
try {
|
|
@@ -96,10 +96,10 @@ function O(e) {
|
|
|
96
96
|
return "image";
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
var
|
|
100
|
-
function
|
|
101
|
-
if (
|
|
102
|
-
|
|
99
|
+
var A = !1;
|
|
100
|
+
function j() {
|
|
101
|
+
if (A) return;
|
|
102
|
+
A = !0;
|
|
103
103
|
let e = document.createElement("style");
|
|
104
104
|
e.textContent = [
|
|
105
105
|
".pswp__counter { font-family: sans-serif; }",
|
|
@@ -114,27 +114,27 @@ function A() {
|
|
|
114
114
|
}
|
|
115
115
|
//#endregion
|
|
116
116
|
//#region ../../packages/components/src/chat/PkChatbotFilePreview.vue?vue&type=script&setup=true&lang.ts
|
|
117
|
-
var
|
|
117
|
+
var M = [
|
|
118
118
|
"href",
|
|
119
119
|
"data-pswp-src",
|
|
120
120
|
"data-pswp-width",
|
|
121
121
|
"data-pswp-height",
|
|
122
122
|
"data-pswp-caption",
|
|
123
123
|
"aria-label"
|
|
124
|
-
],
|
|
124
|
+
], N = ["src", "alt"], P = {
|
|
125
125
|
key: 0,
|
|
126
126
|
class: "pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay"
|
|
127
|
-
},
|
|
127
|
+
}, F = {
|
|
128
|
+
key: 1,
|
|
129
|
+
class: "pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay pk-chatbot-file-preview__status--error"
|
|
130
|
+
}, I = {
|
|
128
131
|
key: 0,
|
|
129
132
|
class: "pk-chatbot-file-preview__caption"
|
|
130
|
-
},
|
|
131
|
-
key: 1,
|
|
132
|
-
class: "pk-chatbot-file-preview__meta"
|
|
133
|
-
}, L = ["title"], R = ["title", "aria-label"], z = { class: "pk-chatbot-file-preview__body" }, B = ["title"], V = { class: "pk-chatbot-file-preview__meta" }, H = ["title"], U = [
|
|
133
|
+
}, L = ["title"], R = { class: "pk-chatbot-file-preview__meta" }, z = ["title"], B = ["title", "aria-label"], V = { class: "pk-chatbot-file-preview__body" }, H = ["title"], U = { class: "pk-chatbot-file-preview__meta" }, W = ["title"], G = [
|
|
134
134
|
"href",
|
|
135
135
|
"title",
|
|
136
136
|
"aria-label"
|
|
137
|
-
],
|
|
137
|
+
], K = ["title", "aria-label"], q = /* @__PURE__ */ u({
|
|
138
138
|
__name: "PkChatbotFilePreview",
|
|
139
139
|
props: {
|
|
140
140
|
mediaType: {},
|
|
@@ -151,7 +151,7 @@ var j = [
|
|
|
151
151
|
let u = e, p = r(() => u.mediaType.startsWith("image/")), _ = r(() => {
|
|
152
152
|
let e = u.filename ?? "", t = e.lastIndexOf(".");
|
|
153
153
|
return t > 0 ? e.slice(t + 1).toLowerCase() : "";
|
|
154
|
-
}),
|
|
154
|
+
}), S = r(() => u.mediaType.split("/")[1]?.split(";")[0] ?? ""), C = [
|
|
155
155
|
{
|
|
156
156
|
test: /pdf/,
|
|
157
157
|
kind: {
|
|
@@ -226,13 +226,13 @@ var j = [
|
|
|
226
226
|
}
|
|
227
227
|
], T = r(() => {
|
|
228
228
|
let e = `${u.mediaType} ${_.value}`;
|
|
229
|
-
for (let { test: t, kind: n } of
|
|
229
|
+
for (let { test: t, kind: n } of C) if (t.test(e)) return n;
|
|
230
230
|
return {
|
|
231
231
|
icon: "ri:file-line",
|
|
232
232
|
accent: "#64748b",
|
|
233
233
|
label: "File"
|
|
234
234
|
};
|
|
235
|
-
}), E = r(() => (_.value ||
|
|
235
|
+
}), E = r(() => (_.value || S.value || T.value.label).toUpperCase()), D = r(() => {
|
|
236
236
|
let e = u.size;
|
|
237
237
|
if (e === void 0 || e < 0) return;
|
|
238
238
|
if (e < 1024) return `${e} B`;
|
|
@@ -244,18 +244,23 @@ var j = [
|
|
|
244
244
|
], n = e / 1024, r = 0;
|
|
245
245
|
for (; n >= 1024 && r < t.length - 1;) n /= 1024, r += 1;
|
|
246
246
|
return `${n < 10 ? n.toFixed(1) : Math.round(n)} ${t[r]}`;
|
|
247
|
-
}), O = g(), k = (e) => {
|
|
247
|
+
}), O = g("loading"), k = g(), A = (e) => {
|
|
248
248
|
let t = e.target;
|
|
249
|
-
t.naturalWidth && t.naturalHeight && (
|
|
249
|
+
t.naturalWidth && t.naturalHeight && (k.value = {
|
|
250
250
|
width: t.naturalWidth,
|
|
251
251
|
height: t.naturalHeight
|
|
252
|
-
});
|
|
253
|
-
},
|
|
254
|
-
|
|
252
|
+
}), O.value = "loaded";
|
|
253
|
+
}, j = () => {
|
|
254
|
+
O.value = "error";
|
|
255
|
+
}, q = r(() => k.value ?? X), J = r(() => [k.value && `${k.value.width}×${k.value.height}`, D.value].filter(Boolean)), Y = r(() => [E.value, D.value].filter(Boolean)), X = {
|
|
256
|
+
width: 1200,
|
|
257
|
+
height: 800
|
|
258
|
+
}, Z = g(), { init: Q } = w({
|
|
259
|
+
gallery: Z,
|
|
255
260
|
loop: !1
|
|
256
261
|
});
|
|
257
262
|
return m(async () => {
|
|
258
|
-
p.value &&
|
|
263
|
+
p.value && await Q();
|
|
259
264
|
}), (r, u) => {
|
|
260
265
|
let m = t;
|
|
261
266
|
return p.value ? (h(), o("figure", {
|
|
@@ -264,39 +269,41 @@ var j = [
|
|
|
264
269
|
}, [
|
|
265
270
|
s("div", {
|
|
266
271
|
ref_key: "galleryRef",
|
|
267
|
-
ref:
|
|
272
|
+
ref: Z,
|
|
268
273
|
class: "pk-chatbot-file-preview__thumb-wrap"
|
|
269
274
|
}, [s("a", {
|
|
270
275
|
href: e.url,
|
|
271
276
|
"data-pswp-src": e.url,
|
|
272
|
-
"data-pswp-width":
|
|
273
|
-
"data-pswp-height":
|
|
277
|
+
"data-pswp-width": q.value.width,
|
|
278
|
+
"data-pswp-height": q.value.height,
|
|
274
279
|
"data-pswp-caption": e.filename ?? "",
|
|
275
280
|
class: "pk-chatbot-file-preview__thumb-link",
|
|
276
281
|
"aria-label": e.filename ?? r.$t("label.file")
|
|
277
|
-
}, [s("img", {
|
|
282
|
+
}, [b(s("img", {
|
|
278
283
|
src: e.url,
|
|
279
284
|
alt: e.filename,
|
|
285
|
+
decoding: "async",
|
|
280
286
|
class: "pk-chatbot-file-preview__thumb",
|
|
281
|
-
onLoad:
|
|
282
|
-
|
|
283
|
-
|
|
287
|
+
onLoad: A,
|
|
288
|
+
onError: j
|
|
289
|
+
}, null, 40, N), [[y, O.value === "loaded"]])], 8, M), e.loading || O.value === "loading" ? (h(), o("span", P, [l(m, { name: "line-md:loading-loop" })])) : O.value === "error" ? (h(), o("span", F, [l(m, { name: "ri:image-2-line" })])) : a("", !0)], 512),
|
|
290
|
+
e.compact ? a("", !0) : (h(), o("figcaption", I, [e.filename ? (h(), o("span", {
|
|
284
291
|
key: 0,
|
|
285
292
|
class: "pk-chatbot-file-preview__name",
|
|
286
293
|
title: e.filename
|
|
287
|
-
}, v(e.filename), 9,
|
|
294
|
+
}, v(e.filename), 9, L)) : a("", !0), s("span", R, [e.error ? (h(), o("span", {
|
|
288
295
|
key: 0,
|
|
289
296
|
class: "pk-chatbot-file-preview__error",
|
|
290
297
|
title: e.error
|
|
291
|
-
}, [l(m, { name: "ri:error-warning-line" }), c(" " + v(e.error), 1)], 8,
|
|
298
|
+
}, [l(m, { name: "ri:error-warning-line" }), c(" " + v(e.error), 1)], 8, z)) : (h(), o(n, { key: 1 }, [c(v(J.value.join(" · ")), 1)], 64))])])),
|
|
292
299
|
e.removable && !e.loading ? (h(), o("button", {
|
|
293
300
|
key: 1,
|
|
294
301
|
type: "button",
|
|
295
302
|
class: "pk-chatbot-file-preview__remove",
|
|
296
303
|
title: r.$t("action.remove"),
|
|
297
304
|
"aria-label": r.$t("action.remove"),
|
|
298
|
-
onClick: u[0] ||=
|
|
299
|
-
}, [l(m, { name: "ri:close-line" })], 8,
|
|
305
|
+
onClick: u[0] ||= x((e) => r.$emit("remove"), ["prevent"])
|
|
306
|
+
}, [l(m, { name: "ri:close-line" })], 8, B)) : a("", !0)
|
|
300
307
|
], 2)) : (h(), o("div", {
|
|
301
308
|
key: 1,
|
|
302
309
|
class: d(["pk-chatbot-file-preview pk-chatbot-file-preview--doc", {
|
|
@@ -316,15 +323,15 @@ var j = [
|
|
|
316
323
|
name: T.value.icon,
|
|
317
324
|
class: "pk-chatbot-file-preview__icon"
|
|
318
325
|
}, null, 8, ["name"]))], 4),
|
|
319
|
-
s("span",
|
|
326
|
+
s("span", V, [e.filename ? (h(), o("span", {
|
|
320
327
|
key: 0,
|
|
321
328
|
class: "pk-chatbot-file-preview__name",
|
|
322
329
|
title: e.filename
|
|
323
|
-
}, v(e.filename), 9,
|
|
330
|
+
}, v(e.filename), 9, H)) : a("", !0), s("span", U, [e.error ? (h(), o("span", {
|
|
324
331
|
key: 0,
|
|
325
332
|
class: "pk-chatbot-file-preview__error",
|
|
326
333
|
title: e.error
|
|
327
|
-
}, [l(m, { name: "ri:error-warning-line" }), c(" " + v(e.error), 1)], 8,
|
|
334
|
+
}, [l(m, { name: "ri:error-warning-line" }), c(" " + v(e.error), 1)], 8, W)) : (h(), o(n, { key: 1 }, [c(v(Y.value.join(" · ")), 1)], 64))])]),
|
|
328
335
|
!e.loading && !e.error && !e.compact ? (h(), o("a", {
|
|
329
336
|
key: 0,
|
|
330
337
|
href: e.url,
|
|
@@ -333,7 +340,7 @@ var j = [
|
|
|
333
340
|
class: "pk-chatbot-file-preview__open",
|
|
334
341
|
title: r.$t("action.download"),
|
|
335
342
|
"aria-label": `${r.$t("action.download")}${e.filename ? ` — ${e.filename}` : ""}`
|
|
336
|
-
}, [l(m, { name: "ri:download-2-line" })], 8,
|
|
343
|
+
}, [l(m, { name: "ri:download-2-line" })], 8, G)) : a("", !0),
|
|
337
344
|
e.removable && !e.loading ? (h(), o("button", {
|
|
338
345
|
key: 1,
|
|
339
346
|
type: "button",
|
|
@@ -341,12 +348,12 @@ var j = [
|
|
|
341
348
|
title: r.$t("action.remove"),
|
|
342
349
|
"aria-label": r.$t("action.remove"),
|
|
343
350
|
onClick: u[1] ||= (e) => r.$emit("remove")
|
|
344
|
-
}, [l(m, { name: "ri:close-line" })], 10,
|
|
351
|
+
}, [l(m, { name: "ri:close-line" })], 10, K)) : a("", !0)
|
|
345
352
|
], 2));
|
|
346
353
|
};
|
|
347
354
|
}
|
|
348
355
|
});
|
|
349
356
|
//#endregion
|
|
350
|
-
export {
|
|
357
|
+
export { T as n, w as r, q as t };
|
|
351
358
|
|
|
352
|
-
//# sourceMappingURL=PkChatbotFilePreview-
|
|
359
|
+
//# sourceMappingURL=PkChatbotFilePreview-Bf1bdZn8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkChatbotFilePreview-Bf1bdZn8.js","names":["$t","$emit"],"sources":["../../../../packages/components/src/composables/useLightbox.ts","../../../../packages/components/src/chat/PkChatbotFilePreview.vue","../../../../packages/components/src/chat/PkChatbotFilePreview.vue"],"sourcesContent":["import {\n onBeforeUnmount,\n ref,\n shallowRef,\n type Ref,\n type ShallowRef,\n} from 'vue'\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox'\nimport type PhotoSwipe from 'photoswipe'\nimport { loadCdnCss } from 'utils'\n\nconst PHOTOSWIPE_CSS =\n 'https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css'\n\nconst DEFAULT_IMAGE_SIZE = { width: 1200, height: 800 }\n\nexport interface LightboxImage {\n url: string\n caption?: string\n alt?: string\n /** Natural width in px — used by PhotoSwipe for proper sizing. */\n width?: number\n /** Natural height in px — used by PhotoSwipe for proper sizing. */\n height?: number\n}\n\nexport interface LightboxOptions {\n /** Container element whose child anchors are the gallery items */\n gallery: Ref<HTMLElement | undefined>\n /** CSS selector for gallery items inside the container (default: `'a[data-pswp-src]'`) */\n children?: string\n loop?: boolean\n /** Show a download button in the lightbox toolbar */\n downloadable?: boolean\n /** Show an open-in-new-tab button in the lightbox toolbar */\n openInNewTab?: boolean\n}\n\nexport interface UseLightboxReturn {\n lightbox: ShallowRef<PhotoSwipeLightbox | null>\n /** Initialises PhotoSwipe. Call this inside `onMounted`. */\n init: () => Promise<void>\n}\n\n/**\n * Encapsulates PhotoSwipe 5 initialisation, toolbar customisation, and lifecycle cleanup.\n * CSS is injected into `document.head` so the overlay works in both regular DOM and Shadow DOM.\n *\n * Usage:\n * ```ts\n * const { init } = useLightbox({ gallery: galleryRef, downloadable: true })\n * onMounted(init)\n * ```\n */\nexport function useLightbox(options: LightboxOptions): UseLightboxReturn {\n const {\n gallery,\n children = 'a[data-pswp-src]',\n loop = true,\n downloadable = true,\n openInNewTab = true,\n } = options\n\n const lightbox = shallowRef<PhotoSwipeLightbox | null>(null)\n\n const init = async () => {\n if (!gallery.value) {\n return\n }\n\n // PhotoSwipe renders its overlay into document.body, so CSS must be in\n // document.head — not inside a shadow root.\n loadCdnCss(PHOTOSWIPE_CSS)\n injectPhotoSwipeOverrides()\n\n const { default: PhotoSwipeLightbox } =\n await import('photoswipe/lightbox')\n\n lightbox.value = new PhotoSwipeLightbox({\n gallery: gallery.value,\n children,\n pswpModule: () => import('photoswipe'),\n loop,\n arrowPrevSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"/></svg>',\n arrowNextSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"/></svg>',\n closeSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"/></svg>',\n zoomSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g class=\"pswp__icn--zoom-in\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM10 10V7h2v3h3v2h-3v3h-2v-3H7v-2z\"/></g><g class=\"pswp__icn--zoom-out\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM7 10h8v2H7z\"/></g></svg>',\n })\n\n if (openInNewTab || downloadable) {\n lightbox.value.on('uiRegister', () => {\n const ui = lightbox.value!.pswp?.ui\n if (!ui) {\n return\n }\n\n if (openInNewTab) {\n ui.registerElement({\n name: 'open-in-new-tab-button',\n order: 8,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm11-3v8h-2V6.413l-7.793 7.794l-1.414-1.414L17.585 5H13V3z\"/></svg>',\n title: 'Open in new tab',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n window.open(\n url,\n '_blank',\n 'noopener,noreferrer',\n )\n }\n },\n })\n }\n\n if (downloadable) {\n ui.registerElement({\n name: 'download-button',\n order: 9,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M3 19h18v2H3zm10-5.828L19.071 7.1l1.414 1.414L12 17L3.515 8.515L4.929 7.1L11 13.173V2h2z\"/></svg>',\n title: 'Download',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n downloadImage(url)\n }\n },\n })\n }\n })\n }\n\n lightbox.value.init()\n }\n\n onBeforeUnmount(() => {\n lightbox.value?.destroy()\n lightbox.value = null\n })\n\n return { lightbox, init }\n}\n\n// ---------------------------------------------------------------------------\n// Image size preloading\n// ---------------------------------------------------------------------------\n\nexport interface UseImageSizesReturn {\n preload: (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => void\n getSize: (url: string) => { width: number; height: number }\n}\n\n/**\n * Preloads natural image dimensions so PhotoSwipe can size its slides correctly.\n * When `width`/`height` are already provided they are used as-is;\n * otherwise the image is loaded in the background to read `naturalWidth`/`naturalHeight`.\n */\nexport function useImageSizes(): UseImageSizesReturn {\n const sizes = ref(new Map<string, { width: number; height: number }>())\n\n const preload = (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => {\n for (const image of images) {\n if (image.width && image.height) {\n sizes.value.set(image.url, {\n width: image.width,\n height: image.height,\n })\n continue\n }\n const img = new Image()\n img.onload = () => {\n sizes.value.set(image.url, {\n width: img.naturalWidth,\n height: img.naturalHeight,\n })\n }\n img.src = image.url\n }\n }\n\n const getSize = (url: string) => sizes.value.get(url) ?? DEFAULT_IMAGE_SIZE\n\n return { preload, getSize }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getCurrentSlideUrl(pswp: PhotoSwipe): string | undefined {\n return (\n pswp.currSlide?.data?.src ??\n pswp.currSlide?.data?.element\n ?.querySelector('img')\n ?.getAttribute('src') ??\n pswp.currSlide?.data?.element\n ?.querySelector('source')\n ?.getAttribute('srcset') ??\n pswp.currSlide?.data?.element?.getAttribute('src') ??\n undefined\n )\n}\n\n/**\n * Triggers a client-side download for an image URL.\n *\n * For backend media URLs (.../media/:file/view), navigates to the\n * corresponding /download endpoint which redirects to an Azure SAS URL\n * with `Content-Disposition: attachment` — no CORS issues.\n *\n * For blob: URLs (in-session uploads), uses the fetch → blob approach.\n *\n * For data: URLs (inline SVGs, etc.), use the download attribute.\n *\n * Falls back to opening in a new tab for all other cases.\n */\nfunction downloadImage(url: string): void {\n const downloadUrl = toDownloadUrl(url)\n\n const anchor = document.createElement('a')\n anchor.href = downloadUrl\n anchor.target = '_blank'\n anchor.rel = 'noopener noreferrer'\n // `download` attribute works for same-origin, data: and blob: URLs; for\n // cross-origin it is ignored but the browser still follows Content-Disposition.\n anchor.download = getFilenameFromUrl(url)\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n}\n\n/**\n * Converts a `/view` media URL to its `/download` counterpart.\n * Leaves blob:, data: and all other URLs untouched.\n */\nfunction toDownloadUrl(url: string): string {\n return url.replace(/\\/view(\\?|$)/, '/download$1')\n}\n\nfunction getFilenameFromUrl(url: string): string {\n if (url.startsWith('data:image/svg+xml')) {\n return 'diagram.svg'\n }\n if (url.startsWith('data:')) {\n const mime = url.split(':')[1].split(';')[0]\n const ext = mime.split('/')[1] || 'bin'\n return `image.${ext}`\n }\n try {\n const pathname = new URL(url).pathname\n const name = pathname.split('/').pop()\n return name && name.includes('.') ? name : 'image'\n } catch {\n return 'image'\n }\n}\n\nlet overridesInjected = false\n\n/**\n * Injects a one-time `<style>` into `document.head` that raises\n * PhotoSwipe's z-index above any host UI (e.g. floating chat widgets\n * that use `z-index: 2147483647`).\n */\nfunction injectPhotoSwipeOverrides(): void {\n if (overridesInjected) {\n return\n }\n overridesInjected = true\n const style = document.createElement('style')\n style.textContent = [\n '.pswp__counter { font-family: sans-serif; }',\n '.pswp { z-index: 2147483647 !important; }',\n '.pswp__icn { width: 20px; height: 20px; }',\n '.pswp__button { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; }',\n '.pswp__icn--zoom-out { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-in { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-out { display: block; }',\n '.pswp__button--arrow .pswp__icn {left: auto; right: auto; width: 40px; height: 40px; transform: none; margin-top: -20px; }',\n ].join(' ')\n document.head.appendChild(style)\n}\n","<script lang=\"ts\" setup>\n import { computed, ref, onMounted } from 'vue'\n import { useLightbox } from '../composables/useLightbox'\n\n const props = defineProps<{\n mediaType: string\n url: string\n filename?: string\n /** Size in bytes, when known (e.g. local uploads). */\n size?: number\n loading?: boolean\n error?: string\n removable?: boolean\n /**\n * Dense layout for the composer: a small square thumbnail / slim row,\n * without the metadata caption. The full card is reserved for the\n * message log where the details matter.\n */\n compact?: boolean\n }>()\n\n defineEmits<{\n remove: []\n }>()\n\n const isImage = computed(() => props.mediaType.startsWith('image/'))\n\n // --- File-type identity (icon + accent + human kind label) ---\n\n const extension = computed(() => {\n const name = props.filename ?? ''\n const dot = name.lastIndexOf('.')\n return dot > 0 ? name.slice(dot + 1).toLowerCase() : ''\n })\n\n // mediaType subtype, e.g. \"pdf\" from \"application/pdf\"\n const subtype = computed(\n () => props.mediaType.split('/')[1]?.split(';')[0] ?? '',\n )\n\n type FileKind = {\n icon: string\n // CSS color driving the icon glyph + tile tint\n accent: string\n label: string\n }\n\n const KINDS: Array<{ test: RegExp; kind: FileKind }> = [\n {\n test: /pdf/,\n kind: {\n icon: 'ri:file-pdf-2-line',\n accent: '#e2483d',\n label: 'PDF',\n },\n },\n {\n // Match Word specifically: the generic `document` substring also\n // appears in the XLSX/PPTX OOXML mime types (…officedocument…), so\n // matching it here would mis-label spreadsheets/decks as Word.\n test: /msword|wordprocessingml/,\n kind: {\n icon: 'ri:file-word-2-line',\n accent: '#2b7de9',\n label: 'Word',\n },\n },\n {\n test: /sheet|excel|csv/,\n kind: {\n icon: 'ri:file-excel-2-line',\n accent: '#1f9d57',\n label: 'Spreadsheet',\n },\n },\n {\n test: /presentation|powerpoint/,\n kind: {\n icon: 'ri:file-ppt-2-line',\n accent: '#d98324',\n label: 'Presentation',\n },\n },\n {\n test: /zip|compressed|x-7z|x-rar|x-tar|gzip/,\n kind: {\n icon: 'ri:file-zip-line',\n accent: '#c08a1e',\n label: 'Archive',\n },\n },\n {\n test: /^audio\\//,\n kind: {\n icon: 'ri:file-music-line',\n accent: '#8b5cf6',\n label: 'Audio',\n },\n },\n {\n test: /^video\\//,\n kind: {\n icon: 'ri:film-line',\n accent: '#6366f1',\n label: 'Video',\n },\n },\n {\n test: /json|javascript|typescript|xml|html|x-sh|x-python/,\n kind: {\n icon: 'ri:file-code-line',\n accent: '#0d9488',\n label: 'Code',\n },\n },\n {\n test: /^text\\//,\n kind: {\n icon: 'ri:file-text-line',\n accent: '#64748b',\n label: 'Text',\n },\n },\n ]\n\n const fileKind = computed<FileKind>(() => {\n const haystack = `${props.mediaType} ${extension.value}`\n for (const { test, kind } of KINDS) {\n if (test.test(haystack)) {\n return kind\n }\n }\n return {\n icon: 'ri:file-line',\n accent: '#64748b',\n label: 'File',\n }\n })\n\n // Short type tag shown in the meta line: prefer the real extension, fall\n // back to the mime subtype, then the generic kind label.\n const typeTag = computed(() =>\n (\n extension.value ||\n subtype.value ||\n fileKind.value.label\n ).toUpperCase(),\n )\n\n // --- Size & dimensions ---\n\n const formattedSize = computed(() => {\n const bytes = props.size\n if (bytes === undefined || bytes < 0) {\n return undefined\n }\n if (bytes < 1024) {\n return `${bytes} B`\n }\n const units = ['KB', 'MB', 'GB', 'TB']\n let value = bytes / 1024\n let unitIndex = 0\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024\n unitIndex += 1\n }\n return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unitIndex]}`\n })\n\n // Thumbnail load lifecycle. Driving the spinner and the error fallback\n // off the real <img> events (not a second background fetch) means the\n // image is requested exactly once and reuses the browser cache on any\n // later re-render, instead of re-downloading every time the message list\n // repaints.\n type ThumbStatus = 'loading' | 'loaded' | 'error'\n const thumbStatus = ref<ThumbStatus>('loading')\n\n // Natural pixel dimensions, captured once the thumbnail decodes. Doubles\n // as the size hint PhotoSwipe needs for its slide (falls back until known).\n const dimensions = ref<{ width: number; height: number }>()\n const onImageLoad = (event: Event) => {\n const img = event.target as HTMLImageElement\n if (img.naturalWidth && img.naturalHeight) {\n dimensions.value = {\n width: img.naturalWidth,\n height: img.naturalHeight,\n }\n }\n thumbStatus.value = 'loaded'\n }\n const onImageError = () => {\n thumbStatus.value = 'error'\n }\n\n const pswpSize = computed(() => dimensions.value ?? DEFAULT_PSWP_SIZE)\n\n // Meta fragments joined with \" · \" for the caption / doc subtitle.\n const imageMeta = computed(() =>\n [\n dimensions.value &&\n `${dimensions.value.width}×${dimensions.value.height}`,\n formattedSize.value,\n ].filter(Boolean),\n )\n const docMeta = computed(() =>\n [typeTag.value, formattedSize.value].filter(Boolean),\n )\n\n // --- Lightbox ---\n\n // Slide size PhotoSwipe assumes before the real dimensions are known.\n const DEFAULT_PSWP_SIZE = { width: 1200, height: 800 }\n\n const galleryRef = ref<HTMLElement>()\n const { init } = useLightbox({ gallery: galleryRef, loop: false })\n\n onMounted(async () => {\n if (!isImage.value) {\n return\n }\n await init()\n })\n</script>\n\n<template>\n <!-- Image attachment: a thumbnail tile with a metadata caption -->\n <figure\n v-if=\"isImage\"\n class=\"pk-chatbot-file-preview pk-chatbot-file-preview--image\"\n :class=\"{ 'pk-chatbot-file-preview--compact': compact }\">\n <div ref=\"galleryRef\" class=\"pk-chatbot-file-preview__thumb-wrap\">\n <a\n :href=\"url\"\n :data-pswp-src=\"url\"\n :data-pswp-width=\"pswpSize.width\"\n :data-pswp-height=\"pswpSize.height\"\n :data-pswp-caption=\"filename ?? ''\"\n class=\"pk-chatbot-file-preview__thumb-link\"\n :aria-label=\"filename ?? $t('label.file')\">\n <img\n v-show=\"thumbStatus === 'loaded'\"\n :src=\"url\"\n :alt=\"filename\"\n decoding=\"async\"\n class=\"pk-chatbot-file-preview__thumb\"\n @load=\"onImageLoad\"\n @error=\"onImageError\" />\n </a>\n <!-- Spinner until the thumbnail decodes (or while an upload is in\n flight); a fixed box keeps this from shifting the layout. -->\n <span\n v-if=\"loading || thumbStatus === 'loading'\"\n class=\"pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay\">\n <VvIcon name=\"line-md:loading-loop\" />\n </span>\n <!-- Failed to load: a quiet icon instead of the browser's broken\n image glyph. -->\n <span\n v-else-if=\"thumbStatus === 'error'\"\n class=\"pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay pk-chatbot-file-preview__status--error\">\n <VvIcon name=\"ri:image-2-line\" />\n </span>\n </div>\n <figcaption v-if=\"!compact\" class=\"pk-chatbot-file-preview__caption\">\n <span\n v-if=\"filename\"\n class=\"pk-chatbot-file-preview__name\"\n :title=\"filename\"\n >{{ filename }}</span\n >\n <span class=\"pk-chatbot-file-preview__meta\">\n <span\n v-if=\"error\"\n class=\"pk-chatbot-file-preview__error\"\n :title=\"error\">\n <VvIcon name=\"ri:error-warning-line\" />\n {{ error }}\n </span>\n <template v-else>{{ imageMeta.join(' · ') }}</template>\n </span>\n </figcaption>\n <button\n v-if=\"removable && !loading\"\n type=\"button\"\n class=\"pk-chatbot-file-preview__remove\"\n :title=\"$t('action.remove')\"\n :aria-label=\"$t('action.remove')\"\n @click.prevent=\"$emit('remove')\">\n <VvIcon name=\"ri:close-line\" />\n </button>\n </figure>\n\n <!-- Document attachment: an icon tile + name + type · size -->\n <div\n v-else\n class=\"pk-chatbot-file-preview pk-chatbot-file-preview--doc\"\n :class=\"{\n 'pk-chatbot-file-preview--error': error,\n 'pk-chatbot-file-preview--compact': compact,\n }\">\n <span\n class=\"pk-chatbot-file-preview__icon-tile\"\n :style=\"{ '--file-accent': fileKind.accent }\">\n <VvIcon\n v-if=\"loading\"\n name=\"line-md:loading-loop\"\n class=\"pk-chatbot-file-preview__icon\" />\n <VvIcon\n v-else\n :name=\"fileKind.icon\"\n class=\"pk-chatbot-file-preview__icon\" />\n </span>\n <span class=\"pk-chatbot-file-preview__body\">\n <span\n v-if=\"filename\"\n class=\"pk-chatbot-file-preview__name\"\n :title=\"filename\"\n >{{ filename }}</span\n >\n <span class=\"pk-chatbot-file-preview__meta\">\n <span\n v-if=\"error\"\n class=\"pk-chatbot-file-preview__error\"\n :title=\"error\">\n <VvIcon name=\"ri:error-warning-line\" />\n {{ error }}\n </span>\n <template v-else>{{ docMeta.join(' · ') }}</template>\n </span>\n </span>\n <a\n v-if=\"!loading && !error && !compact\"\n :href=\"url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-file-preview__open\"\n :title=\"$t('action.download')\"\n :aria-label=\"`${$t('action.download')}${filename ? ` — ${filename}` : ''}`\">\n <VvIcon name=\"ri:download-2-line\" />\n </a>\n <button\n v-if=\"removable && !loading\"\n type=\"button\"\n class=\"pk-chatbot-file-preview__remove\"\n :class=\"{ 'pk-chatbot-file-preview__remove--inline': !compact }\"\n :title=\"$t('action.remove')\"\n :aria-label=\"$t('action.remove')\"\n @click=\"$emit('remove')\">\n <VvIcon name=\"ri:close-line\" />\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-file-preview {\n // Concentric radii: outer card and inner tiles share an 8px step.\n --file-radius: var(--rounded-lg, 12px);\n position: relative;\n max-width: 280px;\n background-color: var(--color-surface-1);\n border: 1px solid var(--color-surface-3);\n border-radius: var(--file-radius);\n color: var(--color-word-2);\n font-size: var(--text-12);\n\n &--error {\n border-color: var(--color-danger);\n }\n\n // --- Document card ---\n &--doc {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n padding: var(--spacing-8);\n min-width: 0;\n transition:\n border-color 0.18s var(--ease-out),\n background-color 0.18s var(--ease-out),\n box-shadow 0.18s var(--ease-out);\n\n &:hover {\n border-color: var(--color-surface-4);\n background-color: var(--color-surface-2);\n box-shadow: var(--shadow-sm);\n }\n }\n\n &__icon-tile {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--spacing-36);\n height: var(--spacing-36);\n // One step down from the card radius keeps the nested tile concentric.\n border-radius: var(--rounded-md, 6px);\n // Tint derived from the file-type accent; glyph sits at full accent.\n background-color: color-mix(\n in srgb,\n var(--file-accent) 14%,\n transparent\n );\n color: var(--file-accent);\n }\n\n &__icon {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n\n &__body {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 0;\n flex: 1;\n }\n\n &__open {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--spacing-28);\n height: var(--spacing-28);\n margin-inline-start: var(--spacing-4);\n border-radius: var(--rounded);\n color: var(--color-word-3);\n text-decoration: none;\n opacity: 0;\n transition:\n opacity 0.18s var(--ease-out),\n color 0.18s var(--ease-out),\n background-color 0.18s var(--ease-out);\n\n &:hover {\n background-color: var(--color-surface-3);\n color: var(--color-word-1);\n }\n }\n\n &--doc:hover &__open,\n &--doc:focus-within &__open {\n opacity: 1;\n }\n\n // Touch devices have no hover: keep the open affordance visible.\n @media (hover: none) {\n &--doc &__open {\n opacity: 1;\n }\n }\n\n // --- Image card ---\n &--image {\n display: inline-flex;\n flex-direction: column;\n margin: 0;\n }\n\n &__thumb-wrap {\n position: relative;\n display: flex;\n // Fixed box: the card claims its final footprint before the\n // image decodes, so the message log never shifts on load.\n width: 280px;\n max-width: 100%;\n height: 200px;\n background-color: var(--color-surface);\n border-radius: var(--file-radius);\n overflow: hidden;\n }\n\n &__thumb-link {\n display: flex;\n width: 100%;\n height: 100%;\n cursor: pointer;\n }\n\n &__thumb {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &__caption {\n display: flex;\n flex-direction: column;\n gap: 1px;\n padding: var(--spacing-8);\n min-width: 0;\n }\n\n &__name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: var(--font-medium, 500);\n color: var(--color-word-1);\n }\n\n &__meta {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--text-10);\n line-height: var(--leading-normal);\n // Reserve the line even while empty: image dimensions arrive\n // only after decode and must not grow the caption.\n min-height: 1.4em;\n color: var(--color-word-4);\n // Stable column for the dimensions/size figures.\n font-variant-numeric: tabular-nums;\n }\n\n &__error {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n color: var(--color-danger);\n\n .vv-icon {\n flex-shrink: 0;\n }\n }\n\n &__status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n &--overlay {\n position: absolute;\n inset: 0;\n background-color: color-mix(\n in srgb,\n var(--color-surface-1) 70%,\n transparent\n );\n color: var(--color-word-1);\n }\n\n &--error {\n color: var(--color-word-4);\n }\n }\n\n // --- Remove button (input context) ---\n &__remove {\n position: absolute;\n top: 0;\n right: 0;\n transform: translate(50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n // Visible glyph is 18px but the hit area stays a comfortable 28px.\n width: var(--spacing-28);\n height: var(--spacing-28);\n padding: 0;\n border: none;\n border-radius: var(--rounded-full, 9999px);\n background-color: color-mix(\n in srgb,\n var(--color-surface-1) 85%,\n transparent\n );\n color: var(--color-word-2);\n cursor: pointer;\n line-height: 1;\n box-shadow: var(--shadow-sm);\n transition:\n background-color 0.18s var(--ease-out),\n color 0.18s var(--ease-out),\n scale 0.12s var(--ease-out);\n\n &:hover {\n background-color: var(--color-surface-2);\n color: var(--color-word-1);\n }\n\n &:active {\n scale: 0.96;\n }\n\n // Inside the document row the button rides inline, not overlaid\n // (size is inherited from the base).\n &--inline {\n position: static;\n flex-shrink: 0;\n box-shadow: none;\n background-color: transparent;\n color: var(--color-word-4);\n\n &:hover {\n background-color: var(--color-surface-3);\n color: var(--color-word-1);\n }\n }\n }\n\n // --- Compact (composer) chips ---\n // ChatGPT/Gemini-style: every attachment is the SAME height and carries\n // an always-visible round remove control in the top-right corner — no\n // hover-revealed actions, no size mismatch between image and file chips.\n &--compact {\n // Shared chip height so image and file chips align in the row.\n --chip-size: var(--spacing-56);\n max-width: 240px;\n\n &.pk-chatbot-file-preview--image {\n width: var(--chip-size);\n height: var(--chip-size);\n border-radius: var(--rounded-md, 6px);\n }\n\n // Fill the square; the root's `overflow: hidden` rounds the corners.\n .pk-chatbot-file-preview__thumb-wrap,\n .pk-chatbot-file-preview__thumb-link {\n width: 100%;\n height: 100%;\n }\n\n &.pk-chatbot-file-preview--doc {\n height: var(--chip-size);\n gap: var(--spacing-8);\n padding: var(--spacing-8);\n // Reserve room so the corner remove button never overlaps the\n // name/meta text.\n padding-inline-end: var(--spacing-28);\n }\n\n // Square icon tile that fills the chip height, so file chips read at\n // the same scale as image thumbnails.\n .pk-chatbot-file-preview__icon-tile {\n align-self: stretch;\n width: auto;\n height: auto;\n aspect-ratio: 1;\n }\n\n .pk-chatbot-file-preview__icon {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n\n // Always-visible round remove control in the top-right corner. Sits\n // just inside the chip (an ancestor clips overflow), bigger than before,\n // with an extended hit area for easy tapping.\n &--compact &__remove {\n top: var(--spacing-4);\n right: var(--spacing-4);\n width: var(--spacing-24);\n height: var(--spacing-24);\n border: 1px solid var(--color-surface-4);\n background-color: var(--color-surface);\n color: var(--color-word-1);\n font-size: var(--text-16);\n box-shadow: var(--shadow-sm);\n\n // Comfortable touch/click target beyond the small visible glyph.\n &::after {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--spacing-4));\n }\n\n &:hover {\n background-color: var(--color-surface-2);\n color: var(--color-word-1);\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n &--doc,\n &__open,\n &__remove {\n transition: none;\n }\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import { computed, ref, onMounted } from 'vue'\n import { useLightbox } from '../composables/useLightbox'\n\n const props = defineProps<{\n mediaType: string\n url: string\n filename?: string\n /** Size in bytes, when known (e.g. local uploads). */\n size?: number\n loading?: boolean\n error?: string\n removable?: boolean\n /**\n * Dense layout for the composer: a small square thumbnail / slim row,\n * without the metadata caption. The full card is reserved for the\n * message log where the details matter.\n */\n compact?: boolean\n }>()\n\n defineEmits<{\n remove: []\n }>()\n\n const isImage = computed(() => props.mediaType.startsWith('image/'))\n\n // --- File-type identity (icon + accent + human kind label) ---\n\n const extension = computed(() => {\n const name = props.filename ?? ''\n const dot = name.lastIndexOf('.')\n return dot > 0 ? name.slice(dot + 1).toLowerCase() : ''\n })\n\n // mediaType subtype, e.g. \"pdf\" from \"application/pdf\"\n const subtype = computed(\n () => props.mediaType.split('/')[1]?.split(';')[0] ?? '',\n )\n\n type FileKind = {\n icon: string\n // CSS color driving the icon glyph + tile tint\n accent: string\n label: string\n }\n\n const KINDS: Array<{ test: RegExp; kind: FileKind }> = [\n {\n test: /pdf/,\n kind: {\n icon: 'ri:file-pdf-2-line',\n accent: '#e2483d',\n label: 'PDF',\n },\n },\n {\n // Match Word specifically: the generic `document` substring also\n // appears in the XLSX/PPTX OOXML mime types (…officedocument…), so\n // matching it here would mis-label spreadsheets/decks as Word.\n test: /msword|wordprocessingml/,\n kind: {\n icon: 'ri:file-word-2-line',\n accent: '#2b7de9',\n label: 'Word',\n },\n },\n {\n test: /sheet|excel|csv/,\n kind: {\n icon: 'ri:file-excel-2-line',\n accent: '#1f9d57',\n label: 'Spreadsheet',\n },\n },\n {\n test: /presentation|powerpoint/,\n kind: {\n icon: 'ri:file-ppt-2-line',\n accent: '#d98324',\n label: 'Presentation',\n },\n },\n {\n test: /zip|compressed|x-7z|x-rar|x-tar|gzip/,\n kind: {\n icon: 'ri:file-zip-line',\n accent: '#c08a1e',\n label: 'Archive',\n },\n },\n {\n test: /^audio\\//,\n kind: {\n icon: 'ri:file-music-line',\n accent: '#8b5cf6',\n label: 'Audio',\n },\n },\n {\n test: /^video\\//,\n kind: {\n icon: 'ri:film-line',\n accent: '#6366f1',\n label: 'Video',\n },\n },\n {\n test: /json|javascript|typescript|xml|html|x-sh|x-python/,\n kind: {\n icon: 'ri:file-code-line',\n accent: '#0d9488',\n label: 'Code',\n },\n },\n {\n test: /^text\\//,\n kind: {\n icon: 'ri:file-text-line',\n accent: '#64748b',\n label: 'Text',\n },\n },\n ]\n\n const fileKind = computed<FileKind>(() => {\n const haystack = `${props.mediaType} ${extension.value}`\n for (const { test, kind } of KINDS) {\n if (test.test(haystack)) {\n return kind\n }\n }\n return {\n icon: 'ri:file-line',\n accent: '#64748b',\n label: 'File',\n }\n })\n\n // Short type tag shown in the meta line: prefer the real extension, fall\n // back to the mime subtype, then the generic kind label.\n const typeTag = computed(() =>\n (\n extension.value ||\n subtype.value ||\n fileKind.value.label\n ).toUpperCase(),\n )\n\n // --- Size & dimensions ---\n\n const formattedSize = computed(() => {\n const bytes = props.size\n if (bytes === undefined || bytes < 0) {\n return undefined\n }\n if (bytes < 1024) {\n return `${bytes} B`\n }\n const units = ['KB', 'MB', 'GB', 'TB']\n let value = bytes / 1024\n let unitIndex = 0\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024\n unitIndex += 1\n }\n return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unitIndex]}`\n })\n\n // Thumbnail load lifecycle. Driving the spinner and the error fallback\n // off the real <img> events (not a second background fetch) means the\n // image is requested exactly once and reuses the browser cache on any\n // later re-render, instead of re-downloading every time the message list\n // repaints.\n type ThumbStatus = 'loading' | 'loaded' | 'error'\n const thumbStatus = ref<ThumbStatus>('loading')\n\n // Natural pixel dimensions, captured once the thumbnail decodes. Doubles\n // as the size hint PhotoSwipe needs for its slide (falls back until known).\n const dimensions = ref<{ width: number; height: number }>()\n const onImageLoad = (event: Event) => {\n const img = event.target as HTMLImageElement\n if (img.naturalWidth && img.naturalHeight) {\n dimensions.value = {\n width: img.naturalWidth,\n height: img.naturalHeight,\n }\n }\n thumbStatus.value = 'loaded'\n }\n const onImageError = () => {\n thumbStatus.value = 'error'\n }\n\n const pswpSize = computed(() => dimensions.value ?? DEFAULT_PSWP_SIZE)\n\n // Meta fragments joined with \" · \" for the caption / doc subtitle.\n const imageMeta = computed(() =>\n [\n dimensions.value &&\n `${dimensions.value.width}×${dimensions.value.height}`,\n formattedSize.value,\n ].filter(Boolean),\n )\n const docMeta = computed(() =>\n [typeTag.value, formattedSize.value].filter(Boolean),\n )\n\n // --- Lightbox ---\n\n // Slide size PhotoSwipe assumes before the real dimensions are known.\n const DEFAULT_PSWP_SIZE = { width: 1200, height: 800 }\n\n const galleryRef = ref<HTMLElement>()\n const { init } = useLightbox({ gallery: galleryRef, loop: false })\n\n onMounted(async () => {\n if (!isImage.value) {\n return\n }\n await init()\n })\n</script>\n\n<template>\n <!-- Image attachment: a thumbnail tile with a metadata caption -->\n <figure\n v-if=\"isImage\"\n class=\"pk-chatbot-file-preview pk-chatbot-file-preview--image\"\n :class=\"{ 'pk-chatbot-file-preview--compact': compact }\">\n <div ref=\"galleryRef\" class=\"pk-chatbot-file-preview__thumb-wrap\">\n <a\n :href=\"url\"\n :data-pswp-src=\"url\"\n :data-pswp-width=\"pswpSize.width\"\n :data-pswp-height=\"pswpSize.height\"\n :data-pswp-caption=\"filename ?? ''\"\n class=\"pk-chatbot-file-preview__thumb-link\"\n :aria-label=\"filename ?? $t('label.file')\">\n <img\n v-show=\"thumbStatus === 'loaded'\"\n :src=\"url\"\n :alt=\"filename\"\n decoding=\"async\"\n class=\"pk-chatbot-file-preview__thumb\"\n @load=\"onImageLoad\"\n @error=\"onImageError\" />\n </a>\n <!-- Spinner until the thumbnail decodes (or while an upload is in\n flight); a fixed box keeps this from shifting the layout. -->\n <span\n v-if=\"loading || thumbStatus === 'loading'\"\n class=\"pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay\">\n <VvIcon name=\"line-md:loading-loop\" />\n </span>\n <!-- Failed to load: a quiet icon instead of the browser's broken\n image glyph. -->\n <span\n v-else-if=\"thumbStatus === 'error'\"\n class=\"pk-chatbot-file-preview__status pk-chatbot-file-preview__status--overlay pk-chatbot-file-preview__status--error\">\n <VvIcon name=\"ri:image-2-line\" />\n </span>\n </div>\n <figcaption v-if=\"!compact\" class=\"pk-chatbot-file-preview__caption\">\n <span\n v-if=\"filename\"\n class=\"pk-chatbot-file-preview__name\"\n :title=\"filename\"\n >{{ filename }}</span\n >\n <span class=\"pk-chatbot-file-preview__meta\">\n <span\n v-if=\"error\"\n class=\"pk-chatbot-file-preview__error\"\n :title=\"error\">\n <VvIcon name=\"ri:error-warning-line\" />\n {{ error }}\n </span>\n <template v-else>{{ imageMeta.join(' · ') }}</template>\n </span>\n </figcaption>\n <button\n v-if=\"removable && !loading\"\n type=\"button\"\n class=\"pk-chatbot-file-preview__remove\"\n :title=\"$t('action.remove')\"\n :aria-label=\"$t('action.remove')\"\n @click.prevent=\"$emit('remove')\">\n <VvIcon name=\"ri:close-line\" />\n </button>\n </figure>\n\n <!-- Document attachment: an icon tile + name + type · size -->\n <div\n v-else\n class=\"pk-chatbot-file-preview pk-chatbot-file-preview--doc\"\n :class=\"{\n 'pk-chatbot-file-preview--error': error,\n 'pk-chatbot-file-preview--compact': compact,\n }\">\n <span\n class=\"pk-chatbot-file-preview__icon-tile\"\n :style=\"{ '--file-accent': fileKind.accent }\">\n <VvIcon\n v-if=\"loading\"\n name=\"line-md:loading-loop\"\n class=\"pk-chatbot-file-preview__icon\" />\n <VvIcon\n v-else\n :name=\"fileKind.icon\"\n class=\"pk-chatbot-file-preview__icon\" />\n </span>\n <span class=\"pk-chatbot-file-preview__body\">\n <span\n v-if=\"filename\"\n class=\"pk-chatbot-file-preview__name\"\n :title=\"filename\"\n >{{ filename }}</span\n >\n <span class=\"pk-chatbot-file-preview__meta\">\n <span\n v-if=\"error\"\n class=\"pk-chatbot-file-preview__error\"\n :title=\"error\">\n <VvIcon name=\"ri:error-warning-line\" />\n {{ error }}\n </span>\n <template v-else>{{ docMeta.join(' · ') }}</template>\n </span>\n </span>\n <a\n v-if=\"!loading && !error && !compact\"\n :href=\"url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"pk-chatbot-file-preview__open\"\n :title=\"$t('action.download')\"\n :aria-label=\"`${$t('action.download')}${filename ? ` — ${filename}` : ''}`\">\n <VvIcon name=\"ri:download-2-line\" />\n </a>\n <button\n v-if=\"removable && !loading\"\n type=\"button\"\n class=\"pk-chatbot-file-preview__remove\"\n :class=\"{ 'pk-chatbot-file-preview__remove--inline': !compact }\"\n :title=\"$t('action.remove')\"\n :aria-label=\"$t('action.remove')\"\n @click=\"$emit('remove')\">\n <VvIcon name=\"ri:close-line\" />\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-file-preview {\n // Concentric radii: outer card and inner tiles share an 8px step.\n --file-radius: var(--rounded-lg, 12px);\n position: relative;\n max-width: 280px;\n background-color: var(--color-surface-1);\n border: 1px solid var(--color-surface-3);\n border-radius: var(--file-radius);\n color: var(--color-word-2);\n font-size: var(--text-12);\n\n &--error {\n border-color: var(--color-danger);\n }\n\n // --- Document card ---\n &--doc {\n display: flex;\n align-items: center;\n gap: var(--spacing-8);\n padding: var(--spacing-8);\n min-width: 0;\n transition:\n border-color 0.18s var(--ease-out),\n background-color 0.18s var(--ease-out),\n box-shadow 0.18s var(--ease-out);\n\n &:hover {\n border-color: var(--color-surface-4);\n background-color: var(--color-surface-2);\n box-shadow: var(--shadow-sm);\n }\n }\n\n &__icon-tile {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--spacing-36);\n height: var(--spacing-36);\n // One step down from the card radius keeps the nested tile concentric.\n border-radius: var(--rounded-md, 6px);\n // Tint derived from the file-type accent; glyph sits at full accent.\n background-color: color-mix(\n in srgb,\n var(--file-accent) 14%,\n transparent\n );\n color: var(--file-accent);\n }\n\n &__icon {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n\n &__body {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 0;\n flex: 1;\n }\n\n &__open {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--spacing-28);\n height: var(--spacing-28);\n margin-inline-start: var(--spacing-4);\n border-radius: var(--rounded);\n color: var(--color-word-3);\n text-decoration: none;\n opacity: 0;\n transition:\n opacity 0.18s var(--ease-out),\n color 0.18s var(--ease-out),\n background-color 0.18s var(--ease-out);\n\n &:hover {\n background-color: var(--color-surface-3);\n color: var(--color-word-1);\n }\n }\n\n &--doc:hover &__open,\n &--doc:focus-within &__open {\n opacity: 1;\n }\n\n // Touch devices have no hover: keep the open affordance visible.\n @media (hover: none) {\n &--doc &__open {\n opacity: 1;\n }\n }\n\n // --- Image card ---\n &--image {\n display: inline-flex;\n flex-direction: column;\n margin: 0;\n }\n\n &__thumb-wrap {\n position: relative;\n display: flex;\n // Fixed box: the card claims its final footprint before the\n // image decodes, so the message log never shifts on load.\n width: 280px;\n max-width: 100%;\n height: 200px;\n background-color: var(--color-surface);\n border-radius: var(--file-radius);\n overflow: hidden;\n }\n\n &__thumb-link {\n display: flex;\n width: 100%;\n height: 100%;\n cursor: pointer;\n }\n\n &__thumb {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &__caption {\n display: flex;\n flex-direction: column;\n gap: 1px;\n padding: var(--spacing-8);\n min-width: 0;\n }\n\n &__name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: var(--font-medium, 500);\n color: var(--color-word-1);\n }\n\n &__meta {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--text-10);\n line-height: var(--leading-normal);\n // Reserve the line even while empty: image dimensions arrive\n // only after decode and must not grow the caption.\n min-height: 1.4em;\n color: var(--color-word-4);\n // Stable column for the dimensions/size figures.\n font-variant-numeric: tabular-nums;\n }\n\n &__error {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-4);\n color: var(--color-danger);\n\n .vv-icon {\n flex-shrink: 0;\n }\n }\n\n &__status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n &--overlay {\n position: absolute;\n inset: 0;\n background-color: color-mix(\n in srgb,\n var(--color-surface-1) 70%,\n transparent\n );\n color: var(--color-word-1);\n }\n\n &--error {\n color: var(--color-word-4);\n }\n }\n\n // --- Remove button (input context) ---\n &__remove {\n position: absolute;\n top: 0;\n right: 0;\n transform: translate(50%, -50%);\n display: flex;\n align-items: center;\n justify-content: center;\n // Visible glyph is 18px but the hit area stays a comfortable 28px.\n width: var(--spacing-28);\n height: var(--spacing-28);\n padding: 0;\n border: none;\n border-radius: var(--rounded-full, 9999px);\n background-color: color-mix(\n in srgb,\n var(--color-surface-1) 85%,\n transparent\n );\n color: var(--color-word-2);\n cursor: pointer;\n line-height: 1;\n box-shadow: var(--shadow-sm);\n transition:\n background-color 0.18s var(--ease-out),\n color 0.18s var(--ease-out),\n scale 0.12s var(--ease-out);\n\n &:hover {\n background-color: var(--color-surface-2);\n color: var(--color-word-1);\n }\n\n &:active {\n scale: 0.96;\n }\n\n // Inside the document row the button rides inline, not overlaid\n // (size is inherited from the base).\n &--inline {\n position: static;\n flex-shrink: 0;\n box-shadow: none;\n background-color: transparent;\n color: var(--color-word-4);\n\n &:hover {\n background-color: var(--color-surface-3);\n color: var(--color-word-1);\n }\n }\n }\n\n // --- Compact (composer) chips ---\n // ChatGPT/Gemini-style: every attachment is the SAME height and carries\n // an always-visible round remove control in the top-right corner — no\n // hover-revealed actions, no size mismatch between image and file chips.\n &--compact {\n // Shared chip height so image and file chips align in the row.\n --chip-size: var(--spacing-56);\n max-width: 240px;\n\n &.pk-chatbot-file-preview--image {\n width: var(--chip-size);\n height: var(--chip-size);\n border-radius: var(--rounded-md, 6px);\n }\n\n // Fill the square; the root's `overflow: hidden` rounds the corners.\n .pk-chatbot-file-preview__thumb-wrap,\n .pk-chatbot-file-preview__thumb-link {\n width: 100%;\n height: 100%;\n }\n\n &.pk-chatbot-file-preview--doc {\n height: var(--chip-size);\n gap: var(--spacing-8);\n padding: var(--spacing-8);\n // Reserve room so the corner remove button never overlaps the\n // name/meta text.\n padding-inline-end: var(--spacing-28);\n }\n\n // Square icon tile that fills the chip height, so file chips read at\n // the same scale as image thumbnails.\n .pk-chatbot-file-preview__icon-tile {\n align-self: stretch;\n width: auto;\n height: auto;\n aspect-ratio: 1;\n }\n\n .pk-chatbot-file-preview__icon {\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n\n // Always-visible round remove control in the top-right corner. Sits\n // just inside the chip (an ancestor clips overflow), bigger than before,\n // with an extended hit area for easy tapping.\n &--compact &__remove {\n top: var(--spacing-4);\n right: var(--spacing-4);\n width: var(--spacing-24);\n height: var(--spacing-24);\n border: 1px solid var(--color-surface-4);\n background-color: var(--color-surface);\n color: var(--color-word-1);\n font-size: var(--text-16);\n box-shadow: var(--shadow-sm);\n\n // Comfortable touch/click target beyond the small visible glyph.\n &::after {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--spacing-4));\n }\n\n &:hover {\n background-color: var(--color-surface-2);\n color: var(--color-word-1);\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n &--doc,\n &__open,\n &__remove {\n transition: none;\n }\n }\n }\n</style>\n"],"mappings":"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"}
|