@8wave/ai-elements 0.75.0 → 0.78.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/{PkStreamingMarkdown-rIdQh5_D.js → PkStreamingMarkdown-gIAvEY1t.js} +372 -303
- package/dist/_chunks/PkStreamingMarkdown-gIAvEY1t.js.map +1 -0
- package/dist/_chunks/{PkToolShowArtifact-CeLgwZBA.js → PkToolShowArtifact-BwW4Yn6k.js} +5 -5
- package/dist/_chunks/{PkToolShowArtifact-CeLgwZBA.js.map → PkToolShowArtifact-BwW4Yn6k.js.map} +1 -1
- package/dist/_chunks/{PkToolShowCalendarEvent-cQpAAE3a.js → PkToolShowCalendarEvent-BEqn5iEb.js} +6 -6
- package/dist/_chunks/{PkToolShowCalendarEvent-cQpAAE3a.js.map → PkToolShowCalendarEvent-BEqn5iEb.js.map} +1 -1
- package/dist/_chunks/{PkToolShowComparison-Cu-zT8-Z.js → PkToolShowComparison-p34r0Hhd.js} +4 -4
- package/dist/_chunks/{PkToolShowComparison-Cu-zT8-Z.js.map → PkToolShowComparison-p34r0Hhd.js.map} +1 -1
- package/dist/_chunks/{PkToolShowContactForm-CqoSVvjG.js → PkToolShowContactForm-DTE-iF_c.js} +18 -18
- package/dist/_chunks/{PkToolShowContactForm-CqoSVvjG.js.map → PkToolShowContactForm-DTE-iF_c.js.map} +1 -1
- package/dist/_chunks/{PkToolShowEmail-oLGym0R9.js → PkToolShowEmail-Be8FvWjw.js} +4 -4
- package/dist/_chunks/{PkToolShowEmail-oLGym0R9.js.map → PkToolShowEmail-Be8FvWjw.js.map} +1 -1
- package/dist/_chunks/PkToolShowImageGallery-CGL-HL6v.js +60 -0
- package/dist/_chunks/PkToolShowImageGallery-CGL-HL6v.js.map +1 -0
- package/dist/_chunks/{PkToolShowLocation-BtRUdoEw.js → PkToolShowLocation-DOoLCHzS.js} +6 -6
- package/dist/_chunks/{PkToolShowLocation-BtRUdoEw.js.map → PkToolShowLocation-DOoLCHzS.js.map} +1 -1
- package/dist/_chunks/{PkToolShowMessage-tJQGRhce.js → PkToolShowMessage-DgeULbdQ.js} +4 -4
- package/dist/_chunks/{PkToolShowMessage-tJQGRhce.js.map → PkToolShowMessage-DgeULbdQ.js.map} +1 -1
- package/dist/_chunks/{PkToolShowMultipleChoice-CtVvdyDg.js → PkToolShowMultipleChoice-CpGyn_bZ.js} +3 -3
- package/dist/_chunks/{PkToolShowMultipleChoice-CtVvdyDg.js.map → PkToolShowMultipleChoice-CpGyn_bZ.js.map} +1 -1
- package/dist/_chunks/{PkToolShowProductList-D_k6CDdb.js → PkToolShowProductList-C8YIh0Dw.js} +4 -4
- package/dist/_chunks/{PkToolShowProductList-D_k6CDdb.js.map → PkToolShowProductList-C8YIh0Dw.js.map} +1 -1
- package/dist/_chunks/{PkToolShowQrCode-S1j_T8wQ.js → PkToolShowQrCode-UE4uSyvJ.js} +4 -4
- package/dist/_chunks/{PkToolShowQrCode-S1j_T8wQ.js.map → PkToolShowQrCode-UE4uSyvJ.js.map} +1 -1
- package/dist/_chunks/{PkToolShowSources-CroItMtG.js → PkToolShowSources-TSjtd1ps.js} +7 -7
- package/dist/_chunks/PkToolShowSources-TSjtd1ps.js.map +1 -0
- package/dist/_chunks/{PkToolShowSuggestedReply-BRa5Lpti.js → PkToolShowSuggestedReply-c9sLv4n4.js} +4 -4
- package/dist/_chunks/{PkToolShowSuggestedReply-BRa5Lpti.js.map → PkToolShowSuggestedReply-c9sLv4n4.js.map} +1 -1
- package/dist/_chunks/{PkToolShowWeather-CUpCJ8Nj.js → PkToolShowWeather-ChJ5lB4K.js} +51 -51
- package/dist/_chunks/PkToolShowWeather-ChJ5lB4K.js.map +1 -0
- package/dist/_chunks/{PkToolShowWebPages-f-dHyxfD.js → PkToolShowWebPages-CL2mYxh-.js} +5 -5
- package/dist/_chunks/{PkToolShowWebPages-f-dHyxfD.js.map → PkToolShowWebPages-CL2mYxh-.js.map} +1 -1
- package/dist/_chunks/{PkUrl-CI17WkYu.js → PkUrl-CvztUywv.js} +3 -3
- package/dist/_chunks/{PkUrl-CI17WkYu.js.map → PkUrl-CvztUywv.js.map} +1 -1
- package/dist/_chunks/{VvCheckbox.es-BF8Mdg0O.js → VvCheckbox.es-ohF87NOe.js} +3 -3
- package/dist/_chunks/{VvCheckbox.es-BF8Mdg0O.js.map → VvCheckbox.es-ohF87NOe.js.map} +1 -1
- package/dist/_chunks/{VvCheckboxGroup.es-BJc8MmJ3.js → VvCheckboxGroup.es-DZCbyLN0.js} +4 -4
- package/dist/_chunks/{VvCheckboxGroup.es-BJc8MmJ3.js.map → VvCheckboxGroup.es-DZCbyLN0.js.map} +1 -1
- package/dist/_chunks/{VvCombobox.es-ILRHqAye.js → VvCombobox.es-YLPD7MpO.js} +6 -6
- package/dist/_chunks/{VvCombobox.es-ILRHqAye.js.map → VvCombobox.es-YLPD7MpO.js.map} +1 -1
- package/dist/_chunks/{VvInputText.es-CDnMeO26.js → VvInputText.es-DAnAXfBO.js} +7 -7
- package/dist/_chunks/{VvInputText.es-CDnMeO26.js.map → VvInputText.es-DAnAXfBO.js.map} +1 -1
- package/dist/_chunks/{VvRadio.es-C2p5vvAx.js → VvRadio.es-Do9oyNtV.js} +3 -3
- package/dist/_chunks/{VvRadio.es-C2p5vvAx.js.map → VvRadio.es-Do9oyNtV.js.map} +1 -1
- package/dist/_chunks/{VvRadioGroup.es-6GlWuDjY.js → VvRadioGroup.es-BHcqcJFC.js} +4 -4
- package/dist/_chunks/{VvRadioGroup.es-6GlWuDjY.js.map → VvRadioGroup.es-BHcqcJFC.js.map} +1 -1
- package/dist/_chunks/{VvSelect.es-i4lO9onq.js → VvSelect.es-CP_y02fy.js} +5 -5
- package/dist/_chunks/{VvSelect.es-i4lO9onq.js.map → VvSelect.es-CP_y02fy.js.map} +1 -1
- package/dist/_chunks/{VvTextarea.es-CGpiCS4S.js → VvTextarea.es-DetA_2DM.js} +6 -6
- package/dist/_chunks/{VvTextarea.es-CGpiCS4S.js.map → VvTextarea.es-DetA_2DM.js.map} +1 -1
- package/dist/_chunks/{dist-BTnzL-m0.js → dist-yqV26MWM.js} +4 -4
- package/dist/_chunks/{dist-BTnzL-m0.js.map → dist-yqV26MWM.js.map} +1 -1
- package/dist/_chunks/{esm-0nyRYwmP.js → esm-DLxNpT06.js} +7 -7
- package/dist/_chunks/{esm-0nyRYwmP.js.map → esm-DLxNpT06.js.map} +1 -1
- package/dist/_chunks/{floating-ui.vue-B5ZV-j8C.js → floating-ui.vue-tVPpNXUc.js} +3 -3
- package/dist/_chunks/{floating-ui.vue-B5ZV-j8C.js.map → floating-ui.vue-tVPpNXUc.js.map} +1 -1
- package/dist/_chunks/{iconify-C1EOwL90.js → iconify-y0w2FIJH.js} +3 -3
- package/dist/_chunks/{iconify-C1EOwL90.js.map → iconify-y0w2FIJH.js.map} +1 -1
- package/dist/_chunks/{index.es-CUjDCkXD.js → index.es-7fUi-rc0.js} +7 -7
- package/dist/_chunks/{index.es-CUjDCkXD.js.map → index.es-7fUi-rc0.js.map} +1 -1
- package/dist/_chunks/{src-C_wl-KYN.js → src-BfoQF6Z3.js} +2 -2
- package/dist/_chunks/{src-C_wl-KYN.js.map → src-BfoQF6Z3.js.map} +1 -1
- package/dist/_chunks/{useLightbox-CH1KeVqr.js → useLightbox-Ddvue042.js} +7 -5
- package/dist/_chunks/{useLightbox-CH1KeVqr.js.map → useLightbox-Ddvue042.js.map} +1 -1
- package/dist/_chunks/{vue-i18n-KvYvoek4.js → vue-i18n-DAH6nDTN.js} +3 -3
- package/dist/_chunks/{vue-i18n-KvYvoek4.js.map → vue-i18n-DAH6nDTN.js.map} +1 -1
- package/dist/_chunks/{vue.runtime.esm-bundler-BmggS4HU.js → vue.runtime.esm-bundler-Dq29dQrz.js} +16 -10
- package/dist/_chunks/vue.runtime.esm-bundler-Dq29dQrz.js.map +1 -0
- package/dist/ai-elements.es.js +3138 -3039
- package/dist/ai-elements.es.js.map +1 -1
- package/dist-vue/PkChatbot.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/PkChatbotMessages.js +1 -1
- package/dist-vue/PkChatbotViewChat.js +1 -1
- package/dist-vue/PkChatbotViewConversations.js +1 -1
- package/dist-vue/PkChatbotViewProfile.js +1 -1
- package/dist-vue/_chunks/{Media-CXQSoKqt.js → Media-kK7BnZGr.js} +2 -2
- package/dist-vue/_chunks/Media-kK7BnZGr.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbot-DAzGc7al.js → PkChatbot-BEJTYq-D.js} +7 -7
- package/dist-vue/_chunks/{PkChatbot-DAzGc7al.js.map → PkChatbot-BEJTYq-D.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotFeedbackForm-DvUzirPP.js → PkChatbotFeedbackForm-lj9CHdhn.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotFeedbackForm-DvUzirPP.js.map → PkChatbotFeedbackForm-lj9CHdhn.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotFilePreview-DHzuGtz5.js → PkChatbotFilePreview-hRNtv2OJ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotFilePreview-DHzuGtz5.js.map → PkChatbotFilePreview-hRNtv2OJ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotInput-C5QSmt21.js → PkChatbotInput-BbGLBVim.js} +124 -116
- package/dist-vue/_chunks/PkChatbotInput-BbGLBVim.js.map +1 -0
- package/dist-vue/_chunks/PkChatbotMessages-j3ALQmGG.js +467 -0
- package/dist-vue/_chunks/PkChatbotMessages-j3ALQmGG.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotViewChat-CjoezIyz.js → PkChatbotViewChat-Z05fqNFE.js} +6 -6
- package/dist-vue/_chunks/{PkChatbotViewChat-CjoezIyz.js.map → PkChatbotViewChat-Z05fqNFE.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewConversations-DSQu6vY1.js → PkChatbotViewConversations-2xc0o-fO.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewConversations-DSQu6vY1.js.map → PkChatbotViewConversations-2xc0o-fO.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewProfile-BJJiaG9H.js → PkChatbotViewProfile-CoT1JnMk.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewProfile-BJJiaG9H.js.map → PkChatbotViewProfile-CoT1JnMk.js.map} +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-BAhC3uGK.js → PkStreamingMarkdown-BBTAwHd_.js} +311 -252
- package/dist-vue/_chunks/PkStreamingMarkdown-BBTAwHd_.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowArtifact-RzrDPcEQ.js → PkToolShowArtifact-CbqpjzCA.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowArtifact-RzrDPcEQ.js.map → PkToolShowArtifact-CbqpjzCA.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowContactForm-r_GgO-ZX.js → PkToolShowContactForm-BkgfSyw7.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowContactForm-r_GgO-ZX.js.map → PkToolShowContactForm-BkgfSyw7.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowImageGallery-B7Bt6ZGv.js → PkToolShowImageGallery-Ckyxa0mx.js} +18 -21
- package/dist-vue/_chunks/PkToolShowImageGallery-Ckyxa0mx.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowSources-DK2DCvU3.js → PkToolShowSources-7Xt3iK2Z.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowSources-DK2DCvU3.js.map → PkToolShowSources-7Xt3iK2Z.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowWeather-Coq6H0iv.js → PkToolShowWeather-B5Wp8WAt.js} +26 -26
- package/dist-vue/_chunks/PkToolShowWeather-B5Wp8WAt.js.map +1 -0
- package/dist-vue/_chunks/{createChatbotApiClient-f86KwRcq.js → createChatbotApiClient-CvDRMmDa.js} +2 -2
- package/dist-vue/_chunks/{createChatbotApiClient-f86KwRcq.js.map → createChatbotApiClient-CvDRMmDa.js.map} +1 -1
- package/dist-vue/_chunks/{index.es-_14zrNZB.js → index.es-Dk_HaA08.js} +2 -2
- package/dist-vue/_chunks/{index.es-_14zrNZB.js.map → index.es-Dk_HaA08.js.map} +1 -1
- package/dist-vue/_chunks/{useChatbotStore-CJlkoNn7.js → useChatbotStore-DMDbzuub.js} +5 -5
- package/dist-vue/_chunks/{useChatbotStore-CJlkoNn7.js.map → useChatbotStore-DMDbzuub.js.map} +1 -1
- package/dist-vue/_chunks/{useLightbox-1sB7fmFb.js → useLightbox-Cl8REkfc.js} +5 -3
- package/dist-vue/_chunks/{useLightbox-1sB7fmFb.js.map → useLightbox-Cl8REkfc.js.map} +1 -1
- package/dist-vue/api.js +1 -1
- package/dist-vue/composables.js +2 -2
- package/dist-vue/index.js +24 -24
- package/dist-vue/index.js.map +1 -1
- package/dist-vue/packages/components/src/chat/PkChatbotMessages.d.ts +4 -5
- package/dist-vue/packages/components/src/chat/PkStreamingMarkdown.d.ts +9 -1
- package/dist-vue/packages/components/src/chat/useChatScroll.d.ts +15 -0
- package/dist-vue/packages/models/src/schema/AgentEndpoint.d.ts +1 -1
- package/dist-vue/packages/models/src/schema/constants.d.ts +3 -1
- package/dist-vue/style.css +1 -1
- package/package.json +2 -2
- package/dist/_chunks/PkStreamingMarkdown-rIdQh5_D.js.map +0 -1
- package/dist/_chunks/PkToolShowImageGallery-CDXSL1Mg.js +0 -63
- package/dist/_chunks/PkToolShowImageGallery-CDXSL1Mg.js.map +0 -1
- package/dist/_chunks/PkToolShowSources-CroItMtG.js.map +0 -1
- package/dist/_chunks/PkToolShowWeather-CUpCJ8Nj.js.map +0 -1
- package/dist/_chunks/vue.runtime.esm-bundler-BmggS4HU.js.map +0 -1
- package/dist-vue/_chunks/Media-CXQSoKqt.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotInput-C5QSmt21.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotMessages-dsjB0-26.js +0 -388
- package/dist-vue/_chunks/PkChatbotMessages-dsjB0-26.js.map +0 -1
- package/dist-vue/_chunks/PkStreamingMarkdown-BAhC3uGK.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowImageGallery-B7Bt6ZGv.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowWeather-Coq6H0iv.js.map +0 -1
- /package/dist/_chunks/{_plugin-vue_export-helper-BI3pHb34.js → _plugin-vue_export-helper-C6kC663S.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $ as e, Bt as t, C as n, E as r, Gt as i, V as a, Z as o, _ as s, b as c, ft as l, h as u, n as d, v as f, w as p, x as m, y as ee, yt as h, z as g } from "./vue.runtime.esm-bundler-
|
|
2
|
-
import { n as te } from "./vue-i18n-
|
|
3
|
-
import { l as ne, o as re } from "./index.es-
|
|
1
|
+
import { $ as e, Bt as t, C as n, E as r, Gt as i, V as a, Z as o, _ as s, b as c, ft as l, h as u, n as d, v as f, w as p, x as m, y as ee, yt as h, z as g } from "./vue.runtime.esm-bundler-Dq29dQrz.js";
|
|
2
|
+
import { n as te } from "./vue-i18n-DAH6nDTN.js";
|
|
3
|
+
import { l as ne, o as re } from "./index.es-7fUi-rc0.js";
|
|
4
4
|
//#region ../../packages/components/src/chat/PkToolShowWeather.vue?vue&type=script&setup=true&lang.ts
|
|
5
5
|
var _ = {
|
|
6
6
|
key: 0,
|
|
@@ -8,38 +8,38 @@ var _ = {
|
|
|
8
8
|
}, v = { class: "px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40" }, ie = { class: "font-bold truncate" }, ae = { class: "ml-auto shrink-0 capitalize" }, oe = {
|
|
9
9
|
key: 0,
|
|
10
10
|
class: "px-sm py-md flex items-center gap-md flex-wrap"
|
|
11
|
-
}, se = { class: "flex items-center gap-8" }, ce = { class: "text-48 font-light leading-none text-word-1" }, le = { class: "flex flex-col gap-4 text-12 text-word-3" }, ue = { class: "flex items-center gap-6" }, de = { class: "flex items-center gap-6" }, fe = { class: "flex items-center gap-6" },
|
|
11
|
+
}, se = { class: "flex items-center gap-8" }, ce = { class: "text-48 font-light leading-none text-word-1" }, le = { class: "flex flex-col gap-4 text-12 text-word-3" }, ue = { class: "flex items-center gap-6" }, de = { class: "flex items-center gap-6" }, fe = { class: "flex items-center gap-6" }, pe = {
|
|
12
12
|
key: 0,
|
|
13
13
|
class: "flex items-center gap-6"
|
|
14
|
-
},
|
|
14
|
+
}, y = {
|
|
15
15
|
key: 1,
|
|
16
16
|
class: "px-sm py-md flex items-center gap-md flex-wrap"
|
|
17
|
-
},
|
|
17
|
+
}, b = { class: "flex items-center gap-8" }, x = { class: "flex flex-col leading-none" }, S = { class: "text-48 font-light text-word-1" }, C = { class: "text-20 text-word-3" }, w = { class: "flex flex-col gap-4 text-12 text-word-3" }, T = {
|
|
18
18
|
key: 0,
|
|
19
19
|
class: "flex items-center gap-6"
|
|
20
|
-
},
|
|
20
|
+
}, E = {
|
|
21
21
|
key: 1,
|
|
22
22
|
class: "flex items-center gap-6"
|
|
23
|
-
},
|
|
23
|
+
}, D = { class: "flex items-center gap-6" }, O = {
|
|
24
24
|
key: 0,
|
|
25
25
|
class: "border-t border-surface-3"
|
|
26
|
-
},
|
|
26
|
+
}, k = { class: "flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar" }, A = { class: "text-word-3" }, j = { class: "font-medium text-word-1" }, M = {
|
|
27
27
|
key: 0,
|
|
28
28
|
class: "text-word-5 text-smaller"
|
|
29
|
-
},
|
|
29
|
+
}, N = ["onClick"], me = { class: "w-48 shrink-0 text-word-3 capitalize" }, P = {
|
|
30
30
|
key: 0,
|
|
31
31
|
class: "text-word-5 text-11 w-32 shrink-0"
|
|
32
|
-
},
|
|
32
|
+
}, F = {
|
|
33
33
|
key: 1,
|
|
34
34
|
class: "w-32 shrink-0"
|
|
35
|
-
},
|
|
35
|
+
}, I = { class: "ml-auto flex items-center gap-8 text-word-3" }, L = { class: "text-word-1 font-semibold" }, R = {
|
|
36
36
|
key: 2,
|
|
37
37
|
class: "border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12"
|
|
38
|
-
},
|
|
38
|
+
}, z = { class: "text-word-3" }, B = /* @__PURE__ */ r({
|
|
39
39
|
__name: "PkToolShowWeather",
|
|
40
40
|
props: { part: { type: null } },
|
|
41
41
|
setup(r) {
|
|
42
|
-
let
|
|
42
|
+
let B = r, { t: V, d: H, n: U } = te({ useScope: "global" }), W = s(() => B.part), G = s(() => W.value.output ?? W.value.input ?? null), K = l(0), q = l(!G.value?.current);
|
|
43
43
|
o(K, (e) => {
|
|
44
44
|
e > 0 && (q.value = !0);
|
|
45
45
|
});
|
|
@@ -73,37 +73,37 @@ var _ = {
|
|
|
73
73
|
let r = X(e + "T12:00:00");
|
|
74
74
|
if (!Number.isNaN(r.getTime())) {
|
|
75
75
|
let e = /* @__PURE__ */ new Date();
|
|
76
|
-
return e.setHours(12, 0, 0, 0), Math.round((r.getTime() - e.getTime()) / 864e5) === 0 ?
|
|
76
|
+
return e.setHours(12, 0, 0, 0), Math.round((r.getTime() - e.getTime()) / 864e5) === 0 ? V("weather.today") : H(r, "weekday-day");
|
|
77
77
|
}
|
|
78
|
-
if (t === 0 && n <= 7) return
|
|
78
|
+
if (t === 0 && n <= 7) return V("weather.today");
|
|
79
79
|
let i = /* @__PURE__ */ new Date();
|
|
80
|
-
return i.setDate(i.getDate() + t),
|
|
80
|
+
return i.setDate(i.getDate() + t), H(i, "weekday-day");
|
|
81
81
|
}
|
|
82
82
|
let he = s(() => {
|
|
83
83
|
if (J.value) {
|
|
84
84
|
let e = X(J.value.date + "T12:00:00");
|
|
85
|
-
if (!Number.isNaN(e.getTime())) return Q(J.value.date, K.value, G.value
|
|
85
|
+
if (!Number.isNaN(e.getTime())) return Q(J.value.date, K.value, G.value?.daily?.length ?? 1);
|
|
86
86
|
}
|
|
87
|
-
return Q(
|
|
87
|
+
return Q((/* @__PURE__ */ new Date()).toISOString().slice(0, 10), 0, 1);
|
|
88
88
|
});
|
|
89
89
|
function $(e) {
|
|
90
90
|
return e <= 20 ? {
|
|
91
|
-
label:
|
|
91
|
+
label: V("weather.aqiGood"),
|
|
92
92
|
class: "text-green-600 bg-green-50"
|
|
93
93
|
} : e <= 40 ? {
|
|
94
|
-
label:
|
|
94
|
+
label: V("weather.aqiFair"),
|
|
95
95
|
class: "text-lime-600 bg-lime-50"
|
|
96
96
|
} : e <= 60 ? {
|
|
97
|
-
label:
|
|
97
|
+
label: V("weather.aqiModerate"),
|
|
98
98
|
class: "text-yellow-600 bg-yellow-50"
|
|
99
99
|
} : e <= 80 ? {
|
|
100
|
-
label:
|
|
100
|
+
label: V("weather.aqiPoor"),
|
|
101
101
|
class: "text-orange-600 bg-orange-50"
|
|
102
102
|
} : e <= 100 ? {
|
|
103
|
-
label:
|
|
103
|
+
label: V("weather.aqiVeryPoor"),
|
|
104
104
|
class: "text-red-600 bg-red-50"
|
|
105
105
|
} : {
|
|
106
|
-
label:
|
|
106
|
+
label: V("weather.aqiHazardous"),
|
|
107
107
|
class: "text-purple-700 bg-purple-50"
|
|
108
108
|
};
|
|
109
109
|
}
|
|
@@ -133,8 +133,8 @@ var _ = {
|
|
|
133
133
|
G.value.current && K.value === 0 ? (g(), m("div", oe, [f("div", se, [p(s, {
|
|
134
134
|
name: Z(G.value.current.weatherCode),
|
|
135
135
|
class: "text-48 text-word-2 shrink-0"
|
|
136
|
-
}, null, 8, ["name"]), f("span", ce, i(h(
|
|
137
|
-
f("div", ue, i(h(
|
|
136
|
+
}, null, 8, ["name"]), f("span", ce, i(h(U)(G.value.current.temperature, "integer")) + "° ", 1)]), f("div", le, [
|
|
137
|
+
f("div", ue, i(h(V)("weather.feelsLike")) + " " + i(h(U)(G.value.current.feelsLike, "integer")) + "° ", 1),
|
|
138
138
|
f("div", de, [p(s, {
|
|
139
139
|
name: "ri:water-percent-line",
|
|
140
140
|
class: "text-14"
|
|
@@ -142,50 +142,50 @@ var _ = {
|
|
|
142
142
|
f("div", fe, [p(s, {
|
|
143
143
|
name: "ri:windy-line",
|
|
144
144
|
class: "text-14"
|
|
145
|
-
}), n(" " + i(h(
|
|
146
|
-
G.value.current.uvIndex > 0 ? (g(), m("div",
|
|
145
|
+
}), n(" " + i(h(U)(G.value.current.windSpeed, "integer")) + " km/h " + i(ge(G.value.current.windDirection)), 1)]),
|
|
146
|
+
G.value.current.uvIndex > 0 ? (g(), m("div", pe, [p(s, {
|
|
147
147
|
name: "ri:sun-line",
|
|
148
148
|
class: "text-14"
|
|
149
|
-
}), n(" UV " + i(h(
|
|
150
|
-
])])) : J.value ? (g(), m("div",
|
|
149
|
+
}), n(" UV " + i(h(U)(G.value.current.uvIndex, "integer")), 1)])) : c("", !0)
|
|
150
|
+
])])) : J.value ? (g(), m("div", y, [f("div", b, [p(s, {
|
|
151
151
|
name: Z(J.value.weatherCode),
|
|
152
152
|
class: "text-48 text-word-2 shrink-0"
|
|
153
|
-
}, null, 8, ["name"]), f("div",
|
|
154
|
-
J.value.precipitationProbabilityMax > 0 ? (g(), m("div",
|
|
153
|
+
}, null, 8, ["name"]), f("div", x, [f("span", S, i(h(U)(J.value.maxTemp, "integer")) + "° ", 1), f("span", C, i(h(U)(J.value.minTemp, "integer")) + "° ", 1)])]), f("div", w, [
|
|
154
|
+
J.value.precipitationProbabilityMax > 0 ? (g(), m("div", T, [p(s, {
|
|
155
155
|
name: "ri:drop-line",
|
|
156
156
|
class: "text-14"
|
|
157
157
|
}), n(" " + i(J.value.precipitationProbabilityMax) + "% (" + i(J.value.precipitationSum) + " mm) ", 1)])) : c("", !0),
|
|
158
|
-
J.value.uvIndexMax > 0 ? (g(), m("div",
|
|
158
|
+
J.value.uvIndexMax > 0 ? (g(), m("div", E, [p(s, {
|
|
159
159
|
name: "ri:sun-line",
|
|
160
160
|
class: "text-14"
|
|
161
|
-
}), n(" UV " + i(h(
|
|
162
|
-
f("div",
|
|
161
|
+
}), n(" UV " + i(h(U)(J.value.uvIndexMax, "integer")), 1)])) : c("", !0),
|
|
162
|
+
f("div", D, [p(s, {
|
|
163
163
|
name: "ri:sun-foggy-line",
|
|
164
164
|
class: "text-14"
|
|
165
|
-
}), n(" " + i(h(
|
|
165
|
+
}), n(" " + i(h(H)(X(J.value.sunrise), "time")) + " – " + i(h(H)(X(J.value.sunset), "time")), 1)])
|
|
166
166
|
])])) : c("", !0),
|
|
167
167
|
p(d, null, {
|
|
168
|
-
default: e(() => [Y.value.length > 0 ? (g(), m("div",
|
|
168
|
+
default: e(() => [Y.value.length > 0 ? (g(), m("div", O, [f("div", k, [(g(!0), m(u, null, a(Y.value, (e) => (g(), m("div", {
|
|
169
169
|
key: e.time,
|
|
170
170
|
class: "flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-lg text-11 text-word-3 shrink-0"
|
|
171
171
|
}, [
|
|
172
|
-
f("span",
|
|
172
|
+
f("span", A, i(Number.isNaN(X(e.time).getTime()) ? e.time : h(H)(X(e.time), "time")), 1),
|
|
173
173
|
p(s, {
|
|
174
174
|
name: Z(e.weatherCode),
|
|
175
175
|
class: "text-20 text-word-2"
|
|
176
176
|
}, null, 8, ["name"]),
|
|
177
|
-
f("span",
|
|
178
|
-
e.precipitationProbability > 0 ? (g(), m("span",
|
|
177
|
+
f("span", j, i(h(U)(e.temperature, "integer")) + "° ", 1),
|
|
178
|
+
e.precipitationProbability > 0 ? (g(), m("span", M, i(e.precipitationProbability) + "% ", 1)) : c("", !0)
|
|
179
179
|
]))), 128))])])) : c("", !0)]),
|
|
180
180
|
_: 1
|
|
181
181
|
}),
|
|
182
182
|
p(d, null, {
|
|
183
|
-
default: e(() => [G.value.daily
|
|
183
|
+
default: e(() => [G.value.daily?.length > 1 ? (g(), ee(l, {
|
|
184
184
|
key: 0,
|
|
185
185
|
modelValue: q.value,
|
|
186
186
|
"onUpdate:modelValue": o[0] ||= (e) => q.value = e,
|
|
187
187
|
modifiers: "details no-padding",
|
|
188
|
-
title: h(
|
|
188
|
+
title: h(V)("weather.dailyForecast"),
|
|
189
189
|
class: "border-t border-surface-3"
|
|
190
190
|
}, {
|
|
191
191
|
default: e(() => [(g(!0), m(u, null, a(G.value.daily, (e, n) => (g(), m("button", {
|
|
@@ -194,24 +194,24 @@ var _ = {
|
|
|
194
194
|
class: t(["flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3", n === K.value ? "bg-surface-2" : "hover:bg-surface-1"]),
|
|
195
195
|
onClick: (e) => K.value = n
|
|
196
196
|
}, [
|
|
197
|
-
f("span",
|
|
197
|
+
f("span", me, i(Q(e.date, n, G.value.daily.length)), 1),
|
|
198
198
|
p(s, {
|
|
199
199
|
name: Z(e.weatherCode),
|
|
200
200
|
class: "text-18 text-word-2 shrink-0"
|
|
201
201
|
}, null, 8, ["name"]),
|
|
202
|
-
e.precipitationProbabilityMax > 0 ? (g(), m("span",
|
|
203
|
-
f("div",
|
|
204
|
-
], 10,
|
|
202
|
+
e.precipitationProbabilityMax > 0 ? (g(), m("span", P, i(e.precipitationProbabilityMax) + "% ", 1)) : (g(), m("span", F)),
|
|
203
|
+
f("div", I, [f("span", L, i(h(U)(e.maxTemp, "integer")) + "° ", 1), f("span", null, i(h(U)(e.minTemp, "integer")) + "°", 1)])
|
|
204
|
+
], 10, N))), 128))]),
|
|
205
205
|
_: 1
|
|
206
206
|
}, 8, ["modelValue", "title"])) : c("", !0)]),
|
|
207
207
|
_: 1
|
|
208
208
|
}),
|
|
209
|
-
G.value.airQuality ? (g(), m("div",
|
|
209
|
+
G.value.airQuality ? (g(), m("div", R, [
|
|
210
210
|
p(s, {
|
|
211
211
|
name: "ri:windy-line",
|
|
212
212
|
class: "text-14 text-word-3"
|
|
213
213
|
}),
|
|
214
|
-
f("span",
|
|
214
|
+
f("span", z, i(h(V)("weather.airQuality")), 1),
|
|
215
215
|
f("span", { class: t(["ml-auto px-8 py-2 text-11 font-semibold", $(G.value.airQuality.aqi).class]) }, i($(G.value.airQuality.aqi).label) + " (" + i(G.value.airQuality.aqi) + ") ", 3)
|
|
216
216
|
])) : c("", !0)
|
|
217
217
|
])) : c("", !0);
|
|
@@ -219,6 +219,6 @@ var _ = {
|
|
|
219
219
|
}
|
|
220
220
|
});
|
|
221
221
|
//#endregion
|
|
222
|
-
export {
|
|
222
|
+
export { B as default };
|
|
223
223
|
|
|
224
|
-
//# sourceMappingURL=PkToolShowWeather-
|
|
224
|
+
//# sourceMappingURL=PkToolShowWeather-ChJ5lB4K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkToolShowWeather-ChJ5lB4K.js","names":[],"sources":["../../../../packages/components/src/chat/PkToolShowWeather.vue","../../../../packages/components/src/chat/PkToolShowWeather.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n interface WeatherCurrent {\n temperature: number\n feelsLike: number\n humidity: number\n precipitation: number\n weatherCode: number\n windSpeed: number\n windDirection: number\n uvIndex: number\n }\n\n interface WeatherHourly {\n time: string\n temperature: number\n precipitationProbability: number\n precipitation: number\n weatherCode: number\n windSpeed: number\n }\n\n interface WeatherDaily {\n date: string\n maxTemp: number\n minTemp: number\n weatherCode: number\n precipitationSum: number\n precipitationProbabilityMax: number\n uvIndexMax: number\n sunrise: string\n sunset: string\n }\n\n interface AirQuality {\n aqi: number\n pm10: number\n pm25: number\n no2: number\n ozone: number\n }\n\n interface WeatherData {\n locationName: string\n latitude: number\n longitude: number\n timezone: string\n current: WeatherCurrent | null\n hourly: WeatherHourly[]\n daily: WeatherDaily[]\n airQuality: AirQuality | null\n }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n if (code === 0) {\n return 'wi:day-sunny'\n }\n if (code === 1) {\n return 'wi:day-sunny-overcast'\n }\n if (code === 2) {\n return 'wi:day-cloudy'\n }\n if (code === 3) {\n return 'wi:cloudy'\n }\n if (code === 45 || code === 48) {\n return 'wi:fog'\n }\n if (code >= 51 && code <= 55) {\n return 'wi:sprinkle'\n }\n if (code === 56 || code === 57) {\n return 'wi:sleet'\n }\n if (code >= 61 && code <= 65) {\n return 'wi:rain'\n }\n if (code === 66 || code === 67) {\n return 'wi:rain-mix'\n }\n if (code >= 71 && code <= 77) {\n return 'wi:snow'\n }\n if (code >= 80 && code <= 82) {\n return 'wi:showers'\n }\n if (code === 85 || code === 86) {\n return 'wi:snow-wind'\n }\n if (code === 95) {\n return 'wi:thunderstorm'\n }\n if (code === 96 || code === 99) {\n return 'wi:storm-showers'\n }\n return 'wi:na'\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n if (aqi <= 20) {\n return {\n label: $t('weather.aqiGood'),\n class: 'text-green-600 bg-green-50',\n }\n }\n if (aqi <= 40) {\n return {\n label: $t('weather.aqiFair'),\n class: 'text-lime-600 bg-lime-50',\n }\n }\n if (aqi <= 60) {\n return {\n label: $t('weather.aqiModerate'),\n class: 'text-yellow-600 bg-yellow-50',\n }\n }\n if (aqi <= 80) {\n return {\n label: $t('weather.aqiPoor'),\n class: 'text-orange-600 bg-orange-50',\n }\n }\n if (aqi <= 100) {\n return {\n label: $t('weather.aqiVeryPoor'),\n class: 'text-red-600 bg-red-50',\n }\n }\n return {\n label: $t('weather.aqiHazardous'),\n class: 'text-purple-700 bg-purple-50',\n }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-lg text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n interface WeatherCurrent {\n temperature: number\n feelsLike: number\n humidity: number\n precipitation: number\n weatherCode: number\n windSpeed: number\n windDirection: number\n uvIndex: number\n }\n\n interface WeatherHourly {\n time: string\n temperature: number\n precipitationProbability: number\n precipitation: number\n weatherCode: number\n windSpeed: number\n }\n\n interface WeatherDaily {\n date: string\n maxTemp: number\n minTemp: number\n weatherCode: number\n precipitationSum: number\n precipitationProbabilityMax: number\n uvIndexMax: number\n sunrise: string\n sunset: string\n }\n\n interface AirQuality {\n aqi: number\n pm10: number\n pm25: number\n no2: number\n ozone: number\n }\n\n interface WeatherData {\n locationName: string\n latitude: number\n longitude: number\n timezone: string\n current: WeatherCurrent | null\n hourly: WeatherHourly[]\n daily: WeatherDaily[]\n airQuality: AirQuality | null\n }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n if (code === 0) {\n return 'wi:day-sunny'\n }\n if (code === 1) {\n return 'wi:day-sunny-overcast'\n }\n if (code === 2) {\n return 'wi:day-cloudy'\n }\n if (code === 3) {\n return 'wi:cloudy'\n }\n if (code === 45 || code === 48) {\n return 'wi:fog'\n }\n if (code >= 51 && code <= 55) {\n return 'wi:sprinkle'\n }\n if (code === 56 || code === 57) {\n return 'wi:sleet'\n }\n if (code >= 61 && code <= 65) {\n return 'wi:rain'\n }\n if (code === 66 || code === 67) {\n return 'wi:rain-mix'\n }\n if (code >= 71 && code <= 77) {\n return 'wi:snow'\n }\n if (code >= 80 && code <= 82) {\n return 'wi:showers'\n }\n if (code === 85 || code === 86) {\n return 'wi:snow-wind'\n }\n if (code === 95) {\n return 'wi:thunderstorm'\n }\n if (code === 96 || code === 99) {\n return 'wi:storm-showers'\n }\n return 'wi:na'\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n if (aqi <= 20) {\n return {\n label: $t('weather.aqiGood'),\n class: 'text-green-600 bg-green-50',\n }\n }\n if (aqi <= 40) {\n return {\n label: $t('weather.aqiFair'),\n class: 'text-lime-600 bg-lime-50',\n }\n }\n if (aqi <= 60) {\n return {\n label: $t('weather.aqiModerate'),\n class: 'text-yellow-600 bg-yellow-50',\n }\n }\n if (aqi <= 80) {\n return {\n label: $t('weather.aqiPoor'),\n class: 'text-orange-600 bg-orange-50',\n }\n }\n if (aqi <= 100) {\n return {\n label: $t('weather.aqiVeryPoor'),\n class: 'text-red-600 bg-red-50',\n }\n }\n return {\n label: $t('weather.aqiHazardous'),\n class: 'text-purple-700 bg-purple-50',\n }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-lg text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { C as e, E as t, Gt as n, V as r, _ as i, b as a, ft as o, h as s, v as c, w as l, x as u, yt as d, z as f } from "./vue.runtime.esm-bundler-
|
|
2
|
-
import { o as p } from "./index.es-
|
|
3
|
-
import { n as m } from "./src-
|
|
4
|
-
import { t as h } from "./PkUrl-
|
|
1
|
+
import { C as e, E as t, Gt as n, V as r, _ as i, b as a, ft as o, h as s, v as c, w as l, x as u, yt as d, z as f } from "./vue.runtime.esm-bundler-Dq29dQrz.js";
|
|
2
|
+
import { o as p } from "./index.es-7fUi-rc0.js";
|
|
3
|
+
import { n as m } from "./src-BfoQF6Z3.js";
|
|
4
|
+
import { t as h } from "./PkUrl-CvztUywv.js";
|
|
5
5
|
//#region ../../packages/components/src/chat/PkToolShowWebPages.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var g = {
|
|
7
7
|
key: 0,
|
|
@@ -58,4 +58,4 @@ var g = {
|
|
|
58
58
|
//#endregion
|
|
59
59
|
export { w as default };
|
|
60
60
|
|
|
61
|
-
//# sourceMappingURL=PkToolShowWebPages-
|
|
61
|
+
//# sourceMappingURL=PkToolShowWebPages-CL2mYxh-.js.map
|
package/dist/_chunks/{PkToolShowWebPages-f-dHyxfD.js.map → PkToolShowWebPages-CL2mYxh-.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkToolShowWebPages-
|
|
1
|
+
{"version":3,"file":"PkToolShowWebPages-CL2mYxh-.js","names":["$t"],"sources":["../../../../packages/components/src/chat/PkToolShowWebPages.vue","../../../../packages/components/src/chat/PkToolShowWebPages.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return toolPart.value.input?.pages || []\n }\n return (toolPart.value.input?.pages || []).slice(0, 2)\n })\n const hasMore = computed(\n () => (toolPart.value.input?.pages || []).length > 2,\n )\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"flex flex-col gap-xs w-full\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"border border-surface-3 rounded-lg overflow-hidden hover:border-surface-4 transition-colors shrink-0\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"flex gap-8 p-8 hover:bg-surface-1 transition-colors\">\n <img\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n class=\"w-48 h-48 object-contain rounded shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"text-center\">\n <button\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: (toolPart?.input?.pages?.length || 0) - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return toolPart.value.input?.pages || []\n }\n return (toolPart.value.input?.pages || []).slice(0, 2)\n })\n const hasMore = computed(\n () => (toolPart.value.input?.pages || []).length > 2,\n )\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"flex flex-col gap-xs w-full\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"border border-surface-3 rounded-lg overflow-hidden hover:border-surface-4 transition-colors shrink-0\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"flex gap-8 p-8 hover:bg-surface-1 transition-colors\">\n <img\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n class=\"w-48 h-48 object-contain rounded shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"text-center\">\n <button\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: (toolPart?.input?.pages?.length || 0) - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EAKI,IAAM,IAAQ,GAIR,IAAW,QACA,EAAM,KAWtB,EAEK,IAAW,EAAI,GAAK,EACpB,IAAQ,QACN,EAAS,QACF,EAAS,MAAM,OAAO,SAAS,EAAC,IAEnC,EAAS,MAAM,OAAO,SAAS,EAAE,EAAE,MAAM,GAAG,EAAC,CACxD,EACK,IAAU,SACL,EAAS,MAAM,OAAO,SAAS,EAAE,EAAE,SAAS,EACvD;;;UAIU,EAAA,OAAO,UAAA,GAAA,EAAjB,EAmDK,MAnDL,GAmDK,EAAA,EAAA,GAAA,EAlDD,EA+BK,GAAA,MAAA,EA9BuB,EAAA,QAAhB,GAAM,YADlB,EA+BK,MAAA;IA7BA,KAAK;IACN,OAAM;OACN,EA0BI,KAAA;IAzBC,MAAM,EAAK;IACX,OAAOA,EAAAA,GAAE,cAAA;IACT,QAAQ,EAAA,EAAU,CAAC,EAAK,IAAG,GAAI,KAAA,IAAS;IACxC,KAAK,EAAA,EAAU,CAAC,EAAK,IAAG,GAAI,KAAA,IAAS;IACtC,OAAM;OAEI,EAAK,SAAA,GAAA,EADf,EAI2F,OAAA;;IAFtF,KAAK,EAAK;IACV,KAAK,EAAK;IACX,OAAM;gCACV,EAcM,OAdN,GAcM;IAbF,EAES,UAFT,GAES,EADF,EAAK,MAAK,EAAA,EAAA;IAEjB,EAIO,QAJP,GAIO,CAFH,EAAkD,GAAA;KAA1C,MAAK;KAAU,OAAM;QAC7B,EAAyB,GAAA,EAAjB,KAAK,EAAK,KAAA,EAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,CAAA;IAGZ,EAAK,eAAA,GAAA,EADf,EAII,KAJJ,GAII,EADG,EAAK,YAAW,EAAA,EAAA,IAAA,EAAA,IAAA,GAAA;0BAKzB,EAAA,SAAA,GAAA,EAAV,EAiBK,MAjBL,GAiBK,CAhBD,EAeS,UAAA;IAdL,OAAM;IACL,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAQ,CAAI,EAAA;OACpB,EAIsB,GAAA;IAHjB,MAA+B,EAAA,QAAQ,uBAAA;IAGxC,OAAM;4BAAY,MACtB,EACI,EAAA,QAAmCA,EAAAA,GAAE,kBAAA,GAA8CA,EAAAA,GAAE,mBAAA,EAAA,QAA4D,EAAA,OAAU,OAAO,OAAO,UAAM,KAAA,GAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,IAAA,GAAA,CAAA,CAAA,IAAA,EAAA,IAAA,GAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as e, Bt as t, E as n, Gt as r, V as i, W as a, _ as o, h as s, v as c, x as l, y as u, z as d } from "./vue.runtime.esm-bundler-
|
|
2
|
-
import { t as f } from "./_plugin-vue_export-helper-
|
|
1
|
+
import { $ as e, Bt as t, E as n, Gt as r, V as i, W as a, _ as o, h as s, v as c, x as l, y as u, z as d } from "./vue.runtime.esm-bundler-Dq29dQrz.js";
|
|
2
|
+
import { t as f } from "./_plugin-vue_export-helper-C6kC663S.js";
|
|
3
3
|
//#region ../../packages/components/src/PkUrl.vue?vue&type=script&setup=true&lang.ts
|
|
4
4
|
var p = { class: "pk-url__segment" }, m = /* @__PURE__ */ f(/* @__PURE__ */ n({
|
|
5
5
|
__name: "PkUrl",
|
|
@@ -88,4 +88,4 @@ var p = { class: "pk-url__segment" }, m = /* @__PURE__ */ f(/* @__PURE__ */ n({
|
|
|
88
88
|
//#endregion
|
|
89
89
|
export { m as t };
|
|
90
90
|
|
|
91
|
-
//# sourceMappingURL=PkUrl-
|
|
91
|
+
//# sourceMappingURL=PkUrl-CvztUywv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkUrl-CI17WkYu.js","names":[],"sources":["../../../../packages/components/src/PkUrl.vue","../../../../packages/components/src/PkUrl.vue","../../../../packages/components/src/PkUrl.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYI,IAAM,IAAQ,GAQR,IAAY,QAAe;AAC7B,OAAI;IACA,IAAM,IAAS,IAAI,IAAI,EAAM,IAAG,EAC5B,IAAW,EAAO;AAGtB,IAAI,EAAS,WAAW,OAAO,KAAE,IAAW,EAAS,UAAU,EAAC;IAGhE,IAAI,IAAW,EAAO;AACtB,IAAI,MAAa,QAAK,IAAW;IAGjC,IAAM,IAAW,EACZ,MAAM,IAAG,CACT,QAAQ,MAAY,EAAQ,SAAS,EAAC;AAE3C,WAAO;KACH,QAAQ;KACR;KACA,UAAU,IAAW;KACzB;WACI;AAEJ,WAAO;KACH,QAAQ,EAAM;KACd,UAAU,EAAE;KACZ,UAAU,EAAM;KACpB;;IAEP,EAEK,IAAe,QAAe;AAChC,OAAI,EAAU,MAAM,SAAS,UAAU,EAAM,UACzC,QAAO,EAAU;GAGrB,IAAM,IAAS,EAAU,MAAM,QACzB,IAAc,EAAU,MAAM;AAGpC,OAAI,EAAY,WAAW,EACvB,QAAO;IACH;IACA,UAAU,EAAE;IACZ,UAAU;IACd;GAGJ,IAAM,IAAqB,EAAC,EAGxB,IAAgB,EAAO;AAG3B,QAAK,IAAI,IAAI,EAAY,SAAS,GAAG,KAAK,GAAG,KAAK;IAC9C,IAAM,IAAU,EAAY;AAG5B,QAAI,EAAS,WAAW,EAEpB,CADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,EAAO;aACjB,IAAgB,EAAQ,SAAS,KAAK,EAAM,UAEnD,CADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,EAAO;SACrB;AACH,OAAS,QAAQ,MAAK;AACtB;;;AAIR,UAAO;IACH;IACA;IACA,UAAU,IAAS,MAAM,EAAS,KAAK,IAAA;IAC3C;IACH;yBAID,EAeY,EAdH,EAAA,QAAK,SAAA,IAAA,EAAA;GACV,OAAM;GACL,MAAM,EAAA,QAAQ,KAAA,IAAY,EAAM;GAChC,QAAQ,EAAA,QAAQ,KAAA,IAAY,EAAM;GAClC,KAAK,EAAA,QAAQ,KAAA,IAAY,EAAM;;oBAGvB,CAFT,EAES,QAAA,EAFF,OAAK,EAAA,CAAA,kBAAqB,EAAA,YAAW,CAAA,EAAA,EAAA,EACxC,EAAA,MAAa,OAAM,EAAA,EAAA,GAAA,EAAA,GAAA,EAEvB,EAKW,GAAA,MAAA,EAJoB,EAAA,MAAa,WAAhC,GAAS,wBACX,GAAK,EAAA,CAAA,AAAA,EAAA,OACX,EAAwC,QAAA,EAAlC,OAAM,qBAAmB,EAAC,KAAC,GAAA,EACjC,EAAkD,QAAlD,GAAkD,EAAjB,EAAO,EAAA,EAAA,CAAA,EAAA,GAAA"}
|
|
1
|
+
{"version":3,"file":"PkUrl-CvztUywv.js","names":[],"sources":["../../../../packages/components/src/PkUrl.vue","../../../../packages/components/src/PkUrl.vue","../../../../packages/components/src/PkUrl.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) hostname = hostname.substring(4)\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') pathname = ''\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n return {\n domain: props.url,\n segments: [],\n fullPath: props.url,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength)\n return parsedUrl.value\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYI,IAAM,IAAQ,GAQR,IAAY,QAAe;AAC7B,OAAI;IACA,IAAM,IAAS,IAAI,IAAI,EAAM,IAAG,EAC5B,IAAW,EAAO;AAGtB,IAAI,EAAS,WAAW,OAAO,KAAE,IAAW,EAAS,UAAU,EAAC;IAGhE,IAAI,IAAW,EAAO;AACtB,IAAI,MAAa,QAAK,IAAW;IAGjC,IAAM,IAAW,EACZ,MAAM,IAAG,CACT,QAAQ,MAAY,EAAQ,SAAS,EAAC;AAE3C,WAAO;KACH,QAAQ;KACR;KACA,UAAU,IAAW;KACzB;WACI;AAEJ,WAAO;KACH,QAAQ,EAAM;KACd,UAAU,EAAE;KACZ,UAAU,EAAM;KACpB;;IAEP,EAEK,IAAe,QAAe;AAChC,OAAI,EAAU,MAAM,SAAS,UAAU,EAAM,UACzC,QAAO,EAAU;GAGrB,IAAM,IAAS,EAAU,MAAM,QACzB,IAAc,EAAU,MAAM;AAGpC,OAAI,EAAY,WAAW,EACvB,QAAO;IACH;IACA,UAAU,EAAE;IACZ,UAAU;IACd;GAGJ,IAAM,IAAqB,EAAC,EAGxB,IAAgB,EAAO;AAG3B,QAAK,IAAI,IAAI,EAAY,SAAS,GAAG,KAAK,GAAG,KAAK;IAC9C,IAAM,IAAU,EAAY;AAG5B,QAAI,EAAS,WAAW,EAEpB,CADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,EAAO;aACjB,IAAgB,EAAQ,SAAS,KAAK,EAAM,UAEnD,CADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,EAAO;SACrB;AACH,OAAS,QAAQ,MAAK;AACtB;;;AAIR,UAAO;IACH;IACA;IACA,UAAU,IAAS,MAAM,EAAS,KAAK,IAAA;IAC3C;IACH;yBAID,EAeY,EAdH,EAAA,QAAK,SAAA,IAAA,EAAA;GACV,OAAM;GACL,MAAM,EAAA,QAAQ,KAAA,IAAY,EAAM;GAChC,QAAQ,EAAA,QAAQ,KAAA,IAAY,EAAM;GAClC,KAAK,EAAA,QAAQ,KAAA,IAAY,EAAM;;oBAGvB,CAFT,EAES,QAAA,EAFF,OAAK,EAAA,CAAA,kBAAqB,EAAA,YAAW,CAAA,EAAA,EAAA,EACxC,EAAA,MAAa,OAAM,EAAA,EAAA,GAAA,EAAA,GAAA,EAEvB,EAKW,GAAA,MAAA,EAJoB,EAAA,MAAa,WAAhC,GAAS,wBACX,GAAK,EAAA,CAAA,AAAA,EAAA,OACX,EAAwC,QAAA,EAAlC,OAAM,qBAAmB,EAAC,KAAC,GAAA,EACjC,EAAkD,QAAlD,GAAkD,EAAjB,EAAO,EAAA,EAAA,CAAA,EAAA,GAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as e, Bt as t, C as n, E as r, Gt as i, H as a, L as o, O as s, Q as c, S as l, Vt as u, Y as d, Z as f, _ as p, _t as m, c as ee, et as te, ft as ne, gt as h, j as g, k as _, q as v, st as y, v as re, w as ie, x as ae, yt as b, z as oe } from "./vue.runtime.esm-bundler-
|
|
2
|
-
//#region ../../node_modules/.pnpm/@volverjs+ui-vue@0.0.13-beta.8_@volverjs+style@0.1.24-beta.3_@vueuse+core@14.3.0_vue@3.
|
|
1
|
+
import { $ as e, Bt as t, C as n, E as r, Gt as i, H as a, L as o, O as s, Q as c, S as l, Vt as u, Y as d, Z as f, _ as p, _t as m, c as ee, et as te, ft as ne, gt as h, j as g, k as _, q as v, st as y, v as re, w as ie, x as ae, yt as b, z as oe } from "./vue.runtime.esm-bundler-Dq29dQrz.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/@volverjs+ui-vue@0.0.13-beta.8_@volverjs+style@0.1.24-beta.3_@vueuse+core@14.3.0_vue@3._b0d461e87ded044697d58df431d5928d/node_modules/@volverjs/ui-vue/dist/components/VvCheckbox/VvCheckbox.es.js
|
|
3
3
|
var x = /* @__PURE__ */ (function(e) {
|
|
4
4
|
return e.local = "local", e.session = "session", e;
|
|
5
5
|
})({}), S = /* @__PURE__ */ (function(e) {
|
|
@@ -511,4 +511,4 @@ var xe = ["for"], Se = [
|
|
|
511
511
|
//#endregion
|
|
512
512
|
export { Ce as default };
|
|
513
513
|
|
|
514
|
-
//# sourceMappingURL=VvCheckbox.es-
|
|
514
|
+
//# sourceMappingURL=VvCheckbox.es-ohF87NOe.js.map
|