@meistrari/tela-build 1.1.0 → 1.2.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/components/tela/badge/badge.vue +1 -1
- package/components/tela/button/button.vue +1 -0
- package/components/tela/collapsible/CollapsibleContent.vue +2 -2
- package/components/tela/icon/custom.vue +43 -23
- package/components/tela/input/tela-input.vue +1 -1
- package/components/tela/modal/modal.vue +38 -2
- package/components/tela/scroll-area/scroll-area.vue +9 -2
- package/components/tela/segment-toggle.vue +1 -1
- package/components/tela/status/status.mdx +5 -0
- package/components/tela/status/status.stories.ts +12 -0
- package/components/tela/status/status.vue +3 -16
- package/components/tela/todo-list/todo-list.vue +130 -0
- package/components/tela/tool-use-display/tool-use-display-details-modal.vue +182 -0
- package/components/tela/tool-use-display/tool-use-display.vue +145 -0
- package/css/text.css +13 -0
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ const tag = computed(() => props.to ? NuxtLink : 'div')
|
|
|
22
22
|
:class="cn(
|
|
23
23
|
'inline-block px-[5px] rounded-[5px] select-none',
|
|
24
24
|
variant === 'outline' && 'border-[0.5px] ring-border-strong',
|
|
25
|
-
variant === 'filled' && 'bg-
|
|
25
|
+
variant === 'filled' && 'bg-lowered',
|
|
26
26
|
props.class,
|
|
27
27
|
)"
|
|
28
28
|
>
|
|
@@ -21,10 +21,10 @@ function handleOpenAutoComplete() {
|
|
|
21
21
|
<CollapsibleContent
|
|
22
22
|
v-bind="props"
|
|
23
23
|
data-collapsible-content
|
|
24
|
-
class="overflow-hidden collapsible-content"
|
|
24
|
+
class="overflow-hidden collapsible-content h-full"
|
|
25
25
|
@animation-start="handleOpenAutoComplete"
|
|
26
26
|
>
|
|
27
|
-
<div ref="containerEl">
|
|
27
|
+
<div ref="containerEl" class="h-full">
|
|
28
28
|
<slot />
|
|
29
29
|
</div>
|
|
30
30
|
</CollapsibleContent>
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { TelaCustomIconName } from '~/types'
|
|
3
|
+
import { Motion } from 'motion-v'
|
|
3
4
|
|
|
4
5
|
const props = withDefaults(defineProps<{
|
|
5
|
-
size?: string
|
|
6
|
-
color?: string
|
|
7
|
-
name: TelaCustomIconName
|
|
6
|
+
size?: string
|
|
7
|
+
color?: string
|
|
8
|
+
name: TelaCustomIconName
|
|
9
|
+
isAnimated?: boolean
|
|
8
10
|
}>(), {
|
|
9
11
|
size: '12px',
|
|
10
12
|
color: 'neutral-400',
|
|
13
|
+
isAnimated: true,
|
|
11
14
|
})
|
|
12
15
|
|
|
13
16
|
const colorValue = computed(() => {
|
|
@@ -27,9 +30,10 @@ const colorValue = computed(() => {
|
|
|
27
30
|
</script>
|
|
28
31
|
|
|
29
32
|
<template>
|
|
30
|
-
<svg :width="size" :height="size" fill="none" :style="{ color: colorValue }" xmlns="http://www.w3.org/2000/svg">
|
|
33
|
+
<svg :width="size" :height="size" viewBox="0 0 12 12" fill="none" :style="{ color: colorValue }" xmlns="http://www.w3.org/2000/svg">
|
|
31
34
|
<template v-if="name === 'circle'">
|
|
32
|
-
<
|
|
35
|
+
<component
|
|
36
|
+
:is="isAnimated ? Motion : 'path'"
|
|
33
37
|
as="path"
|
|
34
38
|
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z"
|
|
35
39
|
fill="currentColor"
|
|
@@ -49,7 +53,8 @@ const colorValue = computed(() => {
|
|
|
49
53
|
</template>
|
|
50
54
|
|
|
51
55
|
<template v-if="name === 'queued'">
|
|
52
|
-
<
|
|
56
|
+
<component
|
|
57
|
+
:is="isAnimated ? Motion : 'path'"
|
|
53
58
|
as="path"
|
|
54
59
|
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z"
|
|
55
60
|
fill="currentColor"
|
|
@@ -57,7 +62,8 @@ const colorValue = computed(() => {
|
|
|
57
62
|
:animate="{ opacity: [0.2, 1] }"
|
|
58
63
|
:transition="{ duration: 0.8, ease: [0.4, 0, 0.2, 1] }"
|
|
59
64
|
/>
|
|
60
|
-
<
|
|
65
|
+
<component
|
|
66
|
+
:is="isAnimated ? Motion : 'rect'"
|
|
61
67
|
as="rect"
|
|
62
68
|
x="3.5"
|
|
63
69
|
y="6.5"
|
|
@@ -69,7 +75,8 @@ const colorValue = computed(() => {
|
|
|
69
75
|
:animate="{ opacity: [0.2, 1] }"
|
|
70
76
|
:transition="{ duration: 0.8, ease: 'easeOut', delay: 0.17, repeat: Infinity, repeatDelay: 1 }"
|
|
71
77
|
/>
|
|
72
|
-
<
|
|
78
|
+
<component
|
|
79
|
+
:is="isAnimated ? Motion : 'rect'"
|
|
73
80
|
as="rect"
|
|
74
81
|
x="4"
|
|
75
82
|
y="4.5"
|
|
@@ -81,7 +88,8 @@ const colorValue = computed(() => {
|
|
|
81
88
|
:animate="{ opacity: [0.2, 1] }"
|
|
82
89
|
:transition="{ duration: 0.8, ease: 'easeOut', delay: 0.12, repeat: Infinity, repeatDelay: 1 }"
|
|
83
90
|
/>
|
|
84
|
-
<
|
|
91
|
+
<component
|
|
92
|
+
:is="isAnimated ? Motion : 'rect'"
|
|
85
93
|
as="rect"
|
|
86
94
|
x="4.5"
|
|
87
95
|
y="3"
|
|
@@ -122,7 +130,8 @@ const colorValue = computed(() => {
|
|
|
122
130
|
</template>
|
|
123
131
|
|
|
124
132
|
<template v-if="name === 'circle-minus'">
|
|
125
|
-
<
|
|
133
|
+
<component
|
|
134
|
+
:is="isAnimated ? Motion : 'path'"
|
|
126
135
|
as="path"
|
|
127
136
|
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z"
|
|
128
137
|
fill="currentColor"
|
|
@@ -130,7 +139,8 @@ const colorValue = computed(() => {
|
|
|
130
139
|
:animate="{ opacity: [0.5, 1, 0.5] }"
|
|
131
140
|
:transition="{ duration: 2.2, ease: 'easeOut', repeat: Infinity }"
|
|
132
141
|
/>
|
|
133
|
-
<
|
|
142
|
+
<component
|
|
143
|
+
:is="isAnimated ? Motion : 'rect'"
|
|
134
144
|
as="rect"
|
|
135
145
|
x="3.5"
|
|
136
146
|
y="5"
|
|
@@ -145,12 +155,15 @@ const colorValue = computed(() => {
|
|
|
145
155
|
</template>
|
|
146
156
|
|
|
147
157
|
<template v-if="name === 'check'">
|
|
148
|
-
<
|
|
158
|
+
<component
|
|
159
|
+
:is="isAnimated ? Motion : 'g'" as="g" :animate="{ opacity: [0.4, 1] }" :transition="{ duration: 0.3, ease: [0.645, 0.045, 0.355, 1] }" tabindex="-1"
|
|
160
|
+
>
|
|
149
161
|
<path
|
|
150
162
|
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z"
|
|
151
163
|
fill="currentColor"
|
|
152
164
|
/>
|
|
153
|
-
<
|
|
165
|
+
<component
|
|
166
|
+
:is="isAnimated ? Motion : 'path'"
|
|
154
167
|
as="path"
|
|
155
168
|
d="M3.5 6 L5.5 8 L8.5 4"
|
|
156
169
|
stroke="currentColor"
|
|
@@ -160,10 +173,10 @@ const colorValue = computed(() => {
|
|
|
160
173
|
stroke-linejoin="round"
|
|
161
174
|
tabindex="-1"
|
|
162
175
|
:animate="{ pathLength: [0, 1] }"
|
|
163
|
-
:style="{ rotate: 4, scale: 0.85 }"
|
|
176
|
+
:style="{ rotate: isAnimated ? 4 : undefined, scale: isAnimated ? 0.85 : undefined }"
|
|
164
177
|
:transition="{ duration: 0.3, ease: [0.645, 0.045, 0.355, 1] }"
|
|
165
178
|
/>
|
|
166
|
-
</
|
|
179
|
+
</component>
|
|
167
180
|
</template>
|
|
168
181
|
|
|
169
182
|
<template v-if="name === 'stop'">
|
|
@@ -194,13 +207,15 @@ const colorValue = computed(() => {
|
|
|
194
207
|
</template>
|
|
195
208
|
|
|
196
209
|
<template v-if="name === 'warning'">
|
|
197
|
-
<
|
|
210
|
+
<component
|
|
211
|
+
:is="isAnimated ? Motion : 'g'"
|
|
198
212
|
as="g"
|
|
199
213
|
tabindex="-1"
|
|
200
214
|
:animate="{ opacity: [0.5, 1, 0.5] }"
|
|
201
215
|
:transition="{ duration: 1.4, ease: 'easeOut', repeat: Infinity }"
|
|
202
216
|
>
|
|
203
|
-
<
|
|
217
|
+
<component
|
|
218
|
+
:is="isAnimated ? Motion : 'path'"
|
|
204
219
|
as="path"
|
|
205
220
|
d="M11.4 6C11.7314 6 12.0031 5.73069 11.97 5.40098C11.858 4.28448 11.4345 3.21734 10.7422 2.32414C9.92681 1.27227 8.78487 0.521339 7.49603 0.189501C6.20719 -0.142337 4.84459 -0.0362459 3.62264 0.491083C2.40069 1.01841 1.38875 1.93705 0.746034 3.10244C0.103318 4.26784 -0.133688 5.61385 0.0723077 6.92869C0.278303 8.24353 0.915607 9.45256 1.88394 10.3656C2.85228 11.2786 4.09668 11.8437 5.42136 11.972C6.5462 12.081 7.67471 11.8698 8.67877 11.3688C8.97528 11.2209 9.05806 10.8474 8.88125 10.5671C8.70444 10.2868 8.3351 10.2068 8.03498 10.3473C7.25926 10.7104 6.39684 10.8609 5.53709 10.7776C4.47735 10.6749 3.48182 10.2228 2.70715 9.49244C1.93249 8.76205 1.42264 7.79482 1.25785 6.74295C1.09305 5.69108 1.28265 4.61427 1.79683 3.68195C2.311 2.74964 3.12055 2.01473 4.09811 1.59287C5.07567 1.171 6.16575 1.08613 7.19682 1.3516C8.2279 1.61707 9.14145 2.21782 9.79373 3.05932C10.3229 3.74201 10.6558 4.55173 10.7626 5.40155C10.8039 5.73033 11.0686 6 11.4 6Z"
|
|
206
221
|
fill="currentColor"
|
|
@@ -208,7 +223,8 @@ const colorValue = computed(() => {
|
|
|
208
223
|
:animate="{ rotate: [0, 360] }"
|
|
209
224
|
:transition="{ duration: 0.7, ease: 'easeOut', repeat: Infinity, repeatDelay: 0.1 }"
|
|
210
225
|
/>
|
|
211
|
-
<
|
|
226
|
+
<component
|
|
227
|
+
:is="isAnimated ? Motion : 'rect'"
|
|
212
228
|
as="rect"
|
|
213
229
|
x="5.25"
|
|
214
230
|
y="3"
|
|
@@ -227,17 +243,20 @@ const colorValue = computed(() => {
|
|
|
227
243
|
r="0.875"
|
|
228
244
|
fill="currentColor"
|
|
229
245
|
/>
|
|
230
|
-
</
|
|
246
|
+
</component>
|
|
231
247
|
</template>
|
|
232
248
|
|
|
233
249
|
<template v-if="name === 'check-dashed'">
|
|
234
|
-
<
|
|
250
|
+
<component
|
|
251
|
+
:is="isAnimated ? Motion : 'g'" as="g" clip-path="url(#clip0_5125_104)" tabindex="-1" :animate="{ opacity: [0.4, 1] }" :transition="{ duration: 0.3, ease: [0.645, 0.045, 0.355, 1] }"
|
|
252
|
+
>
|
|
235
253
|
<path d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z" fill="currentColor" />
|
|
236
254
|
<rect x="5.25" width="1.5" height="12" fill="#F0FDF6" />
|
|
237
255
|
<rect x="12" y="5.25" width="1.5" height="12" transform="rotate(90 12 5.25)" fill="#F0FDF6" />
|
|
238
256
|
<rect x="10.773" y="9.71228" width="1.5" height="12" transform="rotate(135 10.773 9.71228)" fill="#F0FDF6" />
|
|
239
257
|
<rect x="2.28769" y="10.7729" width="1.5" height="12" transform="rotate(-135 2.28769 10.7729)" fill="#F0FDF6" />
|
|
240
|
-
<
|
|
258
|
+
<component
|
|
259
|
+
:is="isAnimated ? Motion : 'path'"
|
|
241
260
|
as="path"
|
|
242
261
|
d="M3.5 6 L5.5 8 L8.5 4"
|
|
243
262
|
stroke="currentColor"
|
|
@@ -250,7 +269,7 @@ const colorValue = computed(() => {
|
|
|
250
269
|
:style="{ rotate: 4, scale: 0.85 }"
|
|
251
270
|
:transition="{ duration: 0.3, ease: [0.645, 0.045, 0.355, 1] }"
|
|
252
271
|
/>
|
|
253
|
-
</
|
|
272
|
+
</component>
|
|
254
273
|
<defs>
|
|
255
274
|
<clipPath id="clip0_5125_104">
|
|
256
275
|
<rect width="12" height="12" fill="white" />
|
|
@@ -275,7 +294,8 @@ const colorValue = computed(() => {
|
|
|
275
294
|
|
|
276
295
|
<template v-if="name === 'arrow-down'">
|
|
277
296
|
<path d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM1.2 6C1.2 8.65097 3.34903 10.8 6 10.8C8.65097 10.8 10.8 8.65097 10.8 6C10.8 3.34903 8.65097 1.2 6 1.2C3.34903 1.2 1.2 3.34903 1.2 6Z" fill="#A3A3A3" />
|
|
278
|
-
<
|
|
297
|
+
<component
|
|
298
|
+
:is="isAnimated ? Motion : 'path'"
|
|
279
299
|
as="path"
|
|
280
300
|
d="M6 4V8M6 8L7.75 6.53682M6 8L4.25 6.53682"
|
|
281
301
|
stroke="currentColor"
|
|
@@ -138,7 +138,7 @@ defineExpose({
|
|
|
138
138
|
@click="$el.querySelector(isTextarea ? 'textarea' : 'input')?.focus()"
|
|
139
139
|
>
|
|
140
140
|
<div v-if="icon" flex mr-6px>
|
|
141
|
-
<TelaIcon :name="icon" size="sm" text="gray-
|
|
141
|
+
<TelaIcon :name="icon" size="sm" text="gray-400" />
|
|
142
142
|
</div>
|
|
143
143
|
<div
|
|
144
144
|
flex="~ col" grow align-center h-full
|
|
@@ -183,7 +183,15 @@ function handlePointerDownOutside(event: any) {
|
|
|
183
183
|
background-color: rgba(2, 9, 19, 0.24);
|
|
184
184
|
position: fixed;
|
|
185
185
|
inset: 0;
|
|
186
|
-
|
|
186
|
+
|
|
187
|
+
&[data-state="open"] {
|
|
188
|
+
animation: overlayShow 0.12s ease-out forwards;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
&[data-state="closed"] {
|
|
192
|
+
animation: overlayHide 0.12s ease-out forwards;
|
|
193
|
+
animation-delay: 0s;
|
|
194
|
+
}
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
.DialogContent {
|
|
@@ -191,7 +199,15 @@ function handlePointerDownOutside(event: any) {
|
|
|
191
199
|
overflow-x: hidden;
|
|
192
200
|
width: 400px;
|
|
193
201
|
padding: 24px;
|
|
194
|
-
|
|
202
|
+
|
|
203
|
+
&[data-state="open"] {
|
|
204
|
+
animation: contentShow 0.12s ease-out forwards;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
&[data-state="closed"] {
|
|
208
|
+
animation: contentHide 0.12s ease-out forwards;
|
|
209
|
+
animation-delay: 0s;
|
|
210
|
+
}
|
|
195
211
|
}
|
|
196
212
|
|
|
197
213
|
.DialogContent:focus {
|
|
@@ -229,6 +245,15 @@ function handlePointerDownOutside(event: any) {
|
|
|
229
245
|
}
|
|
230
246
|
}
|
|
231
247
|
|
|
248
|
+
@keyframes overlayHide {
|
|
249
|
+
from {
|
|
250
|
+
opacity: 1;
|
|
251
|
+
}
|
|
252
|
+
to {
|
|
253
|
+
opacity: 0;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
232
257
|
@keyframes contentShow {
|
|
233
258
|
from {
|
|
234
259
|
opacity: 0;
|
|
@@ -239,4 +264,15 @@ function handlePointerDownOutside(event: any) {
|
|
|
239
264
|
transform: scale(1);
|
|
240
265
|
}
|
|
241
266
|
}
|
|
267
|
+
|
|
268
|
+
@keyframes contentHide {
|
|
269
|
+
from {
|
|
270
|
+
opacity: 1;
|
|
271
|
+
transform: scale(1);
|
|
272
|
+
}
|
|
273
|
+
to {
|
|
274
|
+
opacity: 0;
|
|
275
|
+
transform: scale(0.96);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
242
278
|
</style>
|
|
@@ -10,7 +10,13 @@ import { computed } from 'vue'
|
|
|
10
10
|
import type { HTMLAttributes } from 'vue'
|
|
11
11
|
import ScrollBar from './scroll-bar.vue'
|
|
12
12
|
|
|
13
|
-
const props =
|
|
13
|
+
const props = withDefaults(
|
|
14
|
+
defineProps<ScrollAreaRootProps
|
|
15
|
+
& { class?: HTMLAttributes['class'], orientation?: 'vertical' | 'horizontal' | 'both' }>(),
|
|
16
|
+
{
|
|
17
|
+
orientation: 'vertical',
|
|
18
|
+
},
|
|
19
|
+
)
|
|
14
20
|
|
|
15
21
|
const delegatedProps = computed(() => {
|
|
16
22
|
const { class: _, ...delegated } = props
|
|
@@ -24,7 +30,8 @@ const delegatedProps = computed(() => {
|
|
|
24
30
|
<ScrollAreaViewport class="h-full w-full rounded-[inherit]">
|
|
25
31
|
<slot />
|
|
26
32
|
</ScrollAreaViewport>
|
|
27
|
-
<ScrollBar />
|
|
33
|
+
<ScrollBar v-if="props.orientation === 'vertical' || props.orientation === 'both'" orientation="vertical" />
|
|
34
|
+
<ScrollBar v-if="props.orientation === 'horizontal' || props.orientation === 'both'" orientation="horizontal" />
|
|
28
35
|
<ScrollAreaCorner />
|
|
29
36
|
</ScrollAreaRoot>
|
|
30
37
|
</template>
|
|
@@ -28,7 +28,7 @@ function selectTab(value: string) {
|
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
30
|
<div
|
|
31
|
-
rounded-full flex items-center gap-2px select-none p-2px min-w-68px bg-gray-
|
|
31
|
+
rounded-full flex items-center gap-2px select-none p-2px min-w-68px bg-gray-200
|
|
32
32
|
:class="[
|
|
33
33
|
props.size === 'small' ? 'min-h-24px' : 'min-h-28px',
|
|
34
34
|
props.disabled && 'opacity-50 pointer-events-none cursor-not-allowed',
|
|
@@ -21,6 +21,10 @@ A status component that displays different workflow and task statuses with appro
|
|
|
21
21
|
|
|
22
22
|
<Canvas of={StatusStories.AnimatedTransitions} />
|
|
23
23
|
|
|
24
|
+
### Without Icon Animation
|
|
25
|
+
|
|
26
|
+
<Canvas of={StatusStories.WithoutIconAnimation} />
|
|
27
|
+
|
|
24
28
|
### Basic Usage
|
|
25
29
|
|
|
26
30
|
```vue
|
|
@@ -83,6 +87,7 @@ type Variant =
|
|
|
83
87
|
type StatusProps = {
|
|
84
88
|
variant?: Variant
|
|
85
89
|
label?: string
|
|
90
|
+
isIconAnimated?: boolean
|
|
86
91
|
}
|
|
87
92
|
```
|
|
88
93
|
|
|
@@ -158,3 +158,15 @@ export const AnimatedTransitions: Story = {
|
|
|
158
158
|
layout: 'centered',
|
|
159
159
|
},
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
export const WithoutIconAnimation: Story = {
|
|
163
|
+
render: () => {
|
|
164
|
+
return {
|
|
165
|
+
components: { Status },
|
|
166
|
+
template: '<Status variant="pending-run" :is-icon-animated="false" />',
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
parameters: {
|
|
170
|
+
layout: 'centered',
|
|
171
|
+
},
|
|
172
|
+
}
|
|
@@ -14,8 +14,10 @@ type StatusConfig = {
|
|
|
14
14
|
const props = withDefaults(defineProps<{
|
|
15
15
|
variant?: TelaStatusVariant
|
|
16
16
|
label?: string
|
|
17
|
+
isIconAnimated?: boolean
|
|
17
18
|
}>(), {
|
|
18
19
|
variant: 'running',
|
|
20
|
+
isIconAnimated: true,
|
|
19
21
|
})
|
|
20
22
|
|
|
21
23
|
const variantConfig: Record<TelaStatusVariant, StatusConfig> = {
|
|
@@ -385,7 +387,7 @@ const SPRING_CONFIG = {
|
|
|
385
387
|
>
|
|
386
388
|
<div :class="cn('relative z-1 p-[2px]', backgroundColor)">
|
|
387
389
|
<Motion :key="`icon-${iconName}`" v-bind="iconVariants()">
|
|
388
|
-
<TelaIconCustom :name="iconName" :color="iconColor" />
|
|
390
|
+
<TelaIconCustom :name="iconName" :color="iconColor" :is-animated="isIconAnimated" />
|
|
389
391
|
</Motion>
|
|
390
392
|
</div>
|
|
391
393
|
<Motion
|
|
@@ -403,18 +405,3 @@ const SPRING_CONFIG = {
|
|
|
403
405
|
</div>
|
|
404
406
|
</MotionConfig>
|
|
405
407
|
</template>
|
|
406
|
-
|
|
407
|
-
<style scoped>
|
|
408
|
-
.animate-shine {
|
|
409
|
-
animation: shine 6s 0.05s linear infinite;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
@keyframes shine {
|
|
413
|
-
0% {
|
|
414
|
-
background-position: 350% 0;
|
|
415
|
-
}
|
|
416
|
-
100% {
|
|
417
|
-
background-position: -350% 0;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
</style>
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Todo {
|
|
5
|
+
id: string
|
|
6
|
+
content: string
|
|
7
|
+
status: 'pending' | 'in_progress' | 'completed' | 'cancelled'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(defineProps<{
|
|
11
|
+
todos: Todo[]
|
|
12
|
+
title?: string
|
|
13
|
+
completedText?: string
|
|
14
|
+
showMoreText?: string
|
|
15
|
+
showLessText?: string
|
|
16
|
+
class?: HTMLAttributes['class']
|
|
17
|
+
contentClass?: HTMLAttributes['class']
|
|
18
|
+
footerClass?: HTMLAttributes['class']
|
|
19
|
+
}>(), {
|
|
20
|
+
title: 'To-do-list',
|
|
21
|
+
completedText: 'completed',
|
|
22
|
+
showMoreText: 'Show more',
|
|
23
|
+
showLessText: 'Show less',
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const isExpanded = ref(false)
|
|
27
|
+
|
|
28
|
+
const contentMeasure = useTemplateRef<HTMLElement>('contentMeasure')
|
|
29
|
+
const { height: heightContent } = useElementSize(contentMeasure)
|
|
30
|
+
|
|
31
|
+
const computedHeightContent = computed(() => {
|
|
32
|
+
if (heightContent.value > 0) {
|
|
33
|
+
return `${heightContent.value}px`
|
|
34
|
+
}
|
|
35
|
+
return undefined
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const completedCount = computed(() => props.todos.filter(t => t.status === 'completed').length)
|
|
39
|
+
const completedPercent = computed(() => Math.round((completedCount.value / props.todos.length) * 100))
|
|
40
|
+
|
|
41
|
+
const sortedTodos = computed(() => {
|
|
42
|
+
const order: Record<Todo['status'], number> = { in_progress: 0, completed: 1, pending: 2, cancelled: 3 }
|
|
43
|
+
const sorted = [...props.todos].sort((a, b) => order[a.status] - order[b.status])
|
|
44
|
+
|
|
45
|
+
if (!isExpanded.value && props.todos.length > 3) {
|
|
46
|
+
return sorted.slice(0, 3)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return sorted
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
function getIconName(status: Todo['status']) {
|
|
53
|
+
if (status === 'completed')
|
|
54
|
+
return 'check'
|
|
55
|
+
|
|
56
|
+
if (status === 'in_progress')
|
|
57
|
+
return 'circle-notch'
|
|
58
|
+
|
|
59
|
+
if (status === 'cancelled')
|
|
60
|
+
return 'close'
|
|
61
|
+
|
|
62
|
+
return 'circle'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getIconColor(status: Todo['status']) {
|
|
66
|
+
if (status === 'completed')
|
|
67
|
+
return 'gray-700'
|
|
68
|
+
|
|
69
|
+
return 'neutral-400'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const showMoreTextWithCount = computed(() => {
|
|
73
|
+
const parts = props.showMoreText.split(' ')
|
|
74
|
+
const count = (props.todos.length - sortedTodos.value.length).toString()
|
|
75
|
+
|
|
76
|
+
return parts.join(` ${count} `)
|
|
77
|
+
})
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<template>
|
|
81
|
+
<div
|
|
82
|
+
px-12px pt-12px bg-background rounded-16px overflow-hidden
|
|
83
|
+
:class="cn(!isExpanded && todos.length <= 3 && 'pb-10px', props.class)"
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
transition-height duration-200 ease-out
|
|
87
|
+
:style="computedHeightContent ? { height: computedHeightContent } : {}"
|
|
88
|
+
>
|
|
89
|
+
<div ref="contentMeasure">
|
|
90
|
+
<div flex="~ col" gap-10px :class="props.contentClass">
|
|
91
|
+
<div flex items-center justify-between pl-4px pb-10px border-b-0.5px border>
|
|
92
|
+
<h5 heading-h5-semibold text-primary>
|
|
93
|
+
{{ $t('workflow.agent.tools.todoList') }}
|
|
94
|
+
</h5>
|
|
95
|
+
<p body-14-medium text-secondary>
|
|
96
|
+
<TelaAnimatedNumber :value="completedPercent" />% {{ $t('workflow.agent.tools.completed') }}
|
|
97
|
+
</p>
|
|
98
|
+
</div>
|
|
99
|
+
<div flex="~ col" gap-7px px-1px>
|
|
100
|
+
<div v-for="todo in sortedTodos" :key="todo.id" relative flex items-center gap-8px py-1px>
|
|
101
|
+
<TelaIconCustom :name="getIconName(todo.status)" :color="getIconColor(todo.status)" shrink-0 :is-animated="false" />
|
|
102
|
+
<span
|
|
103
|
+
body-14-medium truncate w="90%"
|
|
104
|
+
:class="{
|
|
105
|
+
'text-primary': (todo.status === 'completed' || todo.status === 'in_progress'),
|
|
106
|
+
'text-tertiary': todo.status === 'pending',
|
|
107
|
+
'text-tertiary line-through': todo.status === 'cancelled',
|
|
108
|
+
}"
|
|
109
|
+
>
|
|
110
|
+
{{ todo.content }}
|
|
111
|
+
</span>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<div flex="~ col" :class="props.footerClass">
|
|
118
|
+
<button
|
|
119
|
+
v-if="todos.length > 3"
|
|
120
|
+
type="button"
|
|
121
|
+
relative z-10 items-center justify-center bg-background h-32px pb-4px mx--12px w="calc(100% + 24px)"
|
|
122
|
+
@click="isExpanded = !isExpanded"
|
|
123
|
+
>
|
|
124
|
+
<span body-12-semibold text-primary>
|
|
125
|
+
{{ isExpanded ? props.showLessText : showMoreTextWithCount }}
|
|
126
|
+
</span>
|
|
127
|
+
</button>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</template>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface ToolUse {
|
|
3
|
+
name: string
|
|
4
|
+
input?: Record<string, any>
|
|
5
|
+
description?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ToolResult {
|
|
9
|
+
id: string
|
|
10
|
+
output: string
|
|
11
|
+
isError: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ToolDetailsModalProps {
|
|
15
|
+
isOpen: boolean
|
|
16
|
+
toolUse: ToolUse
|
|
17
|
+
toolResult: ToolResult
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const props = defineProps<ToolDetailsModalProps>()
|
|
21
|
+
|
|
22
|
+
const emit = defineEmits<{
|
|
23
|
+
close: []
|
|
24
|
+
}>()
|
|
25
|
+
|
|
26
|
+
const expanded = reactive<Record<string, boolean>>({})
|
|
27
|
+
|
|
28
|
+
const input = computed(() => {
|
|
29
|
+
return props.toolUse.input
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
function toggle(key: string) {
|
|
33
|
+
expanded[key] = !expanded[key]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function textForValue(value: any) {
|
|
37
|
+
if (typeof value === 'string')
|
|
38
|
+
return value
|
|
39
|
+
try {
|
|
40
|
+
return JSON.stringify(value, null, 2)
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return String(value)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function needsToggle(value: any) {
|
|
48
|
+
return (textForValue(value) ?? '').length > 500
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function closeDialog() {
|
|
52
|
+
emit('close')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function capitalize(string: string) {
|
|
56
|
+
return string.replace(/_/g, ' ').charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1)
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<TelaModal
|
|
62
|
+
:model-value="isOpen"
|
|
63
|
+
compact
|
|
64
|
+
hide-dividers
|
|
65
|
+
:style="{
|
|
66
|
+
width: '480px',
|
|
67
|
+
maxHeight: '90vh',
|
|
68
|
+
overflow: 'hidden',
|
|
69
|
+
padding: '24px',
|
|
70
|
+
}"
|
|
71
|
+
:is-close-icon="false"
|
|
72
|
+
@close="closeDialog"
|
|
73
|
+
>
|
|
74
|
+
<div flex="~ col" w-full h-full gap-24px>
|
|
75
|
+
<!-- Header -->
|
|
76
|
+
<div flex="~ col">
|
|
77
|
+
<div flex="~ row justify-between" items-start>
|
|
78
|
+
<h3 heading-h3-semibold text-primary>
|
|
79
|
+
{{ toolUse.name === 'Grep' ? `${$t('workflow.codeExecution')} ·` : '' }} {{ toolUse.name }}
|
|
80
|
+
</h3>
|
|
81
|
+
<TelaIconButton
|
|
82
|
+
icon="i-ph-x"
|
|
83
|
+
size="md"
|
|
84
|
+
color="secondary"
|
|
85
|
+
outline-none
|
|
86
|
+
p-8px mt--16px mr--16px
|
|
87
|
+
@click="closeDialog"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
<p body-14-regular text-secondary mt-4px w="90%" class="[text-wrap:pretty]">
|
|
91
|
+
{{ $t('dashboard.modals.toolDetailsModal.description') }}
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!-- Tool Input Parameters -->
|
|
96
|
+
<div flex="~ col" gap-20px>
|
|
97
|
+
<div v-if="input && Object.keys(input).length > 0" text-secondary flex="~ col" gap-20px>
|
|
98
|
+
<div v-for="(value, key) in input" :key="key" flex="~ col" gap-6px>
|
|
99
|
+
<span body-12-medium text-primary>{{ capitalize(key) }}</span>
|
|
100
|
+
|
|
101
|
+
<div v-if="typeof value === 'string' || typeof value === 'boolean' || typeof value === 'number'" border-0.5px border-gray-200 rounded-10px pl-2 py-2>
|
|
102
|
+
<TelaScrollArea>
|
|
103
|
+
<div max-h-300px pr-4>
|
|
104
|
+
<pre v-if="typeof value === 'string'" body-12-regular font-mono whitespace-pre-wrap break-words overflow-wrap-anywhere m-0>{{ value }}</pre>
|
|
105
|
+
<span v-else-if="typeof value === 'boolean'" block body-12-regular font-mono>{{ value ? 'true' : 'false' }}</span>
|
|
106
|
+
<span v-else-if="typeof value === 'number'" block body-12-regular font-mono>{{ value }}</span>
|
|
107
|
+
</div>
|
|
108
|
+
</TelaScrollArea>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<!-- Array value -->
|
|
112
|
+
<div v-else-if="Array.isArray(value)" flex="~ col" gap-4px>
|
|
113
|
+
<span text-xs text-gray-500>
|
|
114
|
+
{{ $t('reasoningSteps.itemsCount', { count: value.length }) }}
|
|
115
|
+
</span>
|
|
116
|
+
<div bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
117
|
+
<div v-for="(item, idx) in value" :key="idx" text-sm py-0.5>
|
|
118
|
+
<span text-gray-400 mr-2 font-mono>{{ idx }}:</span>
|
|
119
|
+
<span font-mono>{{ typeof item === 'string' ? item : JSON.stringify(item) }}</span>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Object value -->
|
|
125
|
+
<div v-else-if="typeof value === 'object' && value !== null" flex="~ col" gap-4px>
|
|
126
|
+
<span text-xs text-gray-500>
|
|
127
|
+
{{ $t('reasoningSteps.propertiesCount', { count: Object.keys(value).length }) }}
|
|
128
|
+
</span>
|
|
129
|
+
<div bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
130
|
+
<div
|
|
131
|
+
:style="{ maxHeight: expanded[String(key)] ? 'none' : '400px', overflow: expanded[String(key)] ? 'visible' : 'hidden' }"
|
|
132
|
+
text-sm font-mono whitespace-pre-wrap break-words overflow-wrap-anywhere
|
|
133
|
+
>
|
|
134
|
+
<pre m-0 break-words overflow-wrap-anywhere>{{ textForValue(value) }}</pre>
|
|
135
|
+
</div>
|
|
136
|
+
<div v-if="needsToggle(value)" mt-2 flex justify-center>
|
|
137
|
+
<button type="button" text-sm text-primary-600 hover:opacity-80 flex items-center gap-2 @click.prevent="toggle(String(key))">
|
|
138
|
+
{{ expanded[String(key)] ? $t('reasoningSteps.showLess') : $t('reasoningSteps.showMore') }}
|
|
139
|
+
<i class="i-ph-caret-down" :style="{ transform: expanded[String(key)] ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s' }" />
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<!-- Null value -->
|
|
146
|
+
<div v-else-if="value === null" bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
147
|
+
<span text-sm font-mono text-gray-500>null</span>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<!-- Fallback for other types -->
|
|
151
|
+
<div v-else bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
152
|
+
<div :style="{ maxHeight: expanded[String(key)] ? 'none' : '400px', overflow: expanded[String(key)] ? 'visible' : 'hidden' }">
|
|
153
|
+
<pre text-sm font-mono>{{ textForValue(value) }}</pre>
|
|
154
|
+
</div>
|
|
155
|
+
<div v-if="needsToggle(value)" mt-2 flex justify-center>
|
|
156
|
+
<button type="button" text-sm text-primary-600 hover:opacity-80 flex items-center gap-2 @click.prevent="toggle(String(key))">
|
|
157
|
+
{{ expanded[String(key)] ? $t('reasoningSteps.showLess') : $t('reasoningSteps.showMore') }}
|
|
158
|
+
<i class="i-ph-caret-down" :style="{ transform: expanded[String(key)] ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s' }" />
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
<div flex="~ col" gap-6px>
|
|
165
|
+
<span body-12-medium text-primary>{{ $t('workflow.result') }}</span>
|
|
166
|
+
<div v-if="toolResult" border-0.5px border-gray-200 rounded-10px pl-2 py-2>
|
|
167
|
+
<TelaScrollArea>
|
|
168
|
+
<div max-h-300px pr-4>
|
|
169
|
+
<span block body-12-regular text-secondary font-mono>
|
|
170
|
+
{{ toolResult.output }}
|
|
171
|
+
</span>
|
|
172
|
+
</div>
|
|
173
|
+
</TelaScrollArea>
|
|
174
|
+
</div>
|
|
175
|
+
<div v-else rounded-10px overflow-hidden>
|
|
176
|
+
<TelaSkeleton w-full h-30px rounded-none bg-gray-200 />
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</TelaModal>
|
|
182
|
+
</template>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ToolUseDisplayDetailsModal from './tool-use-display-details-modal.vue'
|
|
3
|
+
|
|
4
|
+
interface ToolUse {
|
|
5
|
+
name: string
|
|
6
|
+
input?: Record<string, any>
|
|
7
|
+
description?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ToolResult {
|
|
11
|
+
id: string
|
|
12
|
+
output: string
|
|
13
|
+
isError: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const props = withDefaults(defineProps<{
|
|
17
|
+
toolUse: ToolUse
|
|
18
|
+
toolResult: ToolResult
|
|
19
|
+
isRunning?: boolean
|
|
20
|
+
detailsButtonLabel?: string
|
|
21
|
+
toolRunningLabel?: string
|
|
22
|
+
toolExecutedLabel?: string
|
|
23
|
+
showMoreLabel?: string
|
|
24
|
+
showLessLabel?: string
|
|
25
|
+
codeExecutionLabel?: string
|
|
26
|
+
itemsLabel?: string
|
|
27
|
+
propertiesLabel?: string
|
|
28
|
+
}>(), {
|
|
29
|
+
toolRunningLabel: 'Tool running',
|
|
30
|
+
toolExecutedLabel: 'Tool executed',
|
|
31
|
+
showMoreLabel: 'Show more',
|
|
32
|
+
showLessLabel: 'Show less',
|
|
33
|
+
codeExecutionLabel: 'Code execution',
|
|
34
|
+
detailsButtonLabel: 'Details',
|
|
35
|
+
itemsLabel: 'items',
|
|
36
|
+
propertiesLabel: 'properties',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const isToolDetailsModalOpen = ref(false)
|
|
40
|
+
|
|
41
|
+
const input = computed(() => {
|
|
42
|
+
const rawInput = props.toolUse.input ?? {}
|
|
43
|
+
|
|
44
|
+
return Object.fromEntries(
|
|
45
|
+
Object.entries(rawInput).filter(([key]) => key !== 'description' && key !== 'content').slice(0, 1),
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
function textForValue(value: any) {
|
|
50
|
+
if (typeof value === 'string')
|
|
51
|
+
return value
|
|
52
|
+
try {
|
|
53
|
+
return JSON.stringify(value, null, 2)
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return String(value)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function openDetailsModal() {
|
|
61
|
+
isToolDetailsModalOpen.value = true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function closeDetailsModal() {
|
|
65
|
+
isToolDetailsModalOpen.value = false
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<div v-if="isRunning || (input && Object.keys(input).length > 0)" px-14px py-12px bg-background rounded-16px>
|
|
71
|
+
<div pb-12px border-b-0.5px border>
|
|
72
|
+
<div flex items-center gap-6px>
|
|
73
|
+
<TelaIconCustom v-if="isRunning" name="circle-notch" size="12px" :is-animated="true" />
|
|
74
|
+
<TelaIconCustom v-else name="check" size="12px" :is-animated="false" />
|
|
75
|
+
<p body-12-regular text-black-700>
|
|
76
|
+
{{ isRunning ? toolRunningLabel : toolExecutedLabel }}
|
|
77
|
+
</p>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
<div v-if="input && Object.keys(input).length > 0" mt-12px>
|
|
81
|
+
<div v-for="(value, key) in input" :key="key" flex items-center gap-8px>
|
|
82
|
+
<div flex items-center justify-center shrink-0 w-24px h-24px bg-lowered rounded-7px>
|
|
83
|
+
<TelaIcon name="i-ph-code-bold" color="gray-500" />
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div flex-1 min-w-0 flex items-center justify-between gap-8px>
|
|
87
|
+
<div flex="~ col" min-w-0 flex-1>
|
|
88
|
+
<p body-12-medium text-primary>
|
|
89
|
+
{{ toolUse.name === 'Grep' ? `${codeExecutionLabel} ·` : '' }} {{ toolUse.name }}
|
|
90
|
+
</p>
|
|
91
|
+
|
|
92
|
+
<p v-if="typeof value === 'string'" body-12-regular text-secondary line-clamp-2>
|
|
93
|
+
{{ value }}
|
|
94
|
+
</p>
|
|
95
|
+
|
|
96
|
+
<span v-else-if="typeof value === 'boolean'" block text-sm font-mono text-gray-700>
|
|
97
|
+
{{ value ? 'true' : 'false' }}
|
|
98
|
+
</span>
|
|
99
|
+
|
|
100
|
+
<span v-else-if="typeof value === 'number'" block text-sm font-mono text-gray-700>
|
|
101
|
+
{{ value }}
|
|
102
|
+
</span>
|
|
103
|
+
|
|
104
|
+
<div v-else-if="Array.isArray(value)">
|
|
105
|
+
<div block text-xs text-gray-500 mb-1>
|
|
106
|
+
{{ value.length }} {{ itemsLabel }}
|
|
107
|
+
</div>
|
|
108
|
+
<div bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
109
|
+
<div v-for="(item, idx) in value" :key="idx" text-sm text-gray-700 py-0.5>
|
|
110
|
+
<span text-gray-400 mr-2 font-mono>{{ idx }}:</span>
|
|
111
|
+
<span font-mono>{{ typeof item === 'string' ? item : JSON.stringify(item) }}</span>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div v-else-if="typeof value === 'object' && value !== null">
|
|
117
|
+
<div block text-xs text-gray-500 mb-1>
|
|
118
|
+
{{ Object.keys(value).length }} {{ propertiesLabel }}
|
|
119
|
+
</div>
|
|
120
|
+
<div bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
121
|
+
<pre text-sm text-gray-700 font-mono whitespace-pre-wrap break-words overflow-wrap-anywhere>{{ textForValue(value) }}</pre>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<span v-else-if="value === null" block text-sm font-mono text-gray-700>null</span>
|
|
126
|
+
|
|
127
|
+
<div v-else bg-gray-50 rounded-xl border-0.5px border-gray-200 p-3>
|
|
128
|
+
<pre text-sm text-gray-700 font-mono>{{ textForValue(value) }}</pre>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<TelaButton variant="secondary" size="sm" shrink-0 @click="openDetailsModal">
|
|
132
|
+
{{ detailsButtonLabel }}
|
|
133
|
+
</TelaButton>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<ToolUseDisplayDetailsModal
|
|
140
|
+
:is-open="isToolDetailsModalOpen"
|
|
141
|
+
:tool-use="toolUse"
|
|
142
|
+
:tool-result="toolResult"
|
|
143
|
+
@close="closeDetailsModal"
|
|
144
|
+
/>
|
|
145
|
+
</template>
|
package/css/text.css
CHANGED
|
@@ -20,3 +20,16 @@ h5 {
|
|
|
20
20
|
h6 {
|
|
21
21
|
--at-apply: 'text-h6 text-gray-950';
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
.animate-shine {
|
|
25
|
+
animation: shine 6s 0.05s linear infinite;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes shine {
|
|
29
|
+
0% {
|
|
30
|
+
background-position: 350% 0;
|
|
31
|
+
}
|
|
32
|
+
100% {
|
|
33
|
+
background-position: -350% 0;
|
|
34
|
+
}
|
|
35
|
+
}
|