@meistrari/chat-nuxt 3.13.0-rc.0 → 3.13.0-rc.2

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "3.13.0-rc.0",
4
+ "version": "3.13.0-rc.2",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { onClickOutside } from "@vueuse/core";
2
+ import { onClickOutside, useElementBounding, useWindowSize } from "@vueuse/core";
3
3
  import { useEmbedConfig } from "../../embed/composables/embed-config";
4
4
  import { useCitationPanel } from "../composables/citation-panel";
5
5
  import { useCitations } from "../composables/citations";
@@ -20,9 +20,55 @@ const status = computed(() => entry.value?.status.value ?? "loading");
20
20
  const meta = computed(() => entry.value?.meta.value ?? null);
21
21
  const displayLabel = computed(() => props.label?.trim() || meta.value?.identifier || meta.value?.title || "Documento");
22
22
  const rootEl = ref(null);
23
+ const popoverEl = ref(null);
23
24
  const popoverOpen = ref(false);
24
25
  onClickOutside(rootEl, () => {
25
26
  popoverOpen.value = false;
27
+ }, {
28
+ ignore: [popoverEl]
29
+ });
30
+ const POPOVER_WIDTH = 300;
31
+ const POPOVER_GAP = 6;
32
+ const VIEWPORT_PADDING = 8;
33
+ const triggerBounds = useElementBounding(rootEl);
34
+ const popoverBounds = useElementBounding(popoverEl);
35
+ const viewport = useWindowSize();
36
+ const popoverStyle = computed(() => {
37
+ const maxHeight = Math.max(
38
+ 0,
39
+ viewport.height.value - VIEWPORT_PADDING * 2
40
+ );
41
+ const maxLeft = Math.max(
42
+ VIEWPORT_PADDING,
43
+ viewport.width.value - POPOVER_WIDTH - VIEWPORT_PADDING
44
+ );
45
+ const left = Math.min(
46
+ Math.max(triggerBounds.left.value, VIEWPORT_PADDING),
47
+ maxLeft
48
+ );
49
+ const fitsAbove = triggerBounds.top.value >= popoverBounds.height.value + POPOVER_GAP + VIEWPORT_PADDING;
50
+ const fitsBelow = viewport.height.value - triggerBounds.bottom.value >= popoverBounds.height.value + POPOVER_GAP + VIEWPORT_PADDING;
51
+ const constrainedStyle = {
52
+ left: `${left}px`,
53
+ maxHeight: `${maxHeight}px`,
54
+ overflowY: "auto"
55
+ };
56
+ if (fitsAbove) {
57
+ return {
58
+ ...constrainedStyle,
59
+ bottom: `${viewport.height.value - triggerBounds.top.value + POPOVER_GAP}px`
60
+ };
61
+ }
62
+ if (fitsBelow) {
63
+ return {
64
+ ...constrainedStyle,
65
+ top: `${triggerBounds.bottom.value + POPOVER_GAP}px`
66
+ };
67
+ }
68
+ return {
69
+ ...constrainedStyle,
70
+ top: `${VIEWPORT_PADDING}px`
71
+ };
26
72
  });
27
73
  function togglePopover() {
28
74
  if (status.value === "loading")
@@ -99,88 +145,92 @@ const badgeClasses = computed(() => BADGE_TONE_CLASSES[meta.value?.badge?.tone ?
99
145
  @click="togglePopover"
100
146
  ><span :class="chipIcon" class="citation-ref-icon" />{{ displayLabel }}</button>
101
147
 
102
- <div
103
- v-if="popoverOpen"
104
- absolute bottom-full left-0 mb-6px z-50
105
- w-300px
106
- bg-white
107
- border-0.5px border-solid border-neutral-300
108
- rounded-12px p-12px
109
- shadow-lg
110
- cursor-default
111
- flex="~ col" gap-8px
112
- >
113
- <template v-if="status === 'unresolved'">
114
- <div flex items-start gap-6px>
115
- <span i-ph-warning-circle text-14px text-amber-600 mt-2px flex-shrink-0 />
116
- <p text-12px leading-16px text-neutral-700>
117
- Não foi possível verificar esta referência. Ela pode não existir ou não estar disponível para o seu perfil.
118
- </p>
119
- </div>
120
- <button
121
- type="button"
122
- self-start text-12px leading-16px text-neutral-700 underline cursor-pointer
123
- @click="retry"
124
- >
125
- Tentar novamente
126
- </button>
127
- </template>
128
-
129
- <template v-else-if="meta">
130
- <div flex="~ col" gap-2px>
131
- <p text-13px leading-18px font-580 text-neutral-900>
132
- {{ meta.title }}
133
- </p>
134
- <p v-if="meta.sourceLabel || meta.identifier" text-12px leading-16px text-neutral-600>
135
- {{ [meta.sourceLabel, meta.identifier].filter(Boolean).join(" \xB7 ") }}
136
- </p>
137
- <p v-if="formattedDate" text-12px leading-16px text-neutral-500>
138
- {{ meta.dateLabel ? `${meta.dateLabel}: ` : "" }}{{ formattedDate }}
139
- </p>
140
- </div>
141
-
142
- <span
143
- v-if="meta.badge"
144
- self-start px-6px py-1px rounded-4px text-11px leading-15px font-580
145
- :class="badgeClasses"
146
- >
147
- {{ meta.badge.label }}
148
- </span>
149
-
150
- <p v-if="meta.snippet" text-12px leading-17px text-neutral-600 line-clamp-3>
151
- {{ meta.snippet }}
152
- </p>
153
-
154
- <div v-if="canOpenDocument || safeSourceUrl" flex items-center gap-12px pt-2px>
148
+ <Teleport to="body">
149
+ <div
150
+ v-if="popoverOpen"
151
+ ref="popoverEl"
152
+ class="citation-ref-popover"
153
+ :style="popoverStyle"
154
+ w-300px
155
+ bg-white
156
+ border-0.5px border-solid border-neutral-300
157
+ rounded-12px p-12px
158
+ shadow-lg
159
+ cursor-default
160
+ flex="~ col" gap-8px
161
+ >
162
+ <template v-if="status === 'unresolved'">
163
+ <div flex items-start gap-6px>
164
+ <span i-ph-warning-circle text-14px text-amber-600 mt-2px flex-shrink-0 />
165
+ <p text-12px leading-16px text-neutral-700>
166
+ Não foi possível verificar esta referência. Ela pode não existir ou não estar disponível para o seu perfil.
167
+ </p>
168
+ </div>
155
169
  <button
156
- v-if="canOpenDocument"
157
170
  type="button"
158
- inline-flex items-center gap-4px
159
- text-12px leading-16px font-580 text-neutral-900
160
- cursor-pointer hover:underline
161
- @click="openDocument"
171
+ self-start text-12px leading-16px text-neutral-700 underline cursor-pointer
172
+ @click="retry"
162
173
  >
163
- <span i-ph-file-magnifying-glass text-13px />
164
- Ver documento
174
+ Tentar novamente
165
175
  </button>
166
- <a
167
- v-if="safeSourceUrl"
168
- :href="safeSourceUrl"
169
- target="_blank"
170
- rel="noopener noreferrer"
171
- inline-flex items-center gap-4px
172
- text-12px leading-16px text-neutral-600
173
- hover:underline
176
+ </template>
177
+
178
+ <template v-else-if="meta">
179
+ <div flex="~ col" gap-2px>
180
+ <p text-13px leading-18px font-580 text-neutral-900>
181
+ {{ meta.title }}
182
+ </p>
183
+ <p v-if="meta.sourceLabel || meta.identifier" text-12px leading-16px text-neutral-600>
184
+ {{ [meta.sourceLabel, meta.identifier].filter(Boolean).join(" \xB7 ") }}
185
+ </p>
186
+ <p v-if="formattedDate" text-12px leading-16px text-neutral-500>
187
+ {{ meta.dateLabel ? `${meta.dateLabel}: ` : "" }}{{ formattedDate }}
188
+ </p>
189
+ </div>
190
+
191
+ <span
192
+ v-if="meta.badge"
193
+ self-start px-6px py-1px rounded-4px text-11px leading-15px font-580
194
+ :class="badgeClasses"
174
195
  >
175
- <span i-ph-arrow-square-out text-13px />
176
- Abrir na fonte
177
- </a>
178
- </div>
179
- </template>
180
- </div>
196
+ {{ meta.badge.label }}
197
+ </span>
198
+
199
+ <p v-if="meta.snippet" text-12px leading-17px text-neutral-600 line-clamp-3>
200
+ {{ meta.snippet }}
201
+ </p>
202
+
203
+ <div v-if="canOpenDocument || safeSourceUrl" flex items-center gap-12px pt-2px>
204
+ <button
205
+ v-if="canOpenDocument"
206
+ type="button"
207
+ inline-flex items-center gap-4px
208
+ text-12px leading-16px font-580 text-neutral-900
209
+ cursor-pointer hover:underline
210
+ @click="openDocument"
211
+ >
212
+ <span i-ph-file-magnifying-glass text-13px />
213
+ Ver documento
214
+ </button>
215
+ <a
216
+ v-if="safeSourceUrl"
217
+ :href="safeSourceUrl"
218
+ target="_blank"
219
+ rel="noopener noreferrer"
220
+ inline-flex items-center gap-4px
221
+ text-12px leading-16px text-neutral-600
222
+ hover:underline
223
+ >
224
+ <span i-ph-arrow-square-out text-13px />
225
+ Abrir na fonte
226
+ </a>
227
+ </div>
228
+ </template>
229
+ </div>
230
+ </Teleport>
181
231
  </span>
182
232
  </template>
183
233
 
184
234
  <style scoped>
185
- .citation-ref{display:inline;position:relative}.citation-ref-anchor{background:transparent;border:0;border-radius:5px;color:inherit;cursor:pointer;display:inline;font:inherit;margin:0 -2px;padding:1px 3px;text-decoration:underline;text-decoration-color:#a3a3a3;text-decoration-style:dotted;text-decoration-thickness:1px;text-underline-offset:3px;transition:background-color .15s ease,text-decoration-color .15s ease}.citation-ref-anchor:hover{background-color:#f5f5f5;text-decoration-color:#525252}.citation-ref-anchor--loading{cursor:default;opacity:.6;text-decoration-color:#d4d4d4}.citation-ref-anchor--unresolved{text-decoration-color:#f59e0b}.citation-ref-anchor--unresolved:hover{background-color:#fffbeb}.citation-ref-icon{display:inline-block;font-size:.85em;margin-right:.25em;vertical-align:-.08em}
235
+ .citation-ref{display:inline;position:relative}.citation-ref-popover{position:fixed;z-index:50}.citation-ref-anchor{background:transparent;border:0;border-radius:5px;color:inherit;cursor:pointer;display:inline;font:inherit;margin:0 -2px;padding:1px 3px;text-decoration:underline;text-decoration-color:#a3a3a3;text-decoration-style:dotted;text-decoration-thickness:1px;text-underline-offset:3px;transition:background-color .15s ease,text-decoration-color .15s ease}.citation-ref-anchor:hover{background-color:#f5f5f5;text-decoration-color:#525252}.citation-ref-anchor--loading{cursor:default;opacity:.6;text-decoration-color:#d4d4d4}.citation-ref-anchor--unresolved{text-decoration-color:#f59e0b}.citation-ref-anchor--unresolved:hover{background-color:#fffbeb}.citation-ref-icon{display:inline-block;font-size:.85em;margin-right:.25em;vertical-align:-.08em}
186
236
  </style>
@@ -9,6 +9,7 @@ import ChatMobileShell from "./mobile/chat-mobile-shell.vue";
9
9
  import { normalizeConversationId } from "../../conversations/scope";
10
10
  import { resolveChatFeatures } from "../feature-config";
11
11
  import { resolveConversationCreator } from "../../conversations/creator";
12
+ import { buildConversationShareUrl } from "../conversation-share-url";
12
13
  import {
13
14
  resolveTelaAgentInputs,
14
15
  useChat
@@ -59,6 +60,7 @@ function toggleSidebarCollapsed() {
59
60
  isSidebarCollapsed.value = !isSidebarCollapsed.value;
60
61
  }
61
62
  const chatApi = useChatApi();
63
+ const route = useRoute();
62
64
  const embedConfig = useEmbedConfig();
63
65
  const chatAction = useChatAction();
64
66
  const { user: authUser, activeOrganization, logout } = useChatAuth();
@@ -117,8 +119,9 @@ const {
117
119
  closePreview
118
120
  } = useFilePreviewPanel();
119
121
  const { isOpen: isCitationPanelOpen } = useCitationPanel();
122
+ const sharedConversationId = typeof route.query.conversation === "string" ? route.query.conversation : null;
120
123
  const activeConversationId = ref(
121
- normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId)
124
+ normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId) ?? normalizeConversationId(sharedConversationId)
122
125
  );
123
126
  const loadingConversationId = ref(null);
124
127
  const isReady = ref(false);
@@ -643,8 +646,14 @@ function cancelEditing() {
643
646
  }
644
647
  const copiedToClipboard = ref(false);
645
648
  async function handleShare() {
649
+ if (!currentConversation.value)
650
+ return;
646
651
  try {
647
- await navigator.clipboard.writeText(window.location.href);
652
+ const shareUrl = buildConversationShareUrl(
653
+ window.location.href,
654
+ currentConversation.value.id
655
+ );
656
+ await navigator.clipboard.writeText(shareUrl);
648
657
  copiedToClipboard.value = true;
649
658
  statusToast.update({ text: "Link copiado", icon: "i-ph-check" });
650
659
  setTimeout(() => {
@@ -0,0 +1 @@
1
+ export declare function buildConversationShareUrl(currentHref: string, conversationId: string): string;
@@ -0,0 +1,5 @@
1
+ export function buildConversationShareUrl(currentHref, conversationId) {
2
+ const shareUrl = new URL(currentHref);
3
+ shareUrl.searchParams.set("conversation", conversationId);
4
+ return shareUrl.href;
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "3.13.0-rc.0",
3
+ "version": "3.13.0-rc.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {