@parallelworks/ui 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/adapter/types.d.ts +5 -0
- package/dist/ai/ai.css +197 -21
- package/dist/ai/components/AllocationSelector.js +2 -2
- package/dist/ai/components/BranchNavigator.js +6 -6
- package/dist/ai/components/ChatEmptyState.js +39 -36
- package/dist/ai/components/ChatInput.js +67 -60
- package/dist/ai/components/ChatMessage.js +21 -20
- package/dist/ai/components/ChatMessageList.d.ts +7 -2
- package/dist/ai/components/ChatMessageList.js +65 -54
- package/dist/ai/components/ChatSidebar.js +6 -6
- package/dist/ai/components/ChatThread.js +3 -63
- package/dist/ai/components/ModelSelector.js +7 -7
- package/dist/ai/components/PastedText.d.ts +3 -1
- package/dist/ai/components/PastedText.js +21 -6
- package/dist/ai/components/Reasoning.d.ts +17 -0
- package/dist/ai/components/Reasoning.js +29 -0
- package/dist/ai/components/agent/AgentMessageParts.js +32 -22
- package/dist/ai/core/ChatProvider.js +3 -1
- package/dist/ai/core/parts.js +20 -0
- package/dist/ai/core/pasteLanguage.d.ts +6 -0
- package/dist/ai/core/pasteLanguage.js +45 -0
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +2 -2
- package/dist/ai/strings.d.ts +9 -0
- package/dist/ai/strings.js +7 -1
- package/dist/ai/ui/Notice.d.ts +8 -0
- package/dist/ai/ui/Notice.js +27 -1
- package/dist/ai/ui/sidebar.js +3 -3
- package/dist/file-explorer/FileExplorer.js +34 -11
- package/dist/file-explorer/FilePreview/previewCache.d.ts +1 -1
- package/dist/file-explorer/FilePreview/previewCache.js +6 -4
- package/dist/file-explorer/lib/types.d.ts +1 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/ai/ai.css
CHANGED
|
@@ -105,9 +105,10 @@
|
|
|
105
105
|
border-radius: 0.5rem;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
/* Streamdown tables: the body's own type,
|
|
109
|
-
*
|
|
110
|
-
*
|
|
108
|
+
/* Streamdown tables: the body's own type, open rows on hairlines at a tenth
|
|
109
|
+
* of the ink under a firmer rule for the header (no frame, no fill, so a
|
|
110
|
+
* table reads as part of the answer rather than a widget dropped into it),
|
|
111
|
+
* and the copy/download controls only while the pointer is over the table. */
|
|
111
112
|
.markdown [data-streamdown="table-wrapper"] {
|
|
112
113
|
--table-line: color-mix(in oklab, var(--theme-panel, #000) 10%, transparent);
|
|
113
114
|
position: relative;
|
|
@@ -136,8 +137,8 @@
|
|
|
136
137
|
}
|
|
137
138
|
.markdown [data-streamdown="table-wrapper"] > div:last-child {
|
|
138
139
|
padding: 0;
|
|
139
|
-
border:
|
|
140
|
-
border-radius: 0
|
|
140
|
+
border: 0;
|
|
141
|
+
border-radius: 0;
|
|
141
142
|
background: transparent;
|
|
142
143
|
}
|
|
143
144
|
.markdown [data-streamdown="table-wrapper"] table {
|
|
@@ -148,10 +149,10 @@
|
|
|
148
149
|
.markdown [data-streamdown="table"] th {
|
|
149
150
|
padding: 0.4375rem 0.75rem;
|
|
150
151
|
font-size: 1rem;
|
|
151
|
-
font-weight:
|
|
152
|
+
font-weight: 600;
|
|
152
153
|
color: inherit;
|
|
153
|
-
background:
|
|
154
|
-
border-bottom: 1px solid var(--
|
|
154
|
+
background: transparent;
|
|
155
|
+
border-bottom: 1px solid color-mix(in oklab, var(--theme-panel, #000) 28%, transparent);
|
|
155
156
|
}
|
|
156
157
|
.markdown [data-streamdown="table"] td {
|
|
157
158
|
padding: 0.4375rem 0.75rem;
|
|
@@ -163,6 +164,16 @@
|
|
|
163
164
|
/* A prose column keeps enough room to read; a wide table scrolls instead. */
|
|
164
165
|
min-width: 9rem;
|
|
165
166
|
}
|
|
167
|
+
.markdown [data-streamdown="table"] thead {
|
|
168
|
+
background: transparent;
|
|
169
|
+
}
|
|
170
|
+
/* Unframed, the outer columns line up with the prose around the table. */
|
|
171
|
+
.markdown [data-streamdown="table"] :is(th, td):first-child {
|
|
172
|
+
padding-left: 0;
|
|
173
|
+
}
|
|
174
|
+
.markdown [data-streamdown="table"] :is(th, td):last-child {
|
|
175
|
+
padding-right: 0;
|
|
176
|
+
}
|
|
166
177
|
.markdown [data-streamdown="table"] tbody tr {
|
|
167
178
|
border-bottom: 1px solid var(--table-line);
|
|
168
179
|
}
|
|
@@ -175,24 +186,54 @@
|
|
|
175
186
|
}
|
|
176
187
|
}
|
|
177
188
|
|
|
178
|
-
/* Streamdown code blocks
|
|
189
|
+
/* Streamdown code blocks: one surface, not a frame around an inset panel.
|
|
190
|
+
* A wash of the ink with a hairline edge holds the language on its top edge,
|
|
191
|
+
* the copy and download controls quiet beside it, and the code on the same
|
|
192
|
+
* ground, so the block reads as part of the answer. */
|
|
179
193
|
.markdown [data-streamdown="code-block"] {
|
|
180
|
-
padding: 0.375rem 0.5rem 0;
|
|
181
|
-
margin: 0.5em 0;
|
|
182
194
|
gap: 0;
|
|
195
|
+
margin: 0.875rem 0;
|
|
196
|
+
padding: 0;
|
|
197
|
+
border: 0;
|
|
198
|
+
border-radius: 0.75rem;
|
|
199
|
+
overflow: hidden;
|
|
200
|
+
background: color-mix(in oklab, var(--theme-panel, #000) 4%, var(--theme-panel-bg, #fff));
|
|
201
|
+
box-shadow: 0 0 0 1px color-mix(in oklab, var(--theme-panel, #000) 8%, transparent);
|
|
183
202
|
}
|
|
184
203
|
.markdown [data-streamdown="code-block-header"] {
|
|
185
|
-
|
|
204
|
+
height: 2.25rem;
|
|
205
|
+
padding: 0 0.75rem 0 0.75rem;
|
|
206
|
+
font-size: 0.75rem;
|
|
207
|
+
color: var(--theme-muted-text-color, #6a7282);
|
|
208
|
+
}
|
|
209
|
+
.markdown [data-streamdown="code-block-actions"] {
|
|
210
|
+
gap: 0.125rem;
|
|
211
|
+
padding: 0;
|
|
212
|
+
border: 0;
|
|
213
|
+
background: transparent;
|
|
214
|
+
backdrop-filter: none;
|
|
215
|
+
}
|
|
216
|
+
.markdown [data-streamdown="code-block-actions"] button {
|
|
217
|
+
padding: 0.3125rem;
|
|
218
|
+
border-radius: 0.375rem;
|
|
219
|
+
color: var(--theme-muted-text-color, #6a7282);
|
|
220
|
+
transition:
|
|
221
|
+
background-color 150ms ease-out,
|
|
222
|
+
color 150ms ease-out;
|
|
223
|
+
}
|
|
224
|
+
.markdown [data-streamdown="code-block-actions"] button:hover {
|
|
225
|
+
color: var(--theme-panel, #000);
|
|
226
|
+
background: color-mix(in oklab, var(--theme-panel, #000) 7%, transparent);
|
|
186
227
|
}
|
|
187
228
|
.markdown [data-streamdown="code-block-body"] {
|
|
188
|
-
border:
|
|
189
|
-
border-radius: 0
|
|
229
|
+
border: 0;
|
|
230
|
+
border-radius: 0;
|
|
190
231
|
padding: 0;
|
|
232
|
+
background: transparent;
|
|
191
233
|
}
|
|
192
|
-
/* Remove prose pre margin and code block body inner pre margin */
|
|
193
234
|
.markdown [data-streamdown="code-block-body"] pre {
|
|
194
235
|
margin: 0;
|
|
195
|
-
padding: 0.
|
|
236
|
+
padding: 0.125rem 1rem 0.875rem;
|
|
196
237
|
overflow-x: auto;
|
|
197
238
|
/* Code reads looser than prose; Streamdown's text-sm line is too tight. */
|
|
198
239
|
line-height: 1.6;
|
|
@@ -206,20 +247,21 @@
|
|
|
206
247
|
explicitly to ensure correct colors in all modes.
|
|
207
248
|
See: https://shiki.style/guide/dual-themes#class-based-dark-mode */
|
|
208
249
|
|
|
209
|
-
/* Light mode:
|
|
250
|
+
/* Light mode: the primary Shiki theme's colours (--sdm-c) on the block's own
|
|
251
|
+
surface, which stands in for the theme's background. */
|
|
210
252
|
.markdown [data-streamdown="code-block-body"] pre {
|
|
211
253
|
/* biome-ignore lint/complexity/noImportantStyles: the highlighter sets the background as an inline style */
|
|
212
|
-
background-color:
|
|
254
|
+
background-color: transparent !important;
|
|
213
255
|
color: var(--sdm-fg, inherit);
|
|
214
256
|
}
|
|
215
257
|
.markdown [data-streamdown="code-block-body"] pre code > span > span {
|
|
216
258
|
color: var(--sdm-c, inherit);
|
|
217
259
|
}
|
|
218
260
|
|
|
219
|
-
/* Dark mode:
|
|
261
|
+
/* Dark mode: the --shiki-dark colours, again on the block's surface. */
|
|
220
262
|
.dark .markdown [data-streamdown="code-block-body"] pre {
|
|
221
263
|
/* biome-ignore lint/complexity/noImportantStyles: the highlighter sets the background as an inline style */
|
|
222
|
-
background-color:
|
|
264
|
+
background-color: transparent !important;
|
|
223
265
|
color: var(--shiki-dark, var(--sdm-fg, inherit));
|
|
224
266
|
}
|
|
225
267
|
.dark .markdown [data-streamdown="code-block-body"] pre code > span > span {
|
|
@@ -301,7 +343,7 @@
|
|
|
301
343
|
background-image: linear-gradient(
|
|
302
344
|
90deg,
|
|
303
345
|
var(--theme-muted-text-color, #6a7282) 0%,
|
|
304
|
-
var(--theme-
|
|
346
|
+
var(--theme-accent, #06354f) 20%,
|
|
305
347
|
var(--theme-muted-text-color, #6a7282) 40%
|
|
306
348
|
);
|
|
307
349
|
-webkit-background-clip: text;
|
|
@@ -328,3 +370,137 @@
|
|
|
328
370
|
animation: none;
|
|
329
371
|
}
|
|
330
372
|
}
|
|
373
|
+
|
|
374
|
+
/* Tints of the ink for controls that sit on the panel: the theme's hover is a
|
|
375
|
+
* shade off another surface and would not read as a highlight here. */
|
|
376
|
+
@utility chat-tint {
|
|
377
|
+
background-color: color-mix(in oklab, var(--theme-panel, #000) 6%, transparent);
|
|
378
|
+
}
|
|
379
|
+
@utility chat-tint-strong {
|
|
380
|
+
background-color: color-mix(in oklab, var(--theme-panel, #000) 10%, transparent);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* The composer is one surface lifted off the page: a hairline of the ink for
|
|
384
|
+
* its edge, and a short, soft shadow that deepens while it has focus. The
|
|
385
|
+
* shadow is black on every scheme; an ink-coloured one would glow on dark. */
|
|
386
|
+
.chat-composer {
|
|
387
|
+
box-shadow:
|
|
388
|
+
0 0 0 1px color-mix(in oklab, var(--theme-panel, #000) 12%, transparent),
|
|
389
|
+
0 1px 2px rgb(0 0 0 / 0.04),
|
|
390
|
+
0 6px 16px -8px rgb(0 0 0 / 0.12);
|
|
391
|
+
transition: box-shadow 200ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
392
|
+
}
|
|
393
|
+
.chat-composer:focus-within {
|
|
394
|
+
box-shadow:
|
|
395
|
+
0 0 0 1px color-mix(in oklab, var(--theme-panel, #000) 22%, transparent),
|
|
396
|
+
0 1px 2px rgb(0 0 0 / 0.05),
|
|
397
|
+
0 10px 24px -10px rgb(0 0 0 / 0.18);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* The thread runs under the docked composer and fades out above it, so the
|
|
401
|
+
* last lines dissolve rather than cut off at the dock's edge. */
|
|
402
|
+
.chat-composer-dock::before {
|
|
403
|
+
content: "";
|
|
404
|
+
position: absolute;
|
|
405
|
+
inset-inline: 0;
|
|
406
|
+
bottom: 100%;
|
|
407
|
+
height: 1.5rem;
|
|
408
|
+
background: linear-gradient(to top, var(--theme-panel-bg, #fff), transparent);
|
|
409
|
+
pointer-events: none;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
@media (prefers-reduced-motion: reduce) {
|
|
413
|
+
.chat-composer {
|
|
414
|
+
transition: none;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* The tail of the reasoning while it streams fades in from the top, so the
|
|
419
|
+
* lines scrolling out read as more above rather than as cut off. */
|
|
420
|
+
.chat-reasoning-tail {
|
|
421
|
+
mask-image: linear-gradient(to bottom, transparent, black 1.25rem);
|
|
422
|
+
-webkit-mask-image: linear-gradient(to bottom, transparent, black 1.25rem);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* An edge drawn from the ink rather than the theme's border, so a card reads
|
|
426
|
+
* the same on the panel and on a tinted bubble. */
|
|
427
|
+
.chat-hairline {
|
|
428
|
+
box-shadow: 0 0 0 1px color-mix(in oklab, var(--theme-panel, #000) 10%, transparent);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/* A bubble carrying pastes would shrink to its shortest line and squeeze
|
|
432
|
+
* its cards and blocks into a column; give it room for them to read. */
|
|
433
|
+
.chat-bubble-roomy {
|
|
434
|
+
min-width: min(100%, 24rem);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/* ---- Accent ---------------------------------------------------------------
|
|
438
|
+
* The host's accent is the chat's signature: the send button, the caret, the
|
|
439
|
+
* focus ring, the thinking shimmer and the tint on what the reader wrote. Everything else stays ink, so the accent always means "this is the
|
|
440
|
+
* conversation's own voice or the reader's next move". */
|
|
441
|
+
.chat-thread,
|
|
442
|
+
.chat-composer,
|
|
443
|
+
.chat-empty,
|
|
444
|
+
.chat-reasoning-body {
|
|
445
|
+
--chat-accent: var(--theme-accent, var(--theme-element, #06354f));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* What the reader wrote carries a wash of the accent: theirs, not the
|
|
449
|
+
* assistant's, at a glance. */
|
|
450
|
+
.chat-bubble-user {
|
|
451
|
+
background-color: color-mix(
|
|
452
|
+
in oklab,
|
|
453
|
+
var(--theme-accent, #06354f) 9%,
|
|
454
|
+
var(--theme-panel-bg, #fff)
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* The reader's next move is the accent: the caret in the box, its ring on
|
|
459
|
+
* focus, and (in ChatInput) the filled send button. */
|
|
460
|
+
.chat-composer textarea {
|
|
461
|
+
caret-color: var(--chat-accent);
|
|
462
|
+
}
|
|
463
|
+
.chat-composer:focus-within {
|
|
464
|
+
box-shadow:
|
|
465
|
+
0 0 0 1px color-mix(in oklab, var(--chat-accent) 55%, transparent),
|
|
466
|
+
0 0 0 4px color-mix(in oklab, var(--chat-accent) 12%, transparent),
|
|
467
|
+
0 10px 24px -10px rgb(0 0 0 / 0.18);
|
|
468
|
+
}
|
|
469
|
+
@utility chat-send-idle {
|
|
470
|
+
background-color: color-mix(in oklab, var(--theme-accent, #06354f) 14%, transparent);
|
|
471
|
+
color: color-mix(in oklab, var(--theme-accent, #06354f) 70%, var(--theme-panel-bg, #fff));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/* The reply being written ends in the accent's caret. */
|
|
475
|
+
.chat-thread [style*="--streamdown-caret"] > :last-child::after {
|
|
476
|
+
color: var(--chat-accent);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/* Selected text inside the chat takes the accent too. */
|
|
480
|
+
.chat-thread ::selection,
|
|
481
|
+
.chat-composer ::selection {
|
|
482
|
+
background-color: color-mix(in oklab, var(--chat-accent) 22%, transparent);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* A thought hangs off a line of the accent rather than a gray rule. */
|
|
486
|
+
.chat-reasoning-body {
|
|
487
|
+
border-left: 1px solid color-mix(in oklab, var(--theme-accent, #06354f) 35%, transparent);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* A paste in the reader's bubble is a code block like the assistant's, set on
|
|
491
|
+
* the panel so it stands off the bubble's tint, with the bubble's spacing
|
|
492
|
+
* rather than the answer's. */
|
|
493
|
+
.chat-paste-code .markdown [data-streamdown="code-block"] {
|
|
494
|
+
margin: 0;
|
|
495
|
+
background: var(--theme-panel-bg, #fff);
|
|
496
|
+
white-space: normal;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* A queued message is written but not yet sent: its own outline, dashed,
|
|
500
|
+
* where a sent one has its fill, so it reads as pending without the text
|
|
501
|
+
* losing contrast. */
|
|
502
|
+
.chat-queued .chat-bubble-user {
|
|
503
|
+
background: transparent;
|
|
504
|
+
outline: 1px dashed color-mix(in oklab, var(--theme-panel, #000) 30%, transparent);
|
|
505
|
+
outline-offset: -1px;
|
|
506
|
+
}
|
|
@@ -40,10 +40,10 @@ function AllocationSelector({ variant = "default" } = {}) {
|
|
|
40
40
|
value: selectedAllocation ?? "",
|
|
41
41
|
onChange: (v) => setSelectedAllocation(v || null),
|
|
42
42
|
variant,
|
|
43
|
-
textBoxClassName: bare ? "rounded-
|
|
43
|
+
textBoxClassName: bare ? "rounded-full h-8 px-2.5 text-[13px] hover:chat-tint" : "h-8 rounded-lg border theme-border text-xs px-2",
|
|
44
44
|
placeholder: "Select allocation"
|
|
45
45
|
}), selected && /* @__PURE__ */ jsxs("span", {
|
|
46
|
-
className: "text-
|
|
46
|
+
className: "text-xs tabular-nums theme-muted-text whitespace-nowrap",
|
|
47
47
|
children: [
|
|
48
48
|
"$",
|
|
49
49
|
(selected.used ?? 0).toFixed(2),
|
|
@@ -25,19 +25,19 @@ function BranchNavigator({ messages, currentMessageId, onNavigate }) {
|
|
|
25
25
|
if (hasNext && next) onNavigate(next.id);
|
|
26
26
|
};
|
|
27
27
|
return /* @__PURE__ */ jsxs("div", {
|
|
28
|
-
className: "inline-flex items-center
|
|
28
|
+
className: "inline-flex items-center text-xs theme-muted-text",
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ jsx("button", {
|
|
31
31
|
type: "button",
|
|
32
32
|
onClick: handlePrev,
|
|
33
33
|
disabled: !hasPrev,
|
|
34
|
-
className: "p-
|
|
34
|
+
className: "p-1.5 rounded-md transition-colors enabled:hover:chat-tint enabled:hover:theme-text disabled:opacity-30 disabled:cursor-not-allowed",
|
|
35
35
|
title: t.previous,
|
|
36
36
|
"aria-label": t.previous,
|
|
37
|
-
children: /* @__PURE__ */ jsx(FaAngleLeft, { className: "w-3 h-3" })
|
|
37
|
+
children: /* @__PURE__ */ jsx(FaAngleLeft, { className: "w-3.5 h-3.5" })
|
|
38
38
|
}),
|
|
39
39
|
/* @__PURE__ */ jsxs("span", {
|
|
40
|
-
className: "min-w-[3ch] text-center",
|
|
40
|
+
className: "min-w-[3ch] text-center tabular-nums",
|
|
41
41
|
children: [
|
|
42
42
|
currentIndex + 1,
|
|
43
43
|
"/",
|
|
@@ -48,10 +48,10 @@ function BranchNavigator({ messages, currentMessageId, onNavigate }) {
|
|
|
48
48
|
type: "button",
|
|
49
49
|
onClick: handleNext,
|
|
50
50
|
disabled: !hasNext,
|
|
51
|
-
className: "p-
|
|
51
|
+
className: "p-1.5 rounded-md transition-colors enabled:hover:chat-tint enabled:hover:theme-text disabled:opacity-30 disabled:cursor-not-allowed",
|
|
52
52
|
title: t.next,
|
|
53
53
|
"aria-label": t.next,
|
|
54
|
-
children: /* @__PURE__ */ jsx(FaAngleRight, { className: "w-3 h-3" })
|
|
54
|
+
children: /* @__PURE__ */ jsx(FaAngleRight, { className: "w-3.5 h-3.5" })
|
|
55
55
|
})
|
|
56
56
|
]
|
|
57
57
|
});
|
|
@@ -12,7 +12,6 @@ import { ComposerControls, ConnectToolsLink } from "./ComposerChrome.js";
|
|
|
12
12
|
import DragOverlay from "./DragOverlay.js";
|
|
13
13
|
import ChatInput from "./ChatInput.js";
|
|
14
14
|
import ProviderIssueBanner from "./ProviderIssueBanner.js";
|
|
15
|
-
import cx from "classnames";
|
|
16
15
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
16
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
18
17
|
//#region src/ai/components/ChatEmptyState.tsx
|
|
@@ -71,7 +70,7 @@ function ChatEmptyState({ targetSession }) {
|
|
|
71
70
|
const { isDragging, dragHandlers } = useDragDrop({ onFilesDropped: handleFilesDropped });
|
|
72
71
|
const attachmentsAvailable = !!adapter.attachments;
|
|
73
72
|
return /* @__PURE__ */ jsx("div", {
|
|
74
|
-
className: "flex h-full bg-(--theme-panel-bg)",
|
|
73
|
+
className: "chat-empty flex h-full bg-(--theme-panel-bg)",
|
|
75
74
|
children: /* @__PURE__ */ jsxs("div", {
|
|
76
75
|
className: "flex-1 flex flex-col min-w-0",
|
|
77
76
|
children: [
|
|
@@ -110,31 +109,31 @@ function ChatEmptyState({ targetSession }) {
|
|
|
110
109
|
/* @__PURE__ */ jsxs("div", {
|
|
111
110
|
className: "flex-1 flex flex-col relative bg-(--theme-panel-bg)",
|
|
112
111
|
...attachmentsAvailable ? dragHandlers : {},
|
|
113
|
-
children: [
|
|
114
|
-
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
className: "
|
|
117
|
-
children:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
className: "text-center mb-10",
|
|
112
|
+
children: [isDragging && attachmentsAvailable && /* @__PURE__ */ jsx(DragOverlay, { className: "rounded-2xl m-4" }), /* @__PURE__ */ jsx("div", {
|
|
113
|
+
className: "flex-1 flex flex-col items-center justify-center pt-8 pb-[12vh]",
|
|
114
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
115
|
+
className: "w-full",
|
|
116
|
+
children: [
|
|
117
|
+
!(hasLoadedModels && models.length === 0) && /* @__PURE__ */ jsxs("div", {
|
|
118
|
+
className: "mx-auto mb-6 max-w-[50rem] px-8 text-center",
|
|
121
119
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
122
|
-
className:
|
|
120
|
+
className: "text-[1.75rem] leading-tight font-medium tracking-[-0.02em] text-balance text-(--theme-panel)",
|
|
123
121
|
children: greeting
|
|
124
122
|
}), /* @__PURE__ */ jsx("p", {
|
|
125
123
|
className: "mt-2 text-sm theme-muted-text",
|
|
126
124
|
children: t.modernSubtitle
|
|
127
125
|
})]
|
|
128
|
-
}),
|
|
129
|
-
|
|
126
|
+
}),
|
|
127
|
+
hasLoadedModels && models.length === 0 && /* @__PURE__ */ jsxs("div", {
|
|
128
|
+
className: "mx-auto mb-6 flex max-w-md flex-col items-center gap-3 px-8 text-center",
|
|
130
129
|
children: [
|
|
131
|
-
/* @__PURE__ */ jsx(FaCloud, { className: "h-
|
|
130
|
+
/* @__PURE__ */ jsx(FaCloud, { className: "h-10 w-10 theme-muted-text opacity-60" }),
|
|
132
131
|
/* @__PURE__ */ jsx("p", {
|
|
133
|
-
className: "text-lg theme-
|
|
132
|
+
className: "text-lg font-medium theme-text",
|
|
134
133
|
children: t.noProvidersTitle
|
|
135
134
|
}),
|
|
136
135
|
/* @__PURE__ */ jsx("p", {
|
|
137
|
-
className: "text-sm theme-muted-text
|
|
136
|
+
className: "text-sm theme-muted-text",
|
|
138
137
|
children: t.noProvidersBody
|
|
139
138
|
}),
|
|
140
139
|
extraLinks.addProvider && /* @__PURE__ */ jsxs(LinkComponent, {
|
|
@@ -142,31 +141,35 @@ function ChatEmptyState({ targetSession }) {
|
|
|
142
141
|
kind: "external",
|
|
143
142
|
href: extraLinks.addProvider
|
|
144
143
|
},
|
|
145
|
-
className: "inline-flex items-center gap-2 px-4 py-2 rounded-
|
|
144
|
+
className: "mt-1 inline-flex items-center gap-2 px-4 py-2 rounded-full transition-opacity text-sm font-medium theme-element hover:opacity-90",
|
|
146
145
|
children: [/* @__PURE__ */ jsx(FaPlus, { className: "h-3 w-3" }), t.addProvider]
|
|
147
146
|
})
|
|
148
147
|
]
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ jsx(ChatInput, {
|
|
150
|
+
ref: inputRef,
|
|
151
|
+
onSend: handleSendMessage,
|
|
152
|
+
disabled: isLoading || isLoadingModels || models.length === 0,
|
|
153
|
+
placeholder: isLoadingModels ? tInput.placeholderLoading : hasLoadedModels && models.length === 0 ? tInput.placeholderNoProviders : tInput.placeholder,
|
|
154
|
+
settingsLeft: /* @__PURE__ */ jsx(ConnectToolsLink, {}),
|
|
155
|
+
settingsRight: /* @__PURE__ */ jsxs(Fragment$1, { children: [slots.composerUsage, /* @__PURE__ */ jsx(ComposerControls, { targetSession })] })
|
|
156
|
+
}),
|
|
157
|
+
prompts.length > 0 && !(hasLoadedModels && models.length === 0) && /* @__PURE__ */ jsx("ul", {
|
|
158
|
+
className: "mx-auto max-w-[50rem] px-8",
|
|
159
|
+
children: keyedByContent(prompts, (p) => p).map(({ key, item: prompt }) => /* @__PURE__ */ jsx("li", {
|
|
160
|
+
className: "border-b theme-border last:border-b-0",
|
|
161
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
162
|
+
type: "button",
|
|
163
|
+
onClick: () => handleSuggestedPrompt(prompt),
|
|
164
|
+
disabled: isLoading || isLoadingModels || models.length === 0,
|
|
165
|
+
className: "-mx-3 my-1 block w-[calc(100%+1.5rem)] text-pretty rounded-lg px-3 py-2 text-left text-sm theme-muted-text transition-colors hover:chat-tint hover:theme-text disabled:opacity-50 disabled:cursor-not-allowed",
|
|
166
|
+
children: prompt
|
|
167
|
+
})
|
|
157
168
|
}, key))
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
}),
|
|
161
|
-
/* @__PURE__ */ jsx(ChatInput, {
|
|
162
|
-
ref: inputRef,
|
|
163
|
-
onSend: handleSendMessage,
|
|
164
|
-
disabled: isLoading || isLoadingModels || models.length === 0,
|
|
165
|
-
placeholder: isLoadingModels ? tInput.placeholderLoading : hasLoadedModels && models.length === 0 ? tInput.placeholderNoProviders : tInput.placeholder,
|
|
166
|
-
settingsLeft: /* @__PURE__ */ jsx(ConnectToolsLink, {}),
|
|
167
|
-
settingsRight: /* @__PURE__ */ jsxs(Fragment$1, { children: [slots.composerUsage, /* @__PURE__ */ jsx(ComposerControls, { targetSession })] })
|
|
169
|
+
})
|
|
170
|
+
]
|
|
168
171
|
})
|
|
169
|
-
]
|
|
172
|
+
})]
|
|
170
173
|
})
|
|
171
174
|
]
|
|
172
175
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FaArrowUp } from "../../icons/fa/FaArrowUp.js";
|
|
2
|
-
import { FaPaperclip } from "../../icons/fa/FaPaperclip.js";
|
|
3
2
|
import { FaStop } from "../../icons/fa/FaStop.js";
|
|
3
|
+
import { GoPlus } from "../../icons/go/GoPlus.js";
|
|
4
4
|
import { useChatConfig } from "../core/config.js";
|
|
5
5
|
import { useChat } from "../core/ChatProvider.js";
|
|
6
6
|
import AttachmentUpload from "./AttachmentUpload.js";
|
|
@@ -56,9 +56,11 @@ function AttachButton({ open, disabled, label, onClick }) {
|
|
|
56
56
|
type: "button",
|
|
57
57
|
onClick,
|
|
58
58
|
disabled,
|
|
59
|
-
|
|
59
|
+
"aria-expanded": open,
|
|
60
|
+
className: cx("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-colors", open ? "theme-text chat-tint-strong" : "theme-muted-text hover:theme-text hover:chat-tint", "disabled:opacity-50 disabled:cursor-not-allowed"),
|
|
60
61
|
"aria-label": label,
|
|
61
|
-
|
|
62
|
+
title: label,
|
|
63
|
+
children: /* @__PURE__ */ jsx(GoPlus, { className: cx("h-5 w-5 transition-transform duration-200", open && "rotate-45") })
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
66
|
function SendButton({ onClick, enabled, emphasised, label, testId }) {
|
|
@@ -67,7 +69,7 @@ function SendButton({ onClick, enabled, emphasised, label, testId }) {
|
|
|
67
69
|
onClick,
|
|
68
70
|
disabled: !enabled,
|
|
69
71
|
"data-testid": testId,
|
|
70
|
-
className: cx("
|
|
72
|
+
className: cx("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-[background-color,color,transform] duration-150 active:scale-95", emphasised ? "theme-element hover:opacity-90" : "chat-send-idle", !enabled && "cursor-not-allowed active:scale-100"),
|
|
71
73
|
"aria-label": label,
|
|
72
74
|
title: label,
|
|
73
75
|
children: /* @__PURE__ */ jsx(FaArrowUp, { className: "h-4 w-4" })
|
|
@@ -198,22 +200,28 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
198
200
|
if (pastes && handleTextPaste(e.clipboardData.getData("text/plain"))) e.preventDefault();
|
|
199
201
|
};
|
|
200
202
|
const { isDragging, dragHandlers } = useDragDrop({ onFilesDropped: handleFilesDropped });
|
|
203
|
+
const toolbar = attachmentsAvailable || !flush && !!settingsRight;
|
|
204
|
+
const action = isStreaming && !input.trim() ? /* @__PURE__ */ jsx("button", {
|
|
205
|
+
type: "button",
|
|
206
|
+
onClick: stopStreaming,
|
|
207
|
+
disabled: turn?.stopping,
|
|
208
|
+
className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-(--theme-panel) text-(--theme-panel-bg) transition-opacity hover:opacity-85 disabled:opacity-50",
|
|
209
|
+
"aria-label": t.stopGenerating,
|
|
210
|
+
title: t.stopGenerating,
|
|
211
|
+
children: /* @__PURE__ */ jsx(FaStop, { className: "h-3 w-3" })
|
|
212
|
+
}) : /* @__PURE__ */ jsx(SendButton, {
|
|
213
|
+
onClick: handleSubmit,
|
|
214
|
+
enabled: canSend,
|
|
215
|
+
emphasised,
|
|
216
|
+
label: sendLabel ?? t.sendMessage,
|
|
217
|
+
testId: sendTestId
|
|
218
|
+
});
|
|
201
219
|
return /* @__PURE__ */ jsxs("div", {
|
|
202
|
-
className: cx("relative", !flush && "px-4 pb-
|
|
220
|
+
className: cx("relative", !flush && "chat-composer-dock px-4 pb-5 pt-2 bg-(--theme-panel-bg)"),
|
|
203
221
|
...attachmentsAvailable ? dragHandlers : {},
|
|
204
222
|
children: [isDragging && /* @__PURE__ */ jsx(DragOverlay, { className: "rounded-2xl" }), /* @__PURE__ */ jsxs("div", {
|
|
205
223
|
className: cx(!flush && "w-full max-w-[50rem] mx-auto px-4"),
|
|
206
224
|
children: [
|
|
207
|
-
showAttachments && attachmentsAvailable && /* @__PURE__ */ jsx("div", {
|
|
208
|
-
className: "mb-3 p-3 rounded-2xl border theme-border shadow-sm bg-(--theme-panel-bg)",
|
|
209
|
-
children: /* @__PURE__ */ jsx(AttachmentUpload, {
|
|
210
|
-
ref: attachmentUploadRef,
|
|
211
|
-
conversationId,
|
|
212
|
-
attachments,
|
|
213
|
-
onAttachmentsChange: setAttachments,
|
|
214
|
-
maxFiles: 10
|
|
215
|
-
})
|
|
216
|
-
}),
|
|
217
225
|
context && /* @__PURE__ */ jsx(ComposerContext, { children: context }),
|
|
218
226
|
cards.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
219
227
|
className: "mb-2 flex flex-wrap gap-2",
|
|
@@ -238,56 +246,55 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
238
246
|
textareaRef.current?.focus();
|
|
239
247
|
}
|
|
240
248
|
}), /* @__PURE__ */ jsxs("div", {
|
|
241
|
-
className:
|
|
242
|
-
children: [
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
disabled:
|
|
268
|
-
className: cx("p-2.5 rounded-xl", "theme-muted-panel", "hover:theme-hover", "transition-colors"),
|
|
269
|
-
"aria-label": t.stopGenerating,
|
|
270
|
-
title: t.stopGenerating,
|
|
271
|
-
children: /* @__PURE__ */ jsx(FaStop, { className: "h-4 w-4" })
|
|
272
|
-
}) : /* @__PURE__ */ jsx(SendButton, {
|
|
273
|
-
onClick: handleSubmit,
|
|
274
|
-
enabled: canSend,
|
|
275
|
-
emphasised,
|
|
276
|
-
label: sendLabel ?? t.sendMessage,
|
|
277
|
-
testId: sendTestId
|
|
249
|
+
className: "chat-composer flex flex-col rounded-[1.25rem] bg-(--theme-panel-bg)",
|
|
250
|
+
children: [
|
|
251
|
+
showAttachments && attachmentsAvailable && /* @__PURE__ */ jsx("div", {
|
|
252
|
+
className: "px-3 pt-3",
|
|
253
|
+
children: /* @__PURE__ */ jsx(AttachmentUpload, {
|
|
254
|
+
ref: attachmentUploadRef,
|
|
255
|
+
conversationId,
|
|
256
|
+
attachments,
|
|
257
|
+
onAttachmentsChange: setAttachments,
|
|
258
|
+
maxFiles: 10
|
|
259
|
+
})
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ jsxs("div", {
|
|
262
|
+
className: cx(!toolbar && "flex items-end gap-2 pr-2 pb-2"),
|
|
263
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
264
|
+
className: "max-h-[200px] min-w-0 flex-1 overflow-y-auto",
|
|
265
|
+
children: /* @__PURE__ */ jsx("textarea", {
|
|
266
|
+
ref: textareaRef,
|
|
267
|
+
value: input,
|
|
268
|
+
onChange: (e) => setInputAndPersist(e.target.value),
|
|
269
|
+
onKeyDown: handleKeyDown,
|
|
270
|
+
onPaste: handlePaste,
|
|
271
|
+
placeholder: effectivePlaceholder,
|
|
272
|
+
"aria-label": inputLabel ?? effectivePlaceholder,
|
|
273
|
+
disabled,
|
|
274
|
+
rows: 1,
|
|
275
|
+
className: cx("theme-text block w-full resize-none overflow-hidden", "bg-transparent border-0 px-4", toolbar ? "pt-3.5 pb-1" : "pt-3 pb-1", "placeholder:theme-muted-text", "focus:outline-none focus:ring-0", "disabled:opacity-50 disabled:cursor-not-allowed", "text-[1rem] leading-relaxed")
|
|
278
276
|
})
|
|
277
|
+
}), !toolbar && action]
|
|
278
|
+
}),
|
|
279
|
+
toolbar && /* @__PURE__ */ jsxs("div", {
|
|
280
|
+
className: "flex items-center gap-1 px-2 pb-2",
|
|
281
|
+
children: [attachmentsAvailable && /* @__PURE__ */ jsx(AttachButton, {
|
|
282
|
+
open: showAttachments,
|
|
283
|
+
disabled,
|
|
284
|
+
label: t.attachFiles,
|
|
285
|
+
onClick: () => setShowAttachments(!showAttachments)
|
|
286
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
287
|
+
className: "ml-auto flex min-w-0 items-center gap-1",
|
|
288
|
+
children: [!flush && settingsRight, action]
|
|
279
289
|
})]
|
|
280
290
|
})
|
|
281
|
-
|
|
291
|
+
]
|
|
282
292
|
})]
|
|
283
293
|
}),
|
|
284
|
-
!flush && /* @__PURE__ */ jsx(ComposerSettings, {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
})] }),
|
|
289
|
-
children: settingsRight
|
|
290
|
-
})
|
|
294
|
+
!flush && (settingsLeft || uploadedCount > 0) && /* @__PURE__ */ jsx(ComposerSettings, { left: /* @__PURE__ */ jsxs(Fragment$1, { children: [settingsLeft, uploadedCount > 0 && /* @__PURE__ */ jsx("span", {
|
|
295
|
+
className: "text-[11px] theme-muted-text",
|
|
296
|
+
children: t.filesAttached(uploadedCount)
|
|
297
|
+
})] }) })
|
|
291
298
|
]
|
|
292
299
|
})]
|
|
293
300
|
});
|