@meistrari/chat-nuxt 1.7.0 → 1.8.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 (90) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +2 -0
  3. package/dist/runtime/components/MeistrariChatEmbed.vue +5 -1
  4. package/dist/runtime/components/chat/bash-widget.vue +3 -3
  5. package/dist/runtime/components/chat/doc-sdk-widget.vue +3 -3
  6. package/dist/runtime/components/chat/files-view.vue +3 -64
  7. package/dist/runtime/components/chat/generic-tool-widget.vue +3 -3
  8. package/dist/runtime/components/chat/grep-widget.vue +3 -3
  9. package/dist/runtime/components/chat/message-bubble.vue +1 -1
  10. package/dist/runtime/components/chat/message-input.d.vue.ts +2 -0
  11. package/dist/runtime/components/chat/message-input.vue +21 -5
  12. package/dist/runtime/components/chat/message-input.vue.d.ts +2 -0
  13. package/dist/runtime/components/chat/message-list.vue +1 -1
  14. package/dist/runtime/components/chat/mobile/files/file-preview.d.vue.ts +11 -0
  15. package/dist/runtime/components/chat/mobile/files/file-preview.vue +112 -0
  16. package/dist/runtime/components/chat/mobile/files/file-preview.vue.d.ts +11 -0
  17. package/dist/runtime/components/chat/mobile/files/files-view.d.vue.ts +10 -0
  18. package/dist/runtime/components/chat/mobile/files/files-view.vue +384 -0
  19. package/dist/runtime/components/chat/mobile/files/files-view.vue.d.ts +10 -0
  20. package/dist/runtime/components/chat/mobile/home/header.d.vue.ts +19 -0
  21. package/dist/runtime/components/chat/mobile/home/header.vue +55 -0
  22. package/dist/runtime/components/chat/mobile/home/header.vue.d.ts +19 -0
  23. package/dist/runtime/components/chat/mobile/home/recents.d.vue.ts +14 -0
  24. package/dist/runtime/components/chat/mobile/home/recents.vue +48 -0
  25. package/dist/runtime/components/chat/mobile/home/recents.vue.d.ts +14 -0
  26. package/dist/runtime/components/chat/mobile/home/suggestions.d.vue.ts +7 -0
  27. package/dist/runtime/components/chat/mobile/home/suggestions.vue +31 -0
  28. package/dist/runtime/components/chat/mobile/home/suggestions.vue.d.ts +7 -0
  29. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.d.vue.ts +21 -0
  30. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.vue +48 -0
  31. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.vue.d.ts +21 -0
  32. package/dist/runtime/components/chat/mobile/primitives/info-bubble.d.vue.ts +6 -0
  33. package/dist/runtime/components/chat/mobile/primitives/info-bubble.vue +50 -0
  34. package/dist/runtime/components/chat/mobile/primitives/info-bubble.vue.d.ts +6 -0
  35. package/dist/runtime/components/chat/mobile/shell/drawer.d.vue.ts +22 -0
  36. package/dist/runtime/components/chat/mobile/shell/drawer.vue +143 -0
  37. package/dist/runtime/components/chat/mobile/shell/drawer.vue.d.ts +22 -0
  38. package/dist/runtime/components/chat/mobile/shell/header.d.vue.ts +40 -0
  39. package/dist/runtime/components/chat/mobile/shell/header.vue +139 -0
  40. package/dist/runtime/components/chat/mobile/shell/header.vue.d.ts +40 -0
  41. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.d.vue.ts +14 -0
  42. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.vue +47 -0
  43. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.vue.d.ts +14 -0
  44. package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +122 -0
  45. package/dist/runtime/components/chat/mobile/shell/shell.vue +283 -0
  46. package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +122 -0
  47. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.d.vue.ts +19 -0
  48. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.vue +51 -0
  49. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.vue.d.ts +19 -0
  50. package/dist/runtime/components/chat/mobile/usage/usage-view.d.vue.ts +8 -0
  51. package/dist/runtime/components/chat/mobile/usage/usage-view.vue +243 -0
  52. package/dist/runtime/components/chat/mobile/usage/usage-view.vue.d.ts +8 -0
  53. package/dist/runtime/components/chat/model-selector.vue +6 -0
  54. package/dist/runtime/components/chat/read-widget.vue +3 -3
  55. package/dist/runtime/components/chat/reasoning-step-item.vue +1 -1
  56. package/dist/runtime/components/chat/reasoning-steps.vue +1 -1
  57. package/dist/runtime/components/chat/reasoning-thought.vue +2 -3
  58. package/dist/runtime/components/chat/tela-skill-widget.vue +3 -3
  59. package/dist/runtime/components/chat/thinking-widget.vue +3 -3
  60. package/dist/runtime/components/chat/usage-view.vue +20 -101
  61. package/dist/runtime/components/chat/web-search-widget.vue +3 -3
  62. package/dist/runtime/components/chat/workstation-query-widget.vue +6 -6
  63. package/dist/runtime/components/chat/write-widget.vue +3 -3
  64. package/dist/runtime/composables/useConversationFileDownloads.d.ts +6 -0
  65. package/dist/runtime/composables/useConversationFileDownloads.js +50 -0
  66. package/dist/runtime/composables/useConversationUsage.d.ts +13 -0
  67. package/dist/runtime/composables/useConversationUsage.js +121 -0
  68. package/dist/runtime/composables/useEmbedConfig.d.ts +2 -0
  69. package/dist/runtime/composables/useEmbedConfig.js +4 -0
  70. package/dist/runtime/composables/useMentionAutocomplete.d.ts +6 -0
  71. package/dist/runtime/composables/useMentionAutocomplete.js +71 -23
  72. package/dist/runtime/composables/useWorkspaceSwitchModal.d.ts +5 -0
  73. package/dist/runtime/composables/useWorkspaceSwitchModal.js +14 -0
  74. package/dist/runtime/embed/components/ChatConfigurationModal.vue +119 -13
  75. package/dist/runtime/embed/components/ChatEmbed.vue +4 -0
  76. package/dist/runtime/embed/components/ChatEmbedInner.d.vue.ts +2 -0
  77. package/dist/runtime/embed/components/ChatEmbedInner.vue +201 -11
  78. package/dist/runtime/embed/components/ChatEmbedInner.vue.d.ts +2 -0
  79. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.d.vue.ts +34 -0
  80. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue +95 -0
  81. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue.d.ts +34 -0
  82. package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +3 -1
  83. package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +29 -5
  84. package/dist/runtime/server/utils/conversation-message-sync.d.ts +8 -2
  85. package/dist/runtime/server/utils/conversation-message-sync.js +52 -6
  86. package/dist/runtime/types/chat-auth.d.ts +1 -0
  87. package/dist/runtime/types/embed.d.ts +2 -0
  88. package/dist/runtime/utils/breakpoints.d.ts +1 -0
  89. package/dist/runtime/utils/breakpoints.js +1 -0
  90. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ <script setup>
2
+ import { onKeyStroke } from "@vueuse/core";
3
+ const props = defineProps({
4
+ open: { type: Boolean, required: true },
5
+ title: { type: String, required: false }
6
+ });
7
+ const emit = defineEmits(["close"]);
8
+ onKeyStroke("Escape", () => {
9
+ if (props.open) {
10
+ emit("close");
11
+ }
12
+ });
13
+ </script>
14
+
15
+ <template>
16
+ <Transition name="sheet-scrim">
17
+ <div
18
+ v-if="open"
19
+ class="sheet-scrim"
20
+ @click="emit('close')"
21
+ />
22
+ </Transition>
23
+
24
+ <Transition name="sheet">
25
+ <div
26
+ v-if="open"
27
+ class="sheet"
28
+ role="dialog"
29
+ aria-modal="true"
30
+ >
31
+ <div class="sheet__grabber-area">
32
+ <div class="sheet__grabber" />
33
+ </div>
34
+
35
+ <div v-if="title" class="sheet__title-row">
36
+ <span class="sheet__title">{{ title }}</span>
37
+ </div>
38
+
39
+ <div class="sheet__body">
40
+ <slot />
41
+ </div>
42
+ </div>
43
+ </Transition>
44
+ </template>
45
+
46
+ <style scoped>
47
+ .sheet-scrim{background:rgba(0,0,0,.32);inset:0;position:absolute;z-index:40}.sheet-scrim-enter-active,.sheet-scrim-leave-active{transition:opacity .2s linear}.sheet-scrim-enter-from,.sheet-scrim-leave-to{opacity:0}.sheet{background:#fff;border-radius:18px 18px 0 0;bottom:0;box-shadow:0 3px 12px rgba(103,127,148,.08),0 12px 52px rgba(103,127,148,.16);display:flex;flex-direction:column;left:0;max-height:70%;position:absolute;right:0;z-index:41}.sheet-enter-active,.sheet-leave-active{transition:transform .26s cubic-bezier(.2,.8,.2,1)}.sheet-enter-from,.sheet-leave-to{transform:translateY(100%)}.sheet__grabber-area{display:flex;justify-content:center;padding:8px 0 4px}.sheet__grabber{background:#e8e8e8;border-radius:999px;height:4px;width:36px}.sheet__title-row{border-bottom:.5px solid #f5f5f5;padding:4px 16px 10px}.sheet__title{color:#171717;font-size:16px;font-weight:500;letter-spacing:-.2px;line-height:20px}.sheet__body{flex:1;overflow-y:auto;padding:4px 0 8px}
48
+ </style>
@@ -0,0 +1,21 @@
1
+ type __VLS_Props = {
2
+ open: boolean;
3
+ title?: string;
4
+ };
5
+ declare var __VLS_13: {};
6
+ type __VLS_Slots = {} & {
7
+ default?: (props: typeof __VLS_13) => any;
8
+ };
9
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
10
+ close: () => any;
11
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
12
+ onClose?: (() => any) | undefined;
13
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_WithSlots<T, S> = T & {
18
+ new (): {
19
+ $slots: S;
20
+ };
21
+ };
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ text: string;
3
+ };
4
+ 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>;
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
@@ -0,0 +1,50 @@
1
+ <script setup>
2
+ import { onClickOutside, onKeyStroke } from "@vueuse/core";
3
+ defineProps({
4
+ text: { type: String, required: true }
5
+ });
6
+ const open = ref(false);
7
+ const wrapper = ref(null);
8
+ onClickOutside(wrapper, () => {
9
+ if (open.value) {
10
+ open.value = false;
11
+ }
12
+ });
13
+ onKeyStroke("Escape", () => {
14
+ if (open.value) {
15
+ open.value = false;
16
+ }
17
+ });
18
+ function toggle() {
19
+ open.value = !open.value;
20
+ }
21
+ </script>
22
+
23
+ <template>
24
+ <span ref="wrapper" class="info-wrapper">
25
+ <button
26
+ type="button"
27
+ class="info-trigger"
28
+ aria-label="Mais informações"
29
+ :aria-expanded="open"
30
+ @click.stop="toggle"
31
+ >
32
+ i
33
+ </button>
34
+
35
+ <Transition name="info">
36
+ <div
37
+ v-if="open"
38
+ role="tooltip"
39
+ class="info-tooltip"
40
+ @click.stop
41
+ >
42
+ {{ text }}
43
+ </div>
44
+ </Transition>
45
+ </span>
46
+ </template>
47
+
48
+ <style scoped>
49
+ .info-wrapper{margin-left:4px;position:relative}.info-trigger,.info-wrapper{align-items:center;display:inline-flex}.info-trigger{background:transparent;border:1px solid #a3a3a3;border-radius:14px;color:#a3a3a3;cursor:pointer;font-family:inherit;font-size:9px;font-style:normal;font-weight:600;height:14px;justify-content:center;line-height:1;width:14px}.info-trigger[aria-expanded=true]{border-color:#171717;color:#171717}.info-tooltip{background:#171717;border-radius:8px;box-shadow:0 3px 12px rgba(103,127,148,.08);color:#fff;font-size:12px;font-weight:400;left:50%;line-height:1.4;padding:8px 10px;position:absolute;text-align:left;top:20px;transform:translateX(-50%);width:200px;z-index:5}.info-enter-active,.info-leave-active{transition:opacity .12s,transform .12s}.info-enter-from,.info-leave-to{opacity:0;transform:translateX(-50%) translateY(-2px)}
50
+ </style>
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ text: string;
3
+ };
4
+ 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>;
5
+ declare const _default: typeof __VLS_export;
6
+ export default _default;
@@ -0,0 +1,22 @@
1
+ import type { DeepReadonly } from 'vue';
2
+ import type { Conversation } from '../../../../types/chat.js';
3
+ type __VLS_Props = {
4
+ open: boolean;
5
+ conversations: DeepReadonly<Conversation[]>;
6
+ activeId: string | null;
7
+ loading?: boolean;
8
+ userName?: string;
9
+ userEmail?: string;
10
+ userImage?: string;
11
+ };
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
13
+ select: (id: string) => any;
14
+ close: () => any;
15
+ newConvo: () => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
+ onSelect?: ((id: string) => any) | undefined;
18
+ onClose?: (() => any) | undefined;
19
+ onNewConvo?: (() => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -0,0 +1,143 @@
1
+ <script setup>
2
+ import { formatRelativeTime } from "../../../../utils/format-time";
3
+ import { conversationListSkeletonRows } from "../../../../utils/conversation-list-skeleton";
4
+ const props = defineProps({
5
+ open: { type: Boolean, required: true },
6
+ conversations: { type: null, required: true },
7
+ activeId: { type: [String, null], required: true },
8
+ loading: { type: Boolean, required: false },
9
+ userName: { type: String, required: false },
10
+ userEmail: { type: String, required: false },
11
+ userImage: { type: String, required: false }
12
+ });
13
+ const emit = defineEmits(["close", "select", "newConvo"]);
14
+ const initial = computed(() => {
15
+ const source = props.userName ?? props.userEmail ?? "U";
16
+ return source.charAt(0).toUpperCase();
17
+ });
18
+ function handleSelect(id) {
19
+ emit("select", id);
20
+ emit("close");
21
+ }
22
+ function handleNew() {
23
+ emit("newConvo");
24
+ emit("close");
25
+ }
26
+ </script>
27
+
28
+ <template>
29
+ <Transition name="scrim">
30
+ <div
31
+ v-if="open"
32
+ absolute inset-0 z-30
33
+ bg="black/32"
34
+ @click="emit('close')"
35
+ />
36
+ </Transition>
37
+
38
+ <div
39
+ absolute top-0 bottom-0 left-0 z-31
40
+ flex="~ col"
41
+ bg-white
42
+ class="mobile-drawer"
43
+ :class="open ? 'mobile-drawer--open' : ''"
44
+ >
45
+ <div
46
+ flex items-center gap-8px
47
+ pt-14px pr-14px pb-14px pl-14px
48
+ b-b=".5px solid"
49
+ style="border-bottom-color: #F5F5F5"
50
+ >
51
+ <div w-28px h-28px rounded-full overflow-hidden flex-shrink-0>
52
+ <img
53
+ v-if="userImage"
54
+ :src="userImage"
55
+ :alt="userName ?? 'Usu\xE1rio'"
56
+ w-full h-full object-cover
57
+ >
58
+ <div v-else w-full h-full bg-purple-500 flex items-center justify-center>
59
+ <span text-12px text-white font-semibold>{{ initial }}</span>
60
+ </div>
61
+ </div>
62
+ <span flex-1 text-14px font-580 text-neutral-900 truncate tracking="-.15px">
63
+ {{ userName ?? userEmail ?? "Usu\xE1rio" }}
64
+ </span>
65
+ <button
66
+ flex items-center justify-center
67
+ w-32px h-32px rounded-8px
68
+ class="hover:bg-neutral-100 active:scale-94"
69
+ transition-all
70
+ aria-label="Fechar menu"
71
+ @click="emit('close')"
72
+ >
73
+ <span i-ph-x text-18px text-neutral-700 />
74
+ </button>
75
+ </div>
76
+
77
+ <div p-12px>
78
+ <button
79
+ flex items-center justify-center gap-6px
80
+ w-full px-12px py-10px rounded-10px
81
+ bg-white b=".5px neutral-300" shadow-sm
82
+ class="hover:bg-neutral-50"
83
+ transition-colors cursor-pointer
84
+ @click="handleNew"
85
+ >
86
+ <span i-ph-chat-circle text-16px text-neutral-900 />
87
+ <span text-14px font-580 text-neutral-900 leading-18px tracking="-.15px">
88
+ Nova conversa
89
+ </span>
90
+ </button>
91
+ </div>
92
+
93
+ <div px-14px pt-4px pb-4px>
94
+ <span
95
+ text-12px font-medium uppercase text-neutral-400
96
+ style="letter-spacing: 0.5px"
97
+ >
98
+ Recentes
99
+ </span>
100
+ </div>
101
+
102
+ <div flex-1 overflow-y-auto px-8px pb-8px>
103
+ <div v-if="loading && conversations.length === 0" flex="~ col" gap-1px py-4px>
104
+ <div
105
+ v-for="row in conversationListSkeletonRows"
106
+ :key="row.id"
107
+ flex items-center h-44px px-12px rounded-10px
108
+ >
109
+ <TelaSkeleton rounded-6px bg-neutral-200 :style="{ width: row.width, height: '13px' }" />
110
+ </div>
111
+ </div>
112
+ <div v-else-if="conversations.length === 0" p-16px text-center>
113
+ <p text-14px text-neutral-400>
114
+ Nenhuma conversa ainda
115
+ </p>
116
+ </div>
117
+ <div v-else flex="~ col" gap-1px>
118
+ <button
119
+ v-for="conv in conversations"
120
+ :key="conv.id"
121
+ flex="~ col" gap-2px
122
+ w-full px-12px py-10px rounded-10px text-left
123
+ transition-colors cursor-pointer
124
+ :class="conv.id === activeId ? 'bg-neutral-100' : 'hover:bg-neutral-50'"
125
+ @click="handleSelect(conv.id)"
126
+ >
127
+ <div flex items-center gap-8px w-full>
128
+ <span flex-1 text-14px font-medium text-neutral-900 leading-18px truncate>
129
+ {{ conv.title || "Nova conversa" }}
130
+ </span>
131
+ <span text-12px text-neutral-400 leading-16px shrink-0>
132
+ {{ formatRelativeTime(conv.updatedAt) }}
133
+ </span>
134
+ </div>
135
+ </button>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </template>
140
+
141
+ <style scoped>
142
+ .mobile-drawer{box-shadow:0 3px 12px rgba(103,127,148,.08),0 12px 52px rgba(103,127,148,.16);transform:translateX(-100%);transition:transform .26s cubic-bezier(.2,.8,.2,1);width:82%}.mobile-drawer--open{transform:translateX(0)}.scrim-enter-active,.scrim-leave-active{transition:opacity .2s linear}.scrim-enter-from,.scrim-leave-to{opacity:0}
143
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { DeepReadonly } from 'vue';
2
+ import type { Conversation } from '../../../../types/chat.js';
3
+ type __VLS_Props = {
4
+ open: boolean;
5
+ conversations: DeepReadonly<Conversation[]>;
6
+ activeId: string | null;
7
+ loading?: boolean;
8
+ userName?: string;
9
+ userEmail?: string;
10
+ userImage?: string;
11
+ };
12
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
13
+ select: (id: string) => any;
14
+ close: () => any;
15
+ newConvo: () => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
+ onSelect?: ((id: string) => any) | undefined;
18
+ onClose?: (() => any) | undefined;
19
+ onNewConvo?: (() => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -0,0 +1,40 @@
1
+ import type { TopbarTab } from '../../../../types/chat.js';
2
+ type __VLS_Props = {
3
+ title: string;
4
+ creatorName?: string;
5
+ creatorEmail?: string;
6
+ creatorImage?: string;
7
+ updatedAt: string | Date;
8
+ generatingTitle?: boolean;
9
+ filesCount?: number;
10
+ activeTab?: TopbarTab;
11
+ showOutdatedBadge?: boolean;
12
+ showUsageTab?: boolean;
13
+ showDebugOption?: boolean;
14
+ showDrawerButton?: boolean;
15
+ };
16
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
+ delete: () => any;
18
+ rename: () => any;
19
+ duplicate: () => any;
20
+ export: () => any;
21
+ copyLink: () => any;
22
+ debug: () => any;
23
+ tabChange: (tab: TopbarTab) => any;
24
+ openDrawer: () => any;
25
+ openOutdatedSettings: () => any;
26
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
+ onDelete?: (() => any) | undefined;
28
+ onRename?: (() => any) | undefined;
29
+ onDuplicate?: (() => any) | undefined;
30
+ onExport?: (() => any) | undefined;
31
+ onCopyLink?: (() => any) | undefined;
32
+ onDebug?: (() => any) | undefined;
33
+ onTabChange?: ((tab: TopbarTab) => any) | undefined;
34
+ onOpenDrawer?: (() => any) | undefined;
35
+ onOpenOutdatedSettings?: (() => any) | undefined;
36
+ }>, {
37
+ showDrawerButton: boolean;
38
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
@@ -0,0 +1,139 @@
1
+ <script setup>
2
+ import { formatRelativeTime } from "../../../../utils/format-time";
3
+ import { capitalizeFirst } from "../../../../utils/string";
4
+ const props = defineProps({
5
+ title: { type: String, required: true },
6
+ creatorName: { type: String, required: false },
7
+ creatorEmail: { type: String, required: false },
8
+ creatorImage: { type: String, required: false },
9
+ updatedAt: { type: [String, Date], required: true },
10
+ generatingTitle: { type: Boolean, required: false },
11
+ filesCount: { type: Number, required: false },
12
+ activeTab: { type: String, required: false },
13
+ showOutdatedBadge: { type: Boolean, required: false },
14
+ showUsageTab: { type: Boolean, required: false },
15
+ showDebugOption: { type: Boolean, required: false },
16
+ showDrawerButton: { type: Boolean, required: false, default: true }
17
+ });
18
+ const emit = defineEmits(["openDrawer", "openOutdatedSettings", "rename", "duplicate", "export", "copyLink", "debug", "delete", "tabChange"]);
19
+ const currentTab = computed(() => props.activeTab ?? "chat");
20
+ const tabItems = computed(() => {
21
+ const items = [
22
+ { id: "chat", icon: "i-ph-chat-circle", label: "Chat" },
23
+ { id: "files", icon: "i-ph-folder", label: "Arquivos" }
24
+ ];
25
+ if (props.showUsageTab) {
26
+ items.push({ id: "usage", icon: "i-ph-chart-bar", label: "Uso" });
27
+ }
28
+ return items;
29
+ });
30
+ const headerMenuItems = computed(() => {
31
+ const items = [
32
+ { label: "Renomear", icon: "i-ph-pencil-simple", click: () => emit("rename") },
33
+ { label: "Duplicar", icon: "i-ph-copy", click: () => emit("duplicate") },
34
+ { label: "Exportar", icon: "i-ph-download-simple", click: () => emit("export") },
35
+ { label: "Copiar link", icon: "i-ph-link", click: () => emit("copyLink") }
36
+ ];
37
+ if (props.showDebugOption) {
38
+ items.push({ label: "Debug", icon: "i-ph-bug", click: () => emit("debug") });
39
+ }
40
+ items.push({ label: "Excluir", icon: "i-ph-trash", color: "negative", click: () => emit("delete") });
41
+ return items;
42
+ });
43
+ </script>
44
+
45
+ <template>
46
+ <div
47
+ flex items-center gap-8px
48
+ px-10px pt-10px pb-8px
49
+ b-b=".5px solid rgba(0,0,0,0.08)"
50
+ bg-white
51
+ absolute top-0 right-0 left-0 z-10
52
+ >
53
+ <button
54
+ v-if="showDrawerButton"
55
+ flex items-center justify-center
56
+ w-32px h-32px rounded-8px
57
+ class="hover:bg-neutral-100 active:scale-94"
58
+ transition-all
59
+ aria-label="Abrir menu"
60
+ @click="emit('openDrawer')"
61
+ >
62
+ <span i-ph-list text-20px text-neutral-700 />
63
+ </button>
64
+
65
+ <div flex="~ col 1" gap-2px min-w-0>
66
+ <p
67
+ text-14px font-580 text-neutral-900 leading-18px tracking="-.15px"
68
+ truncate
69
+ >
70
+ {{ capitalizeFirst(title) }}<span v-if="generatingTitle" class="typing-cursor">|</span>
71
+ </p>
72
+ <div flex items-center gap-4px text-11px text-secondary leading-14px truncate>
73
+ <div w-12px h-12px rounded-full overflow-hidden flex-shrink-0>
74
+ <img
75
+ v-if="creatorImage"
76
+ :src="creatorImage"
77
+ :alt="creatorName ?? 'Usu\xE1rio'"
78
+ w-full h-full object-cover
79
+ >
80
+ <div v-else w-full h-full bg-purple-500 flex items-center justify-center>
81
+ <span text-7px text-white font-semibold>
82
+ {{ (creatorName ?? creatorEmail ?? "U").charAt(0).toUpperCase() }}
83
+ </span>
84
+ </div>
85
+ </div>
86
+ <span truncate>
87
+ {{ creatorName ?? creatorEmail ?? "Usu\xE1rio" }} · {{ formatRelativeTime(updatedAt) }}
88
+ </span>
89
+ </div>
90
+ </div>
91
+
92
+ <div
93
+ inline-flex items-center shrink-0
94
+ p-2px rounded-8px bg-neutral-100
95
+ >
96
+ <button
97
+ v-for="tab in tabItems"
98
+ :key="tab.id"
99
+ class="segmented-tab"
100
+ :class="{ 'segmented-tab--active': currentTab === tab.id }"
101
+ :aria-label="tab.label"
102
+ :title="tab.label"
103
+ @click="emit('tabChange', tab.id)"
104
+ >
105
+ <span :class="tab.icon" />
106
+ </button>
107
+ </div>
108
+
109
+ <button
110
+ v-if="showOutdatedBadge"
111
+ flex items-center justify-center shrink-0
112
+ w-28px h-28px rounded-8px
113
+ bg="#FFF1D8"
114
+ class="hover:bg-[#FFE9BE] active:scale-94"
115
+ transition-transform
116
+ aria-label="Configurações do workspace atualizadas"
117
+ title="Configurações do workspace atualizadas"
118
+ @click="emit('openOutdatedSettings')"
119
+ >
120
+ <span i-ph-warning text-14px text-neutral-800 />
121
+ </button>
122
+
123
+ <TelaDropdownMenu :items="headerMenuItems" align="end">
124
+ <button
125
+ flex items-center justify-center
126
+ w-32px h-32px rounded-8px
127
+ class="hover:bg-neutral-100"
128
+ transition-colors
129
+ aria-label="Mais opções"
130
+ >
131
+ <span i-ph-dots-three text-18px text-neutral-700 />
132
+ </button>
133
+ </TelaDropdownMenu>
134
+ </div>
135
+ </template>
136
+
137
+ <style scoped>
138
+ .segmented-tab{align-items:center;background:transparent;border:.5px solid transparent;border-radius:6px;box-sizing:border-box;color:#a3a3a3;display:inline-flex;font-size:16px;height:24px;justify-content:center;line-height:0;padding:0;transition:background .15s,border-color .15s,box-shadow .15s,color .15s;width:28px}.segmented-tab--active{background:#fff;border-color:rgba(0,0,0,.06);box-shadow:0 1px 2px rgba(64,64,64,.04);color:#171717}.typing-cursor{animation:blink .7s infinite;color:#6b7280;font-weight:400}@keyframes blink{0%,50%{opacity:1}51%,to{opacity:0}}
139
+ </style>
@@ -0,0 +1,40 @@
1
+ import type { TopbarTab } from '../../../../types/chat.js';
2
+ type __VLS_Props = {
3
+ title: string;
4
+ creatorName?: string;
5
+ creatorEmail?: string;
6
+ creatorImage?: string;
7
+ updatedAt: string | Date;
8
+ generatingTitle?: boolean;
9
+ filesCount?: number;
10
+ activeTab?: TopbarTab;
11
+ showOutdatedBadge?: boolean;
12
+ showUsageTab?: boolean;
13
+ showDebugOption?: boolean;
14
+ showDrawerButton?: boolean;
15
+ };
16
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
+ delete: () => any;
18
+ rename: () => any;
19
+ duplicate: () => any;
20
+ export: () => any;
21
+ copyLink: () => any;
22
+ debug: () => any;
23
+ tabChange: (tab: TopbarTab) => any;
24
+ openDrawer: () => any;
25
+ openOutdatedSettings: () => any;
26
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
+ onDelete?: (() => any) | undefined;
28
+ onRename?: (() => any) | undefined;
29
+ onDuplicate?: (() => any) | undefined;
30
+ onExport?: (() => any) | undefined;
31
+ onCopyLink?: (() => any) | undefined;
32
+ onDebug?: (() => any) | undefined;
33
+ onTabChange?: ((tab: TopbarTab) => any) | undefined;
34
+ onOpenDrawer?: (() => any) | undefined;
35
+ onOpenOutdatedSettings?: (() => any) | undefined;
36
+ }>, {
37
+ showDrawerButton: boolean;
38
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
@@ -0,0 +1,14 @@
1
+ type __VLS_Props = {
2
+ open: boolean;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
5
+ close: () => any;
6
+ dismiss: () => any;
7
+ newConversation: () => any;
8
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onClose?: (() => any) | undefined;
10
+ onDismiss?: (() => any) | undefined;
11
+ onNewConversation?: (() => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
@@ -0,0 +1,47 @@
1
+ <script setup>
2
+ import ChatMobileBottomSheet from "../primitives/bottom-sheet.vue";
3
+ defineProps({
4
+ open: { type: Boolean, required: true }
5
+ });
6
+ const emit = defineEmits(["close", "dismiss", "newConversation"]);
7
+ </script>
8
+
9
+ <template>
10
+ <ChatMobileBottomSheet
11
+ :open="open"
12
+ @close="emit('close')"
13
+ >
14
+ <div class="outdated-sheet">
15
+ <div class="outdated-sheet__icon">
16
+ <span i-ph-warning text-20px />
17
+ </div>
18
+
19
+ <div class="outdated-sheet__copy">
20
+ <h2>Configurações do workspace mudaram</h2>
21
+ <p>Esta conversa usa configurações antigas. Inicie uma nova conversa para aplicar as atualizações.</p>
22
+ </div>
23
+
24
+ <div class="outdated-sheet__actions">
25
+ <button
26
+ type="button"
27
+ class="outdated-sheet__button outdated-sheet__button--primary"
28
+ @click="emit('newConversation')"
29
+ >
30
+ <span i-ph-plus text-16px />
31
+ <span>Iniciar nova conversa</span>
32
+ </button>
33
+ <button
34
+ type="button"
35
+ class="outdated-sheet__button outdated-sheet__button--ghost"
36
+ @click="emit('dismiss')"
37
+ >
38
+ Agora não
39
+ </button>
40
+ </div>
41
+ </div>
42
+ </ChatMobileBottomSheet>
43
+ </template>
44
+
45
+ <style scoped>
46
+ .outdated-sheet{display:flex;flex-direction:column;gap:16px;padding:16px 18px 18px}.outdated-sheet__icon{align-items:center;background:#fff1d8;border-radius:14px;color:#171717;display:flex;height:40px;justify-content:center;width:40px}.outdated-sheet__copy{display:flex;flex-direction:column;gap:6px}.outdated-sheet__copy h2{color:#171717;font-size:18px;font-weight:580;letter-spacing:-.2px;line-height:22px;margin:0}.outdated-sheet__copy p{color:#737373;font-size:14px;line-height:19px;margin:0}.outdated-sheet__actions{display:flex;flex-direction:column;gap:8px}.outdated-sheet__button{align-items:center;border-radius:12px;display:flex;font-size:15px;font-weight:580;gap:8px;justify-content:center;line-height:20px;min-height:44px;padding:12px 14px;transition:background .15s,opacity .15s;width:100%}.outdated-sheet__button--primary{background:#171717;color:#fff}.outdated-sheet__button--primary:active{opacity:.88}.outdated-sheet__button--ghost{background:transparent;color:#404040}.outdated-sheet__button--ghost:active{background:#f5f5f5}
47
+ </style>
@@ -0,0 +1,14 @@
1
+ type __VLS_Props = {
2
+ open: boolean;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
5
+ close: () => any;
6
+ dismiss: () => any;
7
+ newConversation: () => any;
8
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onClose?: (() => any) | undefined;
10
+ onDismiss?: (() => any) | undefined;
11
+ onNewConversation?: (() => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;