@meistrari/chat-nuxt 3.9.1 → 3.10.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.
Files changed (87) hide show
  1. package/README.md +50 -440
  2. package/dist/module.d.mts +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +56 -3
  5. package/dist/runtime/assets/css/markstream.css +1 -1
  6. package/dist/runtime/conversations/components/chat-conversation-creator-filter.vue +11 -67
  7. package/dist/runtime/conversations/components/chat-conversation-item.d.vue.ts +2 -1
  8. package/dist/runtime/conversations/components/chat-conversation-item.vue +29 -33
  9. package/dist/runtime/conversations/components/chat-conversation-item.vue.d.ts +2 -1
  10. package/dist/runtime/conversations/components/chat-conversation-list.d.vue.ts +0 -1
  11. package/dist/runtime/conversations/components/chat-conversation-list.vue +117 -158
  12. package/dist/runtime/conversations/components/chat-conversation-list.vue.d.ts +0 -1
  13. package/dist/runtime/conversations/components/chat-conversation-new-group-button.vue +34 -73
  14. package/dist/runtime/conversations/components/chat-conversation-search.vue +1 -21
  15. package/dist/runtime/conversations/components/chat-widget-history-list.d.vue.ts +12 -0
  16. package/dist/runtime/conversations/components/chat-widget-history-list.vue +27 -0
  17. package/dist/runtime/conversations/components/chat-widget-history-list.vue.d.ts +12 -0
  18. package/dist/runtime/conversations/composables/conversation-groups.d.ts +1 -0
  19. package/dist/runtime/conversations/composables/conversation-groups.js +2 -0
  20. package/dist/runtime/conversations/composables/conversation-item.js +4 -4
  21. package/dist/runtime/conversations/composables/conversation-list.js +14 -5
  22. package/dist/runtime/embed/components/chat-configuration-modal.d.vue.ts +3 -3
  23. package/dist/runtime/embed/components/chat-configuration-modal.vue.d.ts +3 -3
  24. package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +6 -3
  25. package/dist/runtime/embed/components/chat-embed-inner.vue +365 -152
  26. package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +6 -3
  27. package/dist/runtime/embed/components/chat-embed.d.vue.ts +31 -4
  28. package/dist/runtime/embed/components/chat-embed.vue +10 -4
  29. package/dist/runtime/embed/components/chat-embed.vue.d.ts +31 -4
  30. package/dist/runtime/embed/components/chat-topbar.vue +83 -85
  31. package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +5 -3
  32. package/dist/runtime/embed/components/meistrari-chat-embed.vue +118 -57
  33. package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +5 -3
  34. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.d.vue.ts +0 -1
  35. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +2 -45
  36. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue.d.ts +0 -1
  37. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.d.vue.ts +9 -5
  38. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue +14 -25
  39. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue.d.ts +9 -5
  40. package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +6 -6
  41. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +2 -3
  42. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +6 -6
  43. package/dist/runtime/embed/feature-config.d.ts +7 -0
  44. package/dist/runtime/embed/types.d.ts +47 -8
  45. package/dist/runtime/files/icons.d.ts +1 -1
  46. package/dist/runtime/files/icons.js +1 -1
  47. package/dist/runtime/messages/components/chat-mention-dropdown.d.vue.ts +6 -1
  48. package/dist/runtime/messages/components/chat-mention-dropdown.vue +46 -22
  49. package/dist/runtime/messages/components/chat-mention-dropdown.vue.d.ts +6 -1
  50. package/dist/runtime/messages/components/chat-message-bubble.vue +53 -71
  51. package/dist/runtime/messages/components/chat-message-feedback.vue +25 -229
  52. package/dist/runtime/messages/components/chat-message-input.vue +176 -134
  53. package/dist/runtime/messages/components/chat-message-list.d.vue.ts +6 -0
  54. package/dist/runtime/messages/components/chat-message-list.vue +27 -23
  55. package/dist/runtime/messages/components/chat-message-list.vue.d.ts +6 -0
  56. package/dist/runtime/messages/components/chat-model-selector.vue +10 -22
  57. package/dist/runtime/messages/components/reasoning/chat-reasoning-message.vue +2 -3
  58. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +60 -69
  59. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +3 -9
  60. package/dist/runtime/messages/components/widgets/chat-bash-widget.vue +3 -12
  61. package/dist/runtime/messages/components/widgets/chat-doc-sdk-widget.vue +3 -12
  62. package/dist/runtime/messages/components/widgets/chat-generic-tool-widget.vue +3 -12
  63. package/dist/runtime/messages/components/widgets/chat-grep-widget.vue +7 -17
  64. package/dist/runtime/messages/components/widgets/chat-read-widget.vue +7 -17
  65. package/dist/runtime/messages/components/widgets/chat-tela-skill-widget.vue +4 -13
  66. package/dist/runtime/messages/components/widgets/chat-thinking-widget.vue +11 -22
  67. package/dist/runtime/messages/components/widgets/chat-web-search-widget.vue +13 -40
  68. package/dist/runtime/messages/components/widgets/chat-workstation-query-widget.vue +52 -65
  69. package/dist/runtime/messages/components/widgets/chat-write-widget.vue +8 -18
  70. package/dist/runtime/messages/composables/mention-autocomplete.js +4 -0
  71. package/dist/runtime/messages/message-reasoning.js +4 -0
  72. package/dist/runtime/messages/message-state.js +1 -0
  73. package/dist/runtime/public/files/generic.svg +2 -5
  74. package/dist/runtime/public/files/image.svg +2 -1
  75. package/dist/runtime/types/embed.d.ts +1 -1
  76. package/dist/runtime/types/schemas/chat/conversations.d.ts +2 -0
  77. package/dist/runtime/types/schemas/chat/conversations.js +3 -0
  78. package/dist/runtime/types/schemas/chat/messages.d.ts +4 -0
  79. package/dist/runtime/types/schemas/chat/messages.js +7 -0
  80. package/dist/types.d.mts +1 -1
  81. package/package.json +5 -4
  82. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.d.vue.ts +0 -23
  83. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue +0 -75
  84. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue.d.ts +0 -23
  85. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.d.vue.ts +0 -37
  86. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue +0 -125
  87. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue.d.ts +0 -37
@@ -7,8 +7,7 @@ const props = defineProps({
7
7
  selectConversation: { type: Function, required: false },
8
8
  resetConversation: { type: Function, required: false },
9
9
  startConversation: { type: Function, required: false },
10
- loading: { type: Boolean, required: false },
11
- hideFolderHint: { type: Boolean, required: false }
10
+ loading: { type: Boolean, required: false }
12
11
  });
13
12
  const {
14
13
  conversationSearch,
@@ -20,8 +19,6 @@ const {
20
19
  ungroupedConversations,
21
20
  ungroupedDropTarget,
22
21
  ungroupedConversationLabel,
23
- shouldShowUngroupedHeader,
24
- showGroupCreationPrompt,
25
22
  showDeleteGroupModal,
26
23
  showDeleteGroupConversationsModal,
27
24
  groupActionLoading,
@@ -82,44 +79,12 @@ const {
82
79
  </p>
83
80
  </div>
84
81
 
85
- <template v-else>
86
- <div
87
- v-if="showGroupCreationPrompt && !hideFolderHint"
88
- mx-8px
89
- flex="~ col" gap-10px
90
- >
91
- <div h-20px flex items-center px-4px>
92
- <span text-12px font-semibold text-neutral-400 uppercase style="letter-spacing: 0">
93
- PASTAS
94
- </span>
95
- </div>
96
- <div flex="~ col" gap-6px>
97
- <div
98
- h-36px px-10px
99
- flex items-center gap-10px
100
- rounded-8px
101
- b=".5px dashed neutral-200"
102
- >
103
- <span i-ph-folder text-16px text-neutral-400 shrink-0 />
104
- <span h-10px w-120px rounded-full bg-neutral-100 />
105
- </div>
106
- <div
107
- h-36px px-10px
108
- flex items-center gap-10px
109
- rounded-8px
110
- b=".5px dashed neutral-200"
111
- >
112
- <span i-ph-folder text-16px text-neutral-400 shrink-0 />
113
- <span h-10px w-84px rounded-full bg-neutral-100 />
114
- </div>
115
- </div>
116
- <p px-4px text-14px text-neutral-500 leading-20px>
117
- Suas pastas aparecem aqui. Crie uma para começar a agrupar conversas.
118
- </p>
119
- <ChatConversationNewGroupButton label="Criar pasta" variant="empty-state" />
120
- </div>
121
-
82
+ <div v-else flex="~ col" gap-4px mt-4px>
122
83
  <div v-if="groupItems.length > 0" flex="~ col" gap-2px>
84
+ <span body-12-medium text-secondary pl-10px>
85
+ Pastas · {{ groupItems.length }}
86
+ </span>
87
+
123
88
  <div
124
89
  v-for="groupBucket in groupItems"
125
90
  :key="groupBucket.group.id"
@@ -133,100 +98,99 @@ const {
133
98
  @drop.prevent="handleConversationDrop($event, groupBucket.group.id)"
134
99
  >
135
100
  <div
136
- v-if="groupBucket.isRenaming"
137
- h-32px w-full px-8px
138
- flex items-center gap-8px
139
- rounded-8px
140
- :class="groupBucket.dropTarget ? 'bg-neutral-200' : ''"
101
+ rounded-10px
102
+ class="group"
103
+ :class="groupBucket.dropTarget ? '' : groupBucket.open ? 'bg-muted' : 'hover:bg-subtle'"
141
104
  >
142
- <span
143
- i-ph-caret-right
144
- text-12px text-neutral-400
145
- transition-transform
146
- :class="groupBucket.open && 'rotate-90'"
147
- />
148
- <span
149
- :class="groupBucket.folderIcon"
150
- text-16px text-neutral-500 shrink-0
151
- />
152
- <div
153
- flex-1 min-w-0 flex items-center
154
- pb-1px
155
- b-b=".5px solid #A3A3A3"
156
- :class="renameGroupError && 'border-red-500'"
157
- >
158
- <input
159
- :ref="(element) => setRenameGroupInputRef(element, groupBucket.group.id)"
160
- v-model="renameGroupName"
161
- type="text"
162
- autocomplete="off"
163
- maxlength="80"
164
- aria-label="Nome da pasta"
165
- w-full min-w-0
166
- bg-transparent border-none outline-none
167
- text-14px font-semibold text-neutral-700 leading-18px
168
- p-0
169
- :disabled="groupActionLoading"
170
- @blur="handleRenameGroupBlur"
171
- @keydown.enter.prevent="submitRenameGroup"
172
- @keydown.escape.prevent.stop="cancelRenameGroup"
173
- @click.stop
174
- @dblclick.stop
175
- >
176
- </div>
177
- </div>
178
-
179
- <div v-else rounded-8px class="group" :class="groupBucket.dropTarget ? '' : 'hover:bg-neutral-100'">
180
- <div h-32px w-full px-8px flex items-center gap-4px text-left>
181
- <button
182
- type="button"
183
- h-full flex-1 min-w-0
184
- flex items-center gap-8px
185
- text-left
186
- cursor-pointer
187
- @click="toggleGroup(groupBucket.group.id)"
188
- >
189
- <span
190
- i-ph-caret-right
191
- text-12px text-neutral-400
192
- transition-transform
193
- :class="groupBucket.open && 'rotate-90'"
194
- />
195
- <span
196
- :class="groupBucket.folderIcon"
197
- text-16px text-neutral-500 shrink-0
105
+ <div h-32px w-full pl-10px pr-4px flex items-center gap-8px text-left>
106
+ <template v-if="groupBucket.isRenaming">
107
+ <TelaIcon
108
+ :name="groupBucket.folderIcon"
109
+ size="16px"
110
+ color="icon-secondary"
111
+ shrink-0
198
112
  />
199
- <span flex-1 min-w-0 truncate text-14px font-semibold text-neutral-900 leading-18px>
200
- {{ groupBucket.group.name }}
201
- </span>
202
- <span v-if="groupBucket.conversationCountLabel" text-13px font-medium text-neutral-400 tabular-nums>
203
- {{ groupBucket.conversationCountLabel }}
204
- </span>
205
- </button>
113
+ <div
114
+ relative
115
+ flex-1 min-w-0 flex items-center
116
+ mr-4px
117
+ >
118
+ <input
119
+ :ref="(element) => setRenameGroupInputRef(element, groupBucket.group.id)"
120
+ v-model="renameGroupName"
121
+ type="text"
122
+ autocomplete="off"
123
+ maxlength="80"
124
+ aria-label="Nome da pasta"
125
+ w-full min-w-0
126
+ bg-transparent border-none outline-none
127
+ body-14-medium text-primary
128
+ p-0
129
+ :disabled="groupActionLoading"
130
+ @blur="handleRenameGroupBlur"
131
+ @keydown.enter.prevent="submitRenameGroup"
132
+ @keydown.escape.prevent.stop="cancelRenameGroup"
133
+ @click.stop
134
+ @dblclick.stop
135
+ >
136
+ <div
137
+ aria-hidden="true"
138
+ absolute inset-x-0 bottom--2px h-0.5px pointer-events-none
139
+ :class="renameGroupError ? 'bg-red-500' : 'bg-border'"
140
+ />
141
+ </div>
142
+ </template>
206
143
 
207
- <div
208
- flex items-center justify-center shrink-0
209
- class="opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity"
210
- >
211
- <TelaDropdownMenu
212
- :items="groupBucket.menuItems"
213
- align="end"
214
- content-class="chat-sidebar-floating"
144
+ <template v-else>
145
+ <button
146
+ type="button"
147
+ h-full flex-1 min-w-0
148
+ flex items-center gap-8px
149
+ text-left
150
+ cursor-pointer
151
+ @click="toggleGroup(groupBucket.group.id)"
215
152
  >
216
- <button
217
- type="button"
218
- aria-label="Ações da pasta"
219
- p-4px
220
- rounded-6px
221
- hover:bg-neutral-200
222
- transition-colors
223
- cursor-pointer
224
- @click.prevent.stop
153
+ <TelaIcon
154
+ :name="groupBucket.folderIcon"
155
+ size="16px"
156
+ color="icon-secondary"
157
+ shrink-0
158
+ />
159
+ <div flex items-center gap-6px>
160
+ <span min-w-0 truncate body-14-medium :class="groupBucket.open ? 'text-primary' : 'text-secondary group-hover:text-primary'">
161
+ {{ groupBucket.group.name }}
162
+ </span>
163
+ <TelaAnimatedNumber v-if="groupBucket.conversationCountLabel" :value="groupBucket.conversationCountLabel" body-12-medium text-tertiary />
164
+ </div>
165
+ </button>
166
+
167
+ <div
168
+ flex items-center justify-center shrink-0
169
+ class="opacity-0 group-hover:opacity-100 focus-within:opacity-100 [&:has([data-state=open])]:opacity-100"
170
+ >
171
+ <TelaDropdownMenu
172
+ :items="groupBucket.menuItems"
173
+ content-class="chat-sidebar-floating"
225
174
  >
226
- <div i-ph-dots-three-vertical text-16px text-neutral-400 />
227
- </button>
228
- </TelaDropdownMenu>
229
- </div>
175
+ <button
176
+ type="button"
177
+ aria-label="Ações da pasta"
178
+ p-4px mt-2px
179
+ rounded-8px
180
+ hover:bg-lowered
181
+ cursor-pointer
182
+ class="group data-[state=open]:!bg-lowered"
183
+ @click.prevent.stop
184
+ >
185
+ <TelaIcon
186
+ name="i-ph-dots-three"
187
+ size="18px"
188
+ color="icon-subtle group-hover:icon-tertiary group-data-[state=open]:icon-tertiary"
189
+ />
190
+ </button>
191
+ </TelaDropdownMenu>
192
+ </div>
193
+ </template>
230
194
  </div>
231
195
  </div>
232
196
 
@@ -239,14 +203,15 @@ const {
239
203
  </span>
240
204
  </div>
241
205
 
242
- <Transition name="group-slide">
243
- <div v-if="groupBucket.open" class="group-slide-panel">
244
- <div class="group-slide__inner">
245
- <div flex="~ col" gap-1px ml-20px mt-1px mb-4px>
206
+ <TelaCollapsible :open="groupBucket.open" @update:open="toggleGroup(groupBucket.group.id)">
207
+ <TelaCollapsibleContent>
208
+ <div flex="~ col" relative>
209
+ <div flex="~ col" gap-1px mt-1px>
246
210
  <ChatConversationItem
247
211
  v-for="conversation in groupBucket.items"
248
212
  :key="conversation.id"
249
213
  v-bind="getConversationItemProps(conversation)"
214
+ item-class="ml-24px"
250
215
  @delete="handleDelete"
251
216
  @rename="handleRename"
252
217
  @duplicate="handleDuplicate"
@@ -257,50 +222,48 @@ const {
257
222
  <button
258
223
  v-if="groupBucket.showNewConversationAction"
259
224
  type="button"
260
- h-32px px-8px
261
- flex items-center gap-8px
262
- rounded-8px
225
+ h-32px px-12px
226
+ flex items-center gap-9px
227
+ rounded-10px
263
228
  text-left
264
- hover:bg-neutral-100
265
- transition-colors
229
+ hover:bg-subtle
266
230
  cursor-pointer
267
231
  @click="startConversationInGroup(groupBucket.group.id)"
268
232
  >
269
- <span i-ph-plus text-14px text-neutral-500 shrink-0 />
270
- <span text-14px font-medium text-neutral-500 leading-18px>
233
+ <span body-14-medium text-secondary leading-18px ml-24px>
271
234
  Nova conversa
272
235
  </span>
236
+ <TelaIcon name="i-ph-plus" size="14px" color="icon-secondary" shrink-0 />
273
237
  </button>
274
238
  <div
275
239
  v-else-if="groupBucket.showSearchEmpty"
276
- h-32px px-8px flex items-center
240
+ h-32px flex items-center ml-36px
277
241
  >
278
- <span text-13px text-neutral-400 leading-17px>
242
+ <span body-14-medium text-tertiary>
279
243
  Sem resultados
280
244
  </span>
281
245
  </div>
282
246
  </div>
247
+
248
+ <div aria-hidden="true" absolute left-17px h-full w-0.5px bg-border pointer-events-none />
283
249
  </div>
284
- </div>
285
- </Transition>
250
+ </TelaCollapsibleContent>
251
+ </TelaCollapsible>
286
252
  </div>
287
253
  </div>
288
254
 
289
255
  <div
290
256
  flex="~ col" gap-4px
291
- rounded-8px
292
- transition-colors
293
- :class="ungroupedDropTarget ? 'bg-neutral-100' : ''"
257
+ rounded-10px
258
+ :class="ungroupedDropTarget ? 'bg-lowered' : ''"
294
259
  @dragenter.prevent="handleDragEnter(null)"
295
260
  @dragover.prevent="handleDragOver($event, null)"
296
261
  @dragleave="handleDragLeave($event, null)"
297
262
  @drop.prevent="handleConversationDrop($event, null)"
298
263
  >
299
- <div v-if="shouldShowUngroupedHeader" h-20px flex items-center pl-12px pr-4px mb-4px>
300
- <span text-12px font-semibold text-neutral-400 uppercase style="letter-spacing: 0">
301
- {{ ungroupedConversationLabel }}
302
- </span>
303
- </div>
264
+ <span body-12-medium text-secondary pl-10px pt-4px>
265
+ {{ ungroupedConversationLabel }}
266
+ </span>
304
267
 
305
268
  <div v-if="ungroupedConversations.length > 0" flex="~ col" gap-1px>
306
269
  <ChatConversationItem
@@ -316,7 +279,7 @@ const {
316
279
  />
317
280
  </div>
318
281
  </div>
319
- </template>
282
+ </div>
320
283
  </div>
321
284
 
322
285
  <TelaConfirmationModal
@@ -347,7 +310,3 @@ const {
347
310
  {{ deleteGroupConversationsConfirmationMessage }}
348
311
  </TelaConfirmationModal>
349
312
  </template>
350
-
351
- <style scoped>
352
- .group-slide-panel{display:grid;grid-template-rows:1fr}.group-slide-enter-active,.group-slide-leave-active{overflow:hidden;transition:grid-template-rows .18s cubic-bezier(.2,.8,.2,1),opacity .14s ease,transform .18s cubic-bezier(.2,.8,.2,1)}.group-slide-enter-from,.group-slide-leave-to{grid-template-rows:0fr;opacity:0;transform:translateY(-4px)}.group-slide-enter-to,.group-slide-leave-from{grid-template-rows:1fr;opacity:1;transform:translateY(0)}.group-slide__inner{min-height:0;overflow:hidden}
353
- </style>
@@ -8,7 +8,6 @@ type __VLS_Props = {
8
8
  resetConversation?: () => void | Promise<void>;
9
9
  startConversation?: (groupId?: string | null) => void | Promise<void>;
10
10
  loading?: boolean;
11
- hideFolderHint?: boolean;
12
11
  };
13
12
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
13
  declare const _default: typeof __VLS_export;
@@ -1,91 +1,52 @@
1
1
  <script setup>
2
2
  import { useConversationGroups } from "../composables/conversation-groups";
3
- import ChatConversationNewGroupPopoverContent from "./chat-conversation-new-group-popover-content.vue";
4
3
  const props = defineProps({
5
4
  label: { type: String, required: false },
6
5
  variant: { type: String, required: false }
7
6
  });
8
- const { createGroup, error: groupCreationError } = useConversationGroups();
9
- const isOpen = ref(false);
10
- const groupName = ref("");
11
- const isSaving = ref(false);
12
- const creationErrorMessage = ref(null);
13
- const popoverContentRef = ref(null);
7
+ const DEFAULT_GROUP_NAME = "Nova pasta";
8
+ const { groups, createGroup, pendingRenameGroupId } = useConversationGroups();
9
+ const isCreating = ref(false);
14
10
  const hasLabel = computed(() => Boolean(props.label?.trim()));
15
11
  const isEmptyState = computed(() => props.variant === "empty-state");
16
12
  const buttonClasses = computed(() => {
17
13
  if (isEmptyState.value)
18
- return "h-32px w-full gap-6px px-12px border-neutral-300 hover:bg-neutral-50";
14
+ return "h-32px w-full gap-6px px-12px";
19
15
  if (hasLabel.value)
20
- return "h-28px px-10px gap-6px self-start border-neutral-300 hover:bg-neutral-50";
21
- return "h-32px w-40px border-neutral-300 hover:bg-neutral-50";
16
+ return "h-28px px-10px gap-6px self-start";
17
+ return "h-32px! w-40px! p-0!";
22
18
  });
23
- const iconClasses = computed(() => isEmptyState.value ? "text-neutral-900" : "text-neutral-700");
24
- const labelClasses = computed(
25
- () => isEmptyState.value ? "text-14px font-semibold text-neutral-900 leading-18px" : "text-13px font-medium text-neutral-700 leading-17px"
26
- );
27
- watch(isOpen, async (open) => {
28
- if (!open) {
29
- creationErrorMessage.value = null;
30
- return;
31
- }
32
- await nextTick();
33
- popoverContentRef.value?.focusInput?.();
34
- });
35
- watch(groupName, () => {
36
- creationErrorMessage.value = null;
37
- });
38
- async function submitGroup() {
39
- const name = groupName.value.trim();
40
- if (!name || isSaving.value)
41
- return;
42
- creationErrorMessage.value = null;
43
- isSaving.value = true;
44
- const group = await createGroup(name);
45
- isSaving.value = false;
46
- if (!group) {
47
- creationErrorMessage.value = groupCreationError.value || "Erro ao criar pasta";
48
- return;
49
- }
50
- groupName.value = "";
51
- creationErrorMessage.value = null;
52
- isOpen.value = false;
19
+ function nextGroupName() {
20
+ const names = new Set(groups.value.map((group) => group.name));
21
+ if (!names.has(DEFAULT_GROUP_NAME))
22
+ return DEFAULT_GROUP_NAME;
23
+ let index = 2;
24
+ while (names.has(`${DEFAULT_GROUP_NAME} ${index}`))
25
+ index += 1;
26
+ return `${DEFAULT_GROUP_NAME} ${index}`;
53
27
  }
54
- function cancelGroup() {
55
- groupName.value = "";
56
- creationErrorMessage.value = null;
57
- isOpen.value = false;
28
+ async function handleCreateGroup() {
29
+ if (isCreating.value)
30
+ return;
31
+ isCreating.value = true;
32
+ const group = await createGroup(nextGroupName());
33
+ isCreating.value = false;
34
+ if (group)
35
+ pendingRenameGroupId.value = group.id;
58
36
  }
59
37
  </script>
60
38
 
61
39
  <template>
62
- <TelaPopover v-model:open="isOpen">
63
- <TelaPopoverTrigger as-child>
64
- <button
65
- type="button"
66
- flex items-center justify-center
67
- bg-white b=".5px solid"
68
- rounded-10px
69
- transition-colors
70
- cursor-pointer
71
- :class="buttonClasses"
72
- :aria-label="label || 'Nova pasta'"
73
- :title="label || 'Nova pasta'"
74
- >
75
- <span i-ph-folder-plus text-16px :class="iconClasses" />
76
- <span v-if="hasLabel" :class="labelClasses">
77
- {{ label }}
78
- </span>
79
- </button>
80
- </TelaPopoverTrigger>
81
-
82
- <ChatConversationNewGroupPopoverContent
83
- ref="popoverContentRef"
84
- v-model="groupName"
85
- :error-message="creationErrorMessage"
86
- :saving="isSaving"
87
- @submit="submitGroup"
88
- @cancel="cancelGroup"
89
- />
90
- </TelaPopover>
40
+ <TelaButton
41
+ type="button"
42
+ variant="secondary"
43
+ :class="buttonClasses"
44
+ :aria-label="label || 'Nova pasta'"
45
+ @click="handleCreateGroup"
46
+ >
47
+ <TelaIcon name="i-ph-folder-plus" size="16px" color="icon-secondary" ml-0.5px />
48
+ <span v-if="hasLabel">
49
+ {{ label }}
50
+ </span>
51
+ </TelaButton>
91
52
  </template>
@@ -3,9 +3,6 @@ defineProps({
3
3
  placeholder: { type: String, required: false, default: "Buscar conversas" }
4
4
  });
5
5
  const searchQuery = defineModel({ type: String, ...{ required: true } });
6
- function clearSearch() {
7
- searchQuery.value = "";
8
- }
9
6
  </script>
10
7
 
11
8
  <template>
@@ -14,22 +11,5 @@ function clearSearch() {
14
11
  icon="i-ph-magnifying-glass-bold"
15
12
  :placeholder="placeholder"
16
13
  autocomplete="off"
17
- >
18
- <template v-if="searchQuery" #trailing>
19
- <TelaTooltip content="Limpar busca">
20
- <button
21
- type="button"
22
- aria-label="Limpar busca"
23
- hover:bg="#EBEFF199"
24
- transition-colors
25
- p-4px rounded-full
26
- class="group"
27
- tabindex="-1"
28
- @click.stop="clearSearch"
29
- >
30
- <TelaIcon name="i-ph-x-circle-light" text="#031E22" op-40 group-hover:op-100 transition-opacity />
31
- </button>
32
- </TelaTooltip>
33
- </template>
34
- </TelaInput>
14
+ />
35
15
  </template>
@@ -0,0 +1,12 @@
1
+ type __VLS_Props = {
2
+ searchPlaceholder?: string;
3
+ emptyMessage?: string;
4
+ emptySearchMessage?: string;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ searchPlaceholder: string;
8
+ emptyMessage: string;
9
+ emptySearchMessage: string;
10
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const _default: typeof __VLS_export;
12
+ export default _default;
@@ -0,0 +1,27 @@
1
+ <script setup>
2
+ import { useConversations } from "../composables/conversations";
3
+ import { capitalizeFirst } from "../../shared/string";
4
+ defineProps({
5
+ searchPlaceholder: { type: String, required: false, default: "Buscar conversas" },
6
+ emptyMessage: { type: String, required: false, default: "Nenhuma conversa ainda" },
7
+ emptySearchMessage: { type: String, required: false, default: "Nenhuma conversa encontrada" }
8
+ });
9
+ const { conversations, loading, fetchConversations } = useConversations();
10
+ onMounted(() => {
11
+ fetchConversations();
12
+ });
13
+ const items = computed(() => conversations.value.map((conversation) => ({
14
+ id: conversation.id,
15
+ title: capitalizeFirst(conversation.title || "Nova conversa")
16
+ })));
17
+ </script>
18
+
19
+ <template>
20
+ <TelaChatWidgetHistoryList
21
+ :items="items"
22
+ :loading="loading"
23
+ :search-placeholder="searchPlaceholder"
24
+ :empty-message="emptyMessage"
25
+ :empty-search-message="emptySearchMessage"
26
+ />
27
+ </template>
@@ -0,0 +1,12 @@
1
+ type __VLS_Props = {
2
+ searchPlaceholder?: string;
3
+ emptyMessage?: string;
4
+ emptySearchMessage?: string;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ searchPlaceholder: string;
8
+ emptyMessage: string;
9
+ emptySearchMessage: string;
10
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const _default: typeof __VLS_export;
12
+ export default _default;
@@ -3,6 +3,7 @@ export declare function useConversationGroups(): {
3
3
  groups: any;
4
4
  loading: any;
5
5
  error: any;
6
+ pendingRenameGroupId: any;
6
7
  fetchGroups: (options?: {
7
8
  force?: boolean;
8
9
  }) => Promise<void>;
@@ -20,6 +20,7 @@ export function useConversationGroups() {
20
20
  const loadingBuckets = useState("conversation-groups-loading", () => ({}));
21
21
  const fetchedBuckets = useState("conversation-groups-fetched", () => ({}));
22
22
  const errorBuckets = useState("conversation-groups-error", () => ({}));
23
+ const pendingRenameGroupId = useState("conversation-groups-pending-rename", () => null);
23
24
  const runtimeScope = computed(() => resolveChatStateScope(
24
25
  embedConfig?.workspaceId.value || activeOrganization.value?.id,
25
26
  embedConfig?.telaAgentId.value,
@@ -155,6 +156,7 @@ export function useConversationGroups() {
155
156
  groups: readonly(groups),
156
157
  loading: readonly(loading),
157
158
  error: readonly(error),
159
+ pendingRenameGroupId,
158
160
  fetchGroups,
159
161
  createGroup,
160
162
  renameGroup,
@@ -128,22 +128,22 @@ export function useConversationItem(options, emit) {
128
128
  const menuItems = [
129
129
  {
130
130
  label: "Renomear",
131
- icon: "i-ph-pencil-simple",
131
+ icon: "i-ph-pencil-simple-bold",
132
132
  click: () => startRename()
133
133
  },
134
134
  {
135
135
  label: "Duplicar",
136
- icon: "i-ph-copy",
136
+ icon: "i-ph-copy-bold",
137
137
  click: () => emit("duplicate", options.conversation.id)
138
138
  },
139
139
  {
140
140
  label: "Exportar",
141
- icon: "i-ph-download-simple",
141
+ icon: "i-ph-download-simple-bold",
142
142
  click: () => emit("export", options.conversation.id)
143
143
  },
144
144
  {
145
145
  label: "Excluir",
146
- icon: "i-ph-trash",
146
+ icon: "i-ph-trash-bold",
147
147
  color: "negative",
148
148
  click: () => showDeleteModal.value = true
149
149
  }