@schlenkr/quassel 0.5.6 → 0.7.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/ChatInputToolbar.d.ts +6 -10
- package/ComposerPrimaryAction.d.ts +13 -0
- package/QuasselProvider.d.ts +1 -0
- package/README.md +44 -18
- package/RecordingAura.d.ts +4 -0
- package/chat.css +312 -212
- package/index.d.ts +1 -1
- package/index.js +430 -174
- package/index.js.map +4 -4
- package/options.d.ts +12 -4
- package/package.json +1 -1
- package/texts.d.ts +5 -0
package/index.js
CHANGED
|
@@ -42,6 +42,11 @@ var englishTexts = {
|
|
|
42
42
|
send: "Send",
|
|
43
43
|
sendIntoRun: "Feed into the running turn",
|
|
44
44
|
stop: "Stop work",
|
|
45
|
+
microphone: "Speak",
|
|
46
|
+
microphoneHint: "Hold to speak or click to start recording",
|
|
47
|
+
microphonePreparing: "Connecting microphone ...",
|
|
48
|
+
microphoneRecording: "Finish recording",
|
|
49
|
+
microphoneTranscribing: "Transcribing ...",
|
|
45
50
|
placeholder: "Write a message ...",
|
|
46
51
|
steeringPlaceholder: "Interject ...",
|
|
47
52
|
steered: "Fed into the running turn",
|
|
@@ -112,6 +117,11 @@ var germanTexts = {
|
|
|
112
117
|
send: "Senden",
|
|
113
118
|
sendIntoRun: "In die laufende Antwort einreihen",
|
|
114
119
|
stop: "Bearbeitung stoppen",
|
|
120
|
+
microphone: "Sprechen",
|
|
121
|
+
microphoneHint: "Zum Sprechen halten oder zum Aufnehmen antippen",
|
|
122
|
+
microphonePreparing: "Mikrofon wird verbunden ...",
|
|
123
|
+
microphoneRecording: "Aufnahme beenden",
|
|
124
|
+
microphoneTranscribing: "Wird transkribiert ...",
|
|
115
125
|
placeholder: "Nachricht schreiben ...",
|
|
116
126
|
steeringPlaceholder: "Nachsteuern ...",
|
|
117
127
|
steered: "In die laufende Antwort eingereiht",
|
|
@@ -164,7 +174,7 @@ var defaultTexts = englishTexts;
|
|
|
164
174
|
|
|
165
175
|
// packages/quassel/src/ui/cn.ts
|
|
166
176
|
import { createCn } from "cn/config";
|
|
167
|
-
var cn = createCn({ prefix: "qsl", extend: { theme: { text: ["
|
|
177
|
+
var cn = createCn({ prefix: "qsl", extend: { theme: { text: ["body", "small"] } } });
|
|
168
178
|
|
|
169
179
|
// packages/quassel/src/ChatMessages.tsx
|
|
170
180
|
import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
|
|
@@ -236,7 +246,7 @@ import { Button as ButtonPrimitive } from "@base-ui/react/button";
|
|
|
236
246
|
import { cva } from "class-variance-authority";
|
|
237
247
|
import { jsx } from "react/jsx-runtime";
|
|
238
248
|
var buttonVariants = cva(
|
|
239
|
-
"qsl:group/button qsl:inline-flex qsl:shrink-0 qsl:items-center qsl:justify-center qsl:rounded-lg qsl:border qsl:border-transparent qsl:bg-clip-padding qsl:text-
|
|
249
|
+
"qsl:group/button qsl:inline-flex qsl:shrink-0 qsl:items-center qsl:justify-center qsl:rounded-lg qsl:border qsl:border-transparent qsl:bg-clip-padding qsl:text-body qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:select-none qsl:focus-visible:border-ring qsl:focus-visible:ring-3 qsl:focus-visible:ring-ring/50 qsl:active:not-aria-[haspopup]:translate-y-px qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-3 qsl:aria-invalid:ring-destructive/20 qsl:dark:aria-invalid:border-destructive/50 qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
|
|
240
250
|
{
|
|
241
251
|
variants: {
|
|
242
252
|
variant: {
|
|
@@ -249,7 +259,7 @@ var buttonVariants = cva(
|
|
|
249
259
|
},
|
|
250
260
|
size: {
|
|
251
261
|
default: "qsl:h-8 qsl:gap-1.5 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2",
|
|
252
|
-
xs: "qsl:h-6 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),10px)] qsl:px-2 qsl:
|
|
262
|
+
xs: "qsl:h-6 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),10px)] qsl:px-2 qsl:in-data-[slot=button-group]:rounded-lg qsl:has-data-[icon=inline-end]:pr-1.5 qsl:has-data-[icon=inline-start]:pl-1.5 qsl:[&_svg:not([class*='size-'])]:size-3",
|
|
253
263
|
sm: "qsl:h-7 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),12px)] qsl:px-2.5 qsl:in-data-[slot=button-group]:rounded-lg qsl:has-data-[icon=inline-end]:pr-1.5 qsl:has-data-[icon=inline-start]:pl-1.5 qsl:[&_svg:not([class*='size-'])]:size-3.5",
|
|
254
264
|
lg: "qsl:h-9 qsl:gap-1.5 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2",
|
|
255
265
|
icon: "qsl:size-8",
|
|
@@ -295,7 +305,7 @@ function Card({
|
|
|
295
305
|
"data-slot": "card",
|
|
296
306
|
"data-size": size,
|
|
297
307
|
className: cn(
|
|
298
|
-
"qsl:group/card qsl:flex qsl:flex-col qsl:gap-(--qsl-card-spacing) qsl:overflow-hidden qsl:rounded-panel qsl:border qsl:border-border qsl:bg-card qsl:py-(--qsl-card-spacing) qsl:text-
|
|
308
|
+
"qsl:group/card qsl:flex qsl:flex-col qsl:gap-(--qsl-card-spacing) qsl:overflow-hidden qsl:rounded-panel qsl:border qsl:border-border qsl:bg-card qsl:py-(--qsl-card-spacing) qsl:text-body qsl:text-card-foreground qsl:shadow-bar qsl:[--qsl-card-spacing:--spacing(4)] qsl:has-data-[slot=card-footer]:pb-0 qsl:has-[>img:first-child]:pt-0 qsl:data-[size=sm]:[--qsl-card-spacing:--spacing(3)] qsl:data-[size=sm]:has-data-[slot=card-footer]:pb-0 qsl:*:[img:first-child]:rounded-t-xl qsl:*:[img:last-child]:rounded-b-xl",
|
|
299
309
|
className
|
|
300
310
|
),
|
|
301
311
|
...props
|
|
@@ -324,6 +334,7 @@ function PopoverContent({
|
|
|
324
334
|
return /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { container: portalContainer, keepMounted, children: /* @__PURE__ */ jsx3(
|
|
325
335
|
PopoverPrimitive.Positioner,
|
|
326
336
|
{
|
|
337
|
+
"data-quassel": "",
|
|
327
338
|
align,
|
|
328
339
|
alignOffset,
|
|
329
340
|
anchor,
|
|
@@ -338,7 +349,7 @@ function PopoverContent({
|
|
|
338
349
|
"data-quassel-popover": "",
|
|
339
350
|
"data-slot": "popover-content",
|
|
340
351
|
className: cn(
|
|
341
|
-
"qsl:z-[110] qsl:flex qsl:w-72 qsl:origin-(--transform-origin) qsl:flex-col qsl:gap-2.5 qsl:rounded-lg qsl:bg-popover qsl:p-2.5 qsl:text-
|
|
352
|
+
"qsl:z-[110] qsl:flex qsl:w-72 qsl:origin-(--transform-origin) qsl:flex-col qsl:gap-2.5 qsl:rounded-lg qsl:bg-popover qsl:p-2.5 qsl:text-small qsl:text-popover-foreground qsl:shadow-md qsl:ring-1 qsl:ring-foreground/10 qsl:outline-hidden qsl:duration-100 qsl:data-[side=bottom]:slide-in-from-top-2 qsl:data-[side=inline-end]:slide-in-from-left-2 qsl:data-[side=inline-start]:slide-in-from-right-2 qsl:data-[side=left]:slide-in-from-right-2 qsl:data-[side=right]:slide-in-from-left-2 qsl:data-[side=top]:slide-in-from-bottom-2 qsl:data-open:animate-in qsl:data-open:fade-in-0 qsl:data-open:zoom-in-95 qsl:data-closed:animate-out qsl:data-closed:fade-out-0 qsl:data-closed:zoom-out-95",
|
|
342
353
|
className
|
|
343
354
|
),
|
|
344
355
|
...props
|
|
@@ -373,7 +384,7 @@ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
|
373
384
|
import { cva as cva2 } from "class-variance-authority";
|
|
374
385
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
375
386
|
var toggleVariants = cva2(
|
|
376
|
-
"qsl:group/toggle qsl:inline-flex qsl:items-center qsl:justify-center qsl:gap-1 qsl:rounded-lg qsl:text-
|
|
387
|
+
"qsl:group/toggle qsl:inline-flex qsl:items-center qsl:justify-center qsl:gap-1 qsl:rounded-lg qsl:text-body qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:hover:bg-muted qsl:hover:text-foreground qsl:focus-visible:border-ring qsl:focus-visible:ring-[3px] qsl:focus-visible:ring-ring/50 qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-destructive/20 qsl:aria-pressed:bg-muted qsl:data-[state=on]:bg-muted qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
|
|
377
388
|
{
|
|
378
389
|
variants: {
|
|
379
390
|
variant: {
|
|
@@ -493,7 +504,7 @@ function CodeBlock({ children }) {
|
|
|
493
504
|
{
|
|
494
505
|
ref: code,
|
|
495
506
|
"data-chat": "code-block",
|
|
496
|
-
className: cn(scrollbar, "qsl:
|
|
507
|
+
className: cn(scrollbar, "qsl:overflow-auto qsl:overscroll-contain"),
|
|
497
508
|
style: { maxHeight: options?.maxHeight, whiteSpace: options?.wrap ? "pre-wrap" : void 0, overflowWrap: options?.wrap ? "anywhere" : void 0 },
|
|
498
509
|
children
|
|
499
510
|
}
|
|
@@ -516,7 +527,7 @@ function CodeBlock({ children }) {
|
|
|
516
527
|
children: action.status === "done" ? /* @__PURE__ */ jsx8(CheckIcon, {}) : /* @__PURE__ */ jsx8(CopyIcon, {})
|
|
517
528
|
}
|
|
518
529
|
),
|
|
519
|
-
action.error && /* @__PURE__ */ jsx8("p", { className: "qsl:text-
|
|
530
|
+
action.error && /* @__PURE__ */ jsx8("p", { className: "qsl:text-small qsl:text-destructive", role: "alert", children: action.error })
|
|
520
531
|
] });
|
|
521
532
|
}
|
|
522
533
|
function MarkdownLinks({ children, onLinkClick }) {
|
|
@@ -530,7 +541,6 @@ function MarkdownLink({ href, children }) {
|
|
|
530
541
|
return /* @__PURE__ */ jsx8(
|
|
531
542
|
"a",
|
|
532
543
|
{
|
|
533
|
-
className: "qsl:text-primary qsl:[text-underline-offset:2px] qsl:in-data-[tone=on-color]:text-inherit qsl:in-data-[tone=on-color]:underline",
|
|
534
544
|
href,
|
|
535
545
|
onClick: (event) => {
|
|
536
546
|
if (href && onLinkClick?.(href, event.currentTarget.textContent ?? "")) {
|
|
@@ -545,34 +555,32 @@ function MarkdownLink({ href, children }) {
|
|
|
545
555
|
}
|
|
546
556
|
var scrollbar = "qsl:[scrollbar-width:thin] qsl:[&::-webkit-scrollbar]:block qsl:[&::-webkit-scrollbar]:h-2 qsl:[&::-webkit-scrollbar-thumb]:rounded-full qsl:[&::-webkit-scrollbar-thumb]:bg-border";
|
|
547
557
|
var scrollCover = "qsl:bg-[linear-gradient(to_right,var(--qsl-scroll-cover,var(--qsl-background))_50%,transparent)_left/20px_100%_no-repeat_local,linear-gradient(to_left,var(--qsl-scroll-cover,var(--qsl-background))_50%,transparent)_right/20px_100%_no-repeat_local,linear-gradient(to_right,#00000047,transparent)_left/14px_100%_no-repeat_scroll,linear-gradient(to_left,#00000047,transparent)_right/14px_100%_no-repeat_scroll]";
|
|
548
|
-
var headingClasses = "qsl:mt-3 qsl:mb-1 qsl:text-[length:1.1em] qsl:font-medium";
|
|
549
|
-
var cellClasses = "qsl:max-w-[44ch] qsl:border qsl:border-border qsl:px-2 qsl:py-1 qsl:text-left qsl:align-top qsl:in-data-[tone=on-color]:border-white/35";
|
|
550
558
|
var components = {
|
|
551
|
-
h1: ({ children }) => /* @__PURE__ */ jsx8("h1", {
|
|
552
|
-
h2: ({ children }) => /* @__PURE__ */ jsx8("h2", {
|
|
553
|
-
h3: ({ children }) => /* @__PURE__ */ jsx8("h3", {
|
|
554
|
-
h4: ({ children }) => /* @__PURE__ */ jsx8("h4", {
|
|
555
|
-
h5: ({ children }) => /* @__PURE__ */ jsx8("h5", {
|
|
556
|
-
h6: ({ children }) => /* @__PURE__ */ jsx8("h6", {
|
|
557
|
-
p: ({ children }) => /* @__PURE__ */ jsx8("p", {
|
|
558
|
-
ul: ({ children }) => /* @__PURE__ */ jsx8("ul", {
|
|
559
|
-
ol: ({ children }) => /* @__PURE__ */ jsx8("ol", {
|
|
560
|
-
li: ({ children }) => /* @__PURE__ */ jsx8("li", {
|
|
561
|
-
hr: () => /* @__PURE__ */ jsx8("hr", {
|
|
559
|
+
h1: ({ children }) => /* @__PURE__ */ jsx8("h1", { children }),
|
|
560
|
+
h2: ({ children }) => /* @__PURE__ */ jsx8("h2", { children }),
|
|
561
|
+
h3: ({ children }) => /* @__PURE__ */ jsx8("h3", { children }),
|
|
562
|
+
h4: ({ children }) => /* @__PURE__ */ jsx8("h4", { children }),
|
|
563
|
+
h5: ({ children }) => /* @__PURE__ */ jsx8("h5", { children }),
|
|
564
|
+
h6: ({ children }) => /* @__PURE__ */ jsx8("h6", { children }),
|
|
565
|
+
p: ({ children }) => /* @__PURE__ */ jsx8("p", { children }),
|
|
566
|
+
ul: ({ children }) => /* @__PURE__ */ jsx8("ul", { children }),
|
|
567
|
+
ol: ({ children }) => /* @__PURE__ */ jsx8("ol", { children }),
|
|
568
|
+
li: ({ children }) => /* @__PURE__ */ jsx8("li", { children }),
|
|
569
|
+
hr: () => /* @__PURE__ */ jsx8("hr", {}),
|
|
562
570
|
img: ({ src, alt }) => /* @__PURE__ */ jsx8("img", { alt, className: "qsl:h-auto qsl:max-w-full", src: typeof src === "string" ? src : void 0 }),
|
|
563
|
-
blockquote: ({ children }) => /* @__PURE__ */ jsx8("blockquote", {
|
|
564
|
-
strong: ({ children }) => /* @__PURE__ */ jsx8("strong", {
|
|
571
|
+
blockquote: ({ children }) => /* @__PURE__ */ jsx8("blockquote", { children }),
|
|
572
|
+
strong: ({ children }) => /* @__PURE__ */ jsx8("strong", { children }),
|
|
565
573
|
em: ({ children }) => /* @__PURE__ */ jsx8("em", { children }),
|
|
566
574
|
a: ({ href, children }) => /* @__PURE__ */ jsx8(MarkdownLink, { href, children }),
|
|
567
575
|
pre: ({ children }) => /* @__PURE__ */ jsx8(CodeBlock, { children }),
|
|
568
|
-
code: ({ children, className }) => /* @__PURE__ */ jsx8("code", { className
|
|
576
|
+
code: ({ children, className }) => /* @__PURE__ */ jsx8("code", { className, children }),
|
|
569
577
|
// Without max-content the table shrinks to the container and stacks letters.
|
|
570
|
-
table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: cn(scrollbar, scrollCover, "qsl:
|
|
578
|
+
table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: cn(scrollbar, scrollCover, "qsl:overflow-x-auto qsl:overscroll-x-contain"), "data-quassel-table": "", children: /* @__PURE__ */ jsx8("table", { className: "qsl:w-max qsl:min-w-full qsl:border-collapse", children }) }),
|
|
571
579
|
thead: ({ children }) => /* @__PURE__ */ jsx8("thead", { children }),
|
|
572
580
|
tbody: ({ children }) => /* @__PURE__ */ jsx8("tbody", { children }),
|
|
573
581
|
tr: ({ children }) => /* @__PURE__ */ jsx8("tr", { children }),
|
|
574
|
-
th: ({ children }) => /* @__PURE__ */ jsx8("th", {
|
|
575
|
-
td: ({ children }) => /* @__PURE__ */ jsx8("td", {
|
|
582
|
+
th: ({ children }) => /* @__PURE__ */ jsx8("th", { children }),
|
|
583
|
+
td: ({ children }) => /* @__PURE__ */ jsx8("td", { children })
|
|
576
584
|
};
|
|
577
585
|
function transformUrl(url, allowUrl, resolveUrl) {
|
|
578
586
|
const resolved = resolveUrl ? resolveUrl(url) : url;
|
|
@@ -584,10 +592,9 @@ function Markdown({ text, streaming = false }) {
|
|
|
584
592
|
const allowUrl = useAllowUrl();
|
|
585
593
|
const resolveUrl = useResolveUrl();
|
|
586
594
|
const urlTransform = useCallback((url) => transformUrl(url, allowUrl, resolveUrl), [allowUrl, resolveUrl]);
|
|
587
|
-
return /* @__PURE__ */ jsx8(
|
|
595
|
+
return /* @__PURE__ */ jsx8("div", { "data-quassel": "", "data-quassel-markdown": "", children: /* @__PURE__ */ jsx8(
|
|
588
596
|
Streamdown,
|
|
589
597
|
{
|
|
590
|
-
className: "space-y-0 text-inherit",
|
|
591
598
|
prefix: "qsl",
|
|
592
599
|
mode: streaming ? "streaming" : "static",
|
|
593
600
|
isAnimating: streaming,
|
|
@@ -599,7 +606,7 @@ function Markdown({ text, streaming = false }) {
|
|
|
599
606
|
skipHtml: true,
|
|
600
607
|
children: text
|
|
601
608
|
}
|
|
602
|
-
);
|
|
609
|
+
) });
|
|
603
610
|
}
|
|
604
611
|
function markdownPlainText(text) {
|
|
605
612
|
return text.split("\n").filter((line) => !/^\s*```\w*\s*$/.test(line) && !isTableDivider(line)).map((line) => (line.trim().startsWith("|") ? splitTableRow(line).join(", ") : line).replace(/^(#{1,6})\s+/, "").replace(/^\s*>\s?/, "").replace(/^\s*([-*+]|\d+[.)])\s+/, "").replace(/!?\[([^\]]*)\]\(([^)]+)\)|\*\*([^*]+)\*\*|__([^_]+)__|\*([^*]+)\*|`([^`]+)`/g, (_, link, _href, bold, boldUnderscore, italic, code) => link ?? bold ?? boldUnderscore ?? italic ?? code).trim()).filter((line) => line !== "").join("\n");
|
|
@@ -627,7 +634,7 @@ var stepPopoverOrigin = (event) => ({
|
|
|
627
634
|
y: event.clientY,
|
|
628
635
|
base: getComputedStyle(event.currentTarget).getPropertyValue("--qsl-base")
|
|
629
636
|
});
|
|
630
|
-
var preClasses = "qsl:rounded-lg qsl:bg-secondary qsl:p-3 qsl:font-mono qsl:text-
|
|
637
|
+
var preClasses = "qsl:rounded-lg qsl:bg-secondary qsl:p-3 qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap";
|
|
631
638
|
function StepPopover({
|
|
632
639
|
message,
|
|
633
640
|
position,
|
|
@@ -658,7 +665,7 @@ function StepPopover({
|
|
|
658
665
|
anchor,
|
|
659
666
|
"aria-label": title,
|
|
660
667
|
className: cn(
|
|
661
|
-
"qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-
|
|
668
|
+
"qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-body qsl:shadow-pop",
|
|
662
669
|
"qsl:max-h-[min(70dvh,620px,var(--available-height))]"
|
|
663
670
|
),
|
|
664
671
|
collisionPadding: 16,
|
|
@@ -672,10 +679,10 @@ function StepPopover({
|
|
|
672
679
|
/* @__PURE__ */ jsx9("span", { className: "qsl:min-w-0 qsl:flex-1 qsl:overflow-hidden qsl:text-ellipsis qsl:whitespace-nowrap qsl:font-medium", children: title }),
|
|
673
680
|
/* @__PURE__ */ jsx9(Button2, { "aria-label": texts.close, className: "qsl:flex-none", onClick: onClose, size: "icon-sm", title: texts.close, variant: "ghost", children: /* @__PURE__ */ jsx9(XIcon, {}) })
|
|
674
681
|
] }),
|
|
675
|
-
/* @__PURE__ */ jsx9("div", { className: "qsl:min-h-0 qsl:flex-1 qsl:overflow-auto qsl:overscroll-contain qsl:p-4", children: thinking ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-
|
|
676
|
-
/* @__PURE__ */ jsx9("div", { className: "qsl:font-mono qsl:text-
|
|
682
|
+
/* @__PURE__ */ jsx9("div", { className: "qsl:min-h-0 qsl:flex-1 qsl:overflow-auto qsl:overscroll-contain qsl:p-4", children: thinking ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-small qsl:whitespace-pre-wrap", children: message.text }) : tool ? /* @__PURE__ */ jsxs2("div", { className: "qsl:flex qsl:flex-col qsl:gap-4", children: [
|
|
683
|
+
/* @__PURE__ */ jsx9("div", { className: "qsl:font-mono qsl:text-small", children: message.text }),
|
|
677
684
|
/* @__PURE__ */ jsx9(PopoverSection, { label: texts.argumentsLabel, value: toolArgumentsText(tool) }),
|
|
678
|
-
tool.result === void 0 ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-
|
|
685
|
+
tool.result === void 0 ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-small qsl:text-muted-foreground", children: texts.toolStillRunning }) : /* @__PURE__ */ jsx9(PopoverSection, { error: tool.isError, label: texts.resultLabel, value: prettyJson(tool.result) })
|
|
679
686
|
] }) : null })
|
|
680
687
|
]
|
|
681
688
|
}
|
|
@@ -683,7 +690,7 @@ function StepPopover({
|
|
|
683
690
|
}
|
|
684
691
|
function PopoverSection({ label, value, error = false }) {
|
|
685
692
|
return /* @__PURE__ */ jsxs2("section", { children: [
|
|
686
|
-
/* @__PURE__ */ jsx9("h3", { className: "qsl:mb-1.5 qsl:text-
|
|
693
|
+
/* @__PURE__ */ jsx9("h3", { className: "qsl:mb-1.5 qsl:text-small qsl:font-semibold qsl:tracking-[0.04em] qsl:text-muted-foreground qsl:uppercase", children: label }),
|
|
687
694
|
/* @__PURE__ */ jsx9("pre", { className: cn(preClasses, error && "qsl:text-destructive"), children: value })
|
|
688
695
|
] });
|
|
689
696
|
}
|
|
@@ -691,7 +698,7 @@ function PopoverSection({ label, value, error = false }) {
|
|
|
691
698
|
// packages/quassel/src/PendingActionCard.tsx
|
|
692
699
|
import { CheckIcon as CheckIcon2, XIcon as XIcon2 } from "lucide-react";
|
|
693
700
|
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
694
|
-
var cardClasses = "qsl:gap-2.5 qsl:bg-background qsl:px-3.5 qsl:text-
|
|
701
|
+
var cardClasses = "qsl:gap-2.5 qsl:bg-background qsl:px-3.5 qsl:text-body";
|
|
695
702
|
var resultText = (result) => typeof result === "string" ? result : result === null || result === void 0 ? "" : JSON.stringify(result);
|
|
696
703
|
function PendingActionCard({
|
|
697
704
|
text,
|
|
@@ -704,17 +711,17 @@ function PendingActionCard({
|
|
|
704
711
|
const { Button: Button2, Card: Card2 } = useQuasselComponents();
|
|
705
712
|
if (action.status !== void 0) {
|
|
706
713
|
return /* @__PURE__ */ jsxs3(Card2, { className: cardClasses, size: "sm", children: [
|
|
707
|
-
/* @__PURE__ */ jsx10("div", { className: "qsl:
|
|
708
|
-
/* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:gap-1.5 qsl:text-
|
|
714
|
+
/* @__PURE__ */ jsx10("div", { className: "qsl:text-body", children: text }),
|
|
715
|
+
/* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:gap-1.5 qsl:text-body qsl:text-muted-foreground", "data-action": "resolved", children: [
|
|
709
716
|
action.status === "approved" ? /* @__PURE__ */ jsx10(CheckIcon2, { className: "qsl:text-success", size: 12 }) : /* @__PURE__ */ jsx10(XIcon2, { size: 12 }),
|
|
710
717
|
action.status === "approved" ? resultText(action.result) : dismissedLabel
|
|
711
718
|
] })
|
|
712
719
|
] });
|
|
713
720
|
}
|
|
714
721
|
return /* @__PURE__ */ jsxs3(Card2, { className: cardClasses, size: "sm", children: [
|
|
715
|
-
/* @__PURE__ */ jsx10("div", { className: "qsl:
|
|
722
|
+
/* @__PURE__ */ jsx10("div", { className: "qsl:text-body", children: text }),
|
|
716
723
|
/* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:justify-between qsl:gap-2", children: [
|
|
717
|
-
/* @__PURE__ */ jsx10("span", { className: "qsl:text-
|
|
724
|
+
/* @__PURE__ */ jsx10("span", { className: "qsl:text-small qsl:text-muted-foreground", "data-action": "waiting", children: waitingLabel }),
|
|
718
725
|
onDismiss && /* @__PURE__ */ jsx10(Button2, { onClick: onDismiss, size: "sm", variant: "outline", children: dismissLabel })
|
|
719
726
|
] })
|
|
720
727
|
] });
|
|
@@ -903,7 +910,7 @@ function WorkingScenes({ label = "Working ...", compact = false }) {
|
|
|
903
910
|
return () => window.clearInterval(timer);
|
|
904
911
|
}, [reducedMotion]);
|
|
905
912
|
const frame = scene.draw(Math.floor(frameTick / scene.tick) + (scene.moving ? offset : 0));
|
|
906
|
-
return /* @__PURE__ */ jsxs4("span", { "aria-label": label, className: cn("qsl:flex qsl:items-center qsl:gap-2.5 qsl:text-
|
|
913
|
+
return /* @__PURE__ */ jsxs4("span", { "aria-label": label, className: cn("qsl:flex qsl:items-center qsl:gap-2.5 qsl:text-body", compact ? "qsl:text-inherit" : "qsl:mt-4 qsl:text-foreground"), "data-chat": "working", role: "status", children: [
|
|
907
914
|
!compact && /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", className: "qsl:text-muted-foreground qsl:opacity-70", children: ">" }),
|
|
908
915
|
/* @__PURE__ */ jsx11("span", { "aria-hidden": "true", className: cn("qsl:inline-block qsl:flex-none qsl:font-mono qsl:[font-variant-ligatures:none]", compact ? "qsl:w-[2.4em] qsl:text-center" : "qsl:w-[15rem]"), children: /* @__PURE__ */ jsx11("span", { className: "qsl:tracking-[0.02em] qsl:whitespace-pre qsl:motion-reduce:opacity-60", children: typeof frame === "string" ? frame : frame.map((cell, index) => /* @__PURE__ */ jsx11("span", { className: "qsl:inline-block qsl:w-[1.35em] qsl:text-center", children: cell }, index)) }) }, scene.id)
|
|
909
916
|
] });
|
|
@@ -957,12 +964,8 @@ import { CheckIcon as CheckIcon4, ChevronDownIcon, ChevronRightIcon, ChevronUpIc
|
|
|
957
964
|
// packages/quassel/src/options.ts
|
|
958
965
|
var cssLength = (value) => typeof value === "number" ? `${value}px` : value;
|
|
959
966
|
var appearanceStyle = (appearance) => ({
|
|
960
|
-
"--qsl-font-size": cssLength(appearance?.fontSize),
|
|
961
|
-
"--qsl-chat-font-size": cssLength(appearance?.fontSize),
|
|
962
|
-
"--qsl-chat-line-height": appearance?.lineHeight,
|
|
963
967
|
"--qsl-chat-message-gap": cssLength(appearance?.messageGap),
|
|
964
968
|
"--qsl-chat-dense-message-gap": cssLength(appearance?.denseMessageGap),
|
|
965
|
-
"--qsl-tool-font-scale": appearance?.toolFontScale,
|
|
966
969
|
"--qsl-tool-group-gap": cssLength(appearance?.toolGroupGap),
|
|
967
970
|
"--qsl-tool-row-padding": cssLength(appearance?.toolRowPadding)
|
|
968
971
|
});
|
|
@@ -1110,7 +1113,7 @@ function MessageActions({ message, options, texts, contentRef, side = message.ro
|
|
|
1110
1113
|
item.id
|
|
1111
1114
|
);
|
|
1112
1115
|
}) }),
|
|
1113
|
-
action.error && /* @__PURE__ */ jsx12("p", { className: "qsl:mt-2 qsl:text-
|
|
1116
|
+
action.error && /* @__PURE__ */ jsx12("p", { className: "qsl:mt-2 qsl:text-small qsl:text-destructive", role: "alert", children: action.error })
|
|
1114
1117
|
] });
|
|
1115
1118
|
}
|
|
1116
1119
|
|
|
@@ -1198,7 +1201,7 @@ function announce(text) {
|
|
|
1198
1201
|
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1199
1202
|
var stepClasses = "qsl:mt-[var(--qsl-chat-message-gap,10px)]";
|
|
1200
1203
|
var denseStepClasses = "qsl:mt-[var(--qsl-chat-dense-message-gap,3px)]";
|
|
1201
|
-
var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:py-[var(--qsl-tool-row-padding,1px)] qsl:pl-6 qsl:text-left qsl:text-
|
|
1204
|
+
var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:py-[var(--qsl-tool-row-padding,1px)] qsl:pl-6 qsl:text-left qsl:text-small qsl:text-muted-foreground";
|
|
1202
1205
|
var traceButtonClasses = "qsl:cursor-pointer qsl:rounded-md qsl:pr-2 qsl:transition-colors qsl:hover:bg-secondary qsl:hover:text-foreground qsl:focus-visible:bg-secondary qsl:focus-visible:text-foreground qsl:focus-visible:outline-none";
|
|
1203
1206
|
var traceIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:opacity-60";
|
|
1204
1207
|
var traceErrorIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:text-destructive qsl:opacity-100";
|
|
@@ -1209,7 +1212,7 @@ var rowErrorIconClasses = cn(traceErrorIconClasses, "qsl:mt-0");
|
|
|
1209
1212
|
var rowLineClasses = cn(traceLineClasses, "qsl:self-auto");
|
|
1210
1213
|
var chipClasses = cn(
|
|
1211
1214
|
"qsl:inline-flex qsl:max-w-[220px] qsl:items-center qsl:gap-[5px] qsl:rounded-full qsl:border qsl:border-border-soft qsl:px-2.5 qsl:py-0.5",
|
|
1212
|
-
"qsl:text-
|
|
1215
|
+
"qsl:text-small qsl:text-muted-foreground qsl:transition-colors",
|
|
1213
1216
|
"qsl:data-[state=running]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
|
|
1214
1217
|
"qsl:data-[state=thinking]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
|
|
1215
1218
|
"qsl:data-[state=error]:border-[color-mix(in_srgb,var(--qsl-destructive)_45%,var(--qsl-border-soft))]",
|
|
@@ -1218,7 +1221,7 @@ var chipClasses = cn(
|
|
|
1218
1221
|
var chipInteractiveClasses = "qsl:cursor-pointer qsl:hover:border-border qsl:hover:bg-secondary qsl:hover:text-foreground qsl:focus-visible:border-border qsl:focus-visible:bg-secondary qsl:focus-visible:text-foreground qsl:focus-visible:outline-none qsl:data-[state=done]:hover:opacity-100 qsl:data-[state=done]:focus-visible:opacity-100";
|
|
1219
1222
|
var collapseAtBottomFrom = 11;
|
|
1220
1223
|
var maxAnnouncementsAtOnce = 2;
|
|
1221
|
-
var bubbleBodyClasses = "qsl:relative qsl:max-w-[86%] qsl:px-3 qsl:py-2 qsl:
|
|
1224
|
+
var bubbleBodyClasses = "qsl:relative qsl:max-w-[86%] qsl:px-3 qsl:py-2 qsl:text-body qsl:[overflow-wrap:anywhere] qsl:@max-[620px]/chat:max-w-full";
|
|
1222
1225
|
function isStep(message) {
|
|
1223
1226
|
return !!message && (message.role === "thinking" || message.role === "tool");
|
|
1224
1227
|
}
|
|
@@ -1380,7 +1383,7 @@ function ChatMessages({
|
|
|
1380
1383
|
"data-timestamp-position": timestampOptions?.position ?? "aside",
|
|
1381
1384
|
children: [
|
|
1382
1385
|
/* @__PURE__ */ jsx13("time", { dateTime: messageDate(at)?.toISOString(), className: cn(
|
|
1383
|
-
"qsl:flex-none qsl:text-
|
|
1386
|
+
"qsl:flex-none qsl:text-small qsl:tabular-nums qsl:text-muted-foreground qsl:opacity-85",
|
|
1384
1387
|
timestampOptions?.position === "above" ? "qsl:self-start" : timestampOptions?.format && timestampOptions.format !== "time" ? "qsl:w-[clamp(60px,20%,120px)]" : "qsl:min-w-[5ch] qsl:whitespace-nowrap"
|
|
1385
1388
|
), children: messageDate(at) ? timestampLabel(messageDate(at), timestampOptions, now) : "" }),
|
|
1386
1389
|
/* @__PURE__ */ jsx13("div", { className: "qsl:min-w-0 qsl:flex-1 qsl:[&>*:first-child]:mt-0", children: content })
|
|
@@ -1435,7 +1438,7 @@ function ChatMessages({
|
|
|
1435
1438
|
const day = timestampDay(date, timestampOptions);
|
|
1436
1439
|
if (day.key !== lastDay) {
|
|
1437
1440
|
closeGroup();
|
|
1438
|
-
blocks.push(/* @__PURE__ */ jsx13("div", { className: cn(stepClasses, "qsl:text-center qsl:text-
|
|
1441
|
+
blocks.push(/* @__PURE__ */ jsx13("div", { className: cn(stepClasses, "qsl:text-center qsl:text-small qsl:text-muted-foreground"), "data-chat": "day-separator", "data-day": day.key, children: day.label }, `day-${message.key}`));
|
|
1439
1442
|
lastDay = day.key;
|
|
1440
1443
|
}
|
|
1441
1444
|
}
|
|
@@ -1483,15 +1486,14 @@ function ChatMessages({
|
|
|
1483
1486
|
const transcript = /* @__PURE__ */ jsxs6("div", { className: cn("qsl:@container/chat qsl:relative qsl:flex qsl:min-h-0 qsl:flex-1 qsl:flex-col", className), "data-quassel": "", style: {
|
|
1484
1487
|
...appearanceStyle(appearance),
|
|
1485
1488
|
"--qsl-chat-content-max-width": typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth,
|
|
1486
|
-
"--qsl-chat-horizontal-padding": typeof horizontalPadding === "number" ? `${horizontalPadding}px` : horizontalPadding
|
|
1487
|
-
"--qsl-timestamp-font-size": timestampOptions?.fontScale === void 0 ? void 0 : `calc(var(--qsl-base) * ${timestampOptions.fontScale})`
|
|
1489
|
+
"--qsl-chat-horizontal-padding": typeof horizontalPadding === "number" ? `${horizontalPadding}px` : horizontalPadding
|
|
1488
1490
|
}, children: [
|
|
1489
1491
|
/* @__PURE__ */ jsx13(
|
|
1490
1492
|
"div",
|
|
1491
1493
|
{
|
|
1492
1494
|
"aria-label": allTexts.transcript,
|
|
1493
1495
|
className: cn(
|
|
1494
|
-
"qsl:min-h-0 qsl:flex-1 qsl:cursor-default qsl:overflow-y-auto qsl:overscroll-contain qsl:text-
|
|
1496
|
+
"qsl:min-h-0 qsl:flex-1 qsl:cursor-default qsl:overflow-y-auto qsl:overscroll-contain qsl:text-body qsl:text-foreground",
|
|
1495
1497
|
"qsl:[--qsl-fade-edge:calc(100%_-_var(--qsl-composer-height,0px))]",
|
|
1496
1498
|
"qsl:[-webkit-mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
|
|
1497
1499
|
"qsl:[mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
|
|
@@ -1549,7 +1551,7 @@ function ChatMessages({
|
|
|
1549
1551
|
}
|
|
1550
1552
|
}, children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) }) }),
|
|
1551
1553
|
dock && openActions.length > 0 && createPortal(
|
|
1552
|
-
/* @__PURE__ */ jsx13("div", { className: "qsl:flex qsl:flex-col qsl:gap-[var(--qsl-chat-dense-message-gap,3px)] qsl:text-
|
|
1554
|
+
/* @__PURE__ */ jsx13("div", { className: "qsl:flex qsl:flex-col qsl:gap-[var(--qsl-chat-dense-message-gap,3px)] qsl:text-body qsl:text-foreground", style: appearanceStyle(appearance), children: openActions.map((message) => /* @__PURE__ */ jsx13("div", { children: /* @__PURE__ */ jsx13(ActionContent, { action: message.action, onDismissAction, renderAction, text: message.text, texts: allTexts }) }, message.key)) }),
|
|
1553
1555
|
dock
|
|
1554
1556
|
)
|
|
1555
1557
|
] });
|
|
@@ -1776,9 +1778,9 @@ function Bubble({
|
|
|
1776
1778
|
/* @__PURE__ */ jsxs6("div", { className: "qsl:min-w-0 qsl:flex-1", children: [
|
|
1777
1779
|
/* @__PURE__ */ jsx13("div", { className: cn(traceLineClasses, thinking && "qsl:italic qsl:whitespace-pre-wrap"), children: line }),
|
|
1778
1780
|
tool && /* @__PURE__ */ jsxs6("div", { className: "qsl:mt-0.5 qsl:border-l-2 qsl:border-border-soft qsl:pl-2", children: [
|
|
1779
|
-
/* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-
|
|
1781
|
+
/* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80", children: toolArgumentsText(tool) }),
|
|
1780
1782
|
tool.result !== void 0 && /* @__PURE__ */ jsx13("pre", { className: cn(
|
|
1781
|
-
"qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-
|
|
1783
|
+
"qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80",
|
|
1782
1784
|
tool.isError && "qsl:text-destructive qsl:opacity-100"
|
|
1783
1785
|
), children: prettyJson(tool.result) })
|
|
1784
1786
|
] })
|
|
@@ -1789,7 +1791,7 @@ function Bubble({
|
|
|
1789
1791
|
return /* @__PURE__ */ jsx13("div", { className: stepSpacing, children: /* @__PURE__ */ jsx13(ActionContent, { action: message.action, onDismissAction, renderAction, text: message.text, texts }) });
|
|
1790
1792
|
}
|
|
1791
1793
|
if (message.role === "system") {
|
|
1792
|
-
return /* @__PURE__ */ jsxs6("div", { className: cn(stepSpacing, "qsl:border-l-2 qsl:border-destructive/50 qsl:pl-3 qsl:text-
|
|
1794
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn(stepSpacing, "qsl:border-l-2 qsl:border-destructive/50 qsl:pl-3 qsl:text-small qsl:text-muted-foreground"), "data-message": "system", children: [
|
|
1793
1795
|
/* @__PURE__ */ jsx13(Markdown, { text: message.text }),
|
|
1794
1796
|
/* @__PURE__ */ jsx13(MessageAttachments, { message, texts })
|
|
1795
1797
|
] });
|
|
@@ -1802,15 +1804,15 @@ function Bubble({
|
|
|
1802
1804
|
const showSender = bubbleOptions?.showSender ?? (!!message.bubble?.label && !plain);
|
|
1803
1805
|
const content = /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1804
1806
|
showSender && sender && /* @__PURE__ */ jsx13("span", { className: cn(
|
|
1805
|
-
"qsl:mb-[5px] qsl:table qsl:text-
|
|
1807
|
+
"qsl:mb-[5px] qsl:table qsl:text-small qsl:font-semibold",
|
|
1806
1808
|
useBubble && message.bubble && "qsl:rounded-full qsl:border qsl:border-white/30 qsl:bg-black/15 qsl:px-[7px] qsl:py-px qsl:tracking-[0.02em]"
|
|
1807
1809
|
), "data-chat": "sender", children: sender }),
|
|
1808
1810
|
/* @__PURE__ */ jsx13("div", { "data-chat": "message-text", ref: textRef, children: /* @__PURE__ */ jsx13(Markdown, { text: message.text, streaming: message.role === "assistant" && !message.closed }) }),
|
|
1809
1811
|
/* @__PURE__ */ jsx13(MessageAttachments, { message, texts }),
|
|
1810
|
-
message.steered && /* @__PURE__ */ jsx13("small", { className: "qsl:mt-1 qsl:block qsl:text-
|
|
1812
|
+
message.steered && /* @__PURE__ */ jsx13("small", { className: "qsl:mt-1 qsl:block qsl:text-small qsl:opacity-70", "data-chat": "steered", children: texts.steered })
|
|
1811
1813
|
] });
|
|
1812
1814
|
const cursor = message.role === "assistant" && message.textCursor ? JSON.stringify(message.textCursor) : void 0;
|
|
1813
|
-
if (!useBubble) return /* @__PURE__ */ jsxs6("div", { "data-chat-text-cursor": cursor, className: cn(stepSpacing, "qsl:group/message qsl:relative qsl:w-full qsl:
|
|
1815
|
+
if (!useBubble) return /* @__PURE__ */ jsxs6("div", { "data-chat-text-cursor": cursor, className: cn(stepSpacing, "qsl:group/message qsl:relative qsl:w-full qsl:text-foreground"), "data-message": "answer", children: [
|
|
1814
1816
|
content,
|
|
1815
1817
|
/* @__PURE__ */ jsx13(MessageActions, { contentRef: textRef, message, options: messageActions, side, texts })
|
|
1816
1818
|
] });
|
|
@@ -1868,18 +1870,20 @@ function MessageAttachments({ message, texts }) {
|
|
|
1868
1870
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1869
1871
|
/* @__PURE__ */ jsx13("ul", { className: "qsl:mt-2.5 qsl:flex qsl:flex-wrap qsl:gap-2", "aria-label": texts.attachments, children: message.attachments.map((attachment, index) => {
|
|
1870
1872
|
const isImage = attachment.mediaType.startsWith("image/");
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
+
if (isImage)
|
|
1874
|
+
return /* @__PURE__ */ jsx13("li", { className: "qsl:relative qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border", children: /* @__PURE__ */ jsx13(
|
|
1873
1875
|
"button",
|
|
1874
1876
|
{
|
|
1875
1877
|
type: "button",
|
|
1876
|
-
className: "qsl:block qsl:
|
|
1878
|
+
className: "qsl:block qsl:cursor-zoom-in qsl:bg-secondary",
|
|
1877
1879
|
"aria-label": fillText(texts.enlargeImage ?? defaultTexts.enlargeImage, { name: attachment.name }),
|
|
1880
|
+
title: attachment.name,
|
|
1878
1881
|
onClick: () => setEnlarged(attachment),
|
|
1879
1882
|
"data-chat": "attachment-image",
|
|
1880
|
-
children: /* @__PURE__ */ jsx13("img", { className: "qsl:
|
|
1883
|
+
children: /* @__PURE__ */ jsx13("img", { className: "qsl:block qsl:size-24 qsl:object-cover", src: attachment.url, alt: attachment.name, loading: "lazy" })
|
|
1881
1884
|
}
|
|
1882
|
-
),
|
|
1885
|
+
) }, `${attachment.url}-${index}`);
|
|
1886
|
+
return /* @__PURE__ */ jsxs6("li", { className: "qsl:relative qsl:flex qsl:w-[190px] qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-small", children: [
|
|
1883
1887
|
attachment.mediaType.startsWith("video/") && /* @__PURE__ */ jsx13("video", { className: "qsl:block qsl:h-[112px] qsl:w-full qsl:bg-secondary qsl:object-contain", src: attachment.url, controls: true, preload: "metadata", "aria-label": attachment.name }),
|
|
1884
1888
|
/* @__PURE__ */ jsxs6("div", { className: "qsl:flex qsl:flex-col qsl:gap-1 qsl:p-2 qsl:[overflow-wrap:anywhere]", children: [
|
|
1885
1889
|
/* @__PURE__ */ jsx13("a", { className: "qsl:font-medium", href: attachmentDownloadUrl(attachment.url), download: attachment.name, children: attachment.name }),
|
|
@@ -1903,7 +1907,7 @@ function ImageViewer({ attachment, onClose, texts }) {
|
|
|
1903
1907
|
"data-chat": "image-viewer",
|
|
1904
1908
|
children: attachment && /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1905
1909
|
/* @__PURE__ */ jsx13("img", { className: "qsl:block qsl:max-h-[calc(100vh-6rem)] qsl:max-w-full qsl:rounded-md qsl:bg-background qsl:object-contain qsl:shadow-lg", src: attachment.url, alt: attachment.name }),
|
|
1906
|
-
/* @__PURE__ */ jsxs6("div", { className: "qsl:flex qsl:items-center qsl:gap-4 qsl:text-
|
|
1910
|
+
/* @__PURE__ */ jsxs6("div", { className: "qsl:flex qsl:items-center qsl:gap-4 qsl:text-small qsl:text-white", children: [
|
|
1907
1911
|
/* @__PURE__ */ jsx13("span", { className: "qsl:[overflow-wrap:anywhere]", children: attachment.name }),
|
|
1908
1912
|
/* @__PURE__ */ jsx13("a", { className: "qsl:underline", href: attachmentDownloadUrl(attachment.url), download: attachment.name, children: texts.downloadAttachment ?? defaultTexts.downloadAttachment }),
|
|
1909
1913
|
/* @__PURE__ */ jsx13(Dialog.Close, { className: "qsl:cursor-pointer qsl:underline", children: texts.close })
|
|
@@ -1994,7 +1998,7 @@ function ChatPanel({
|
|
|
1994
1998
|
}
|
|
1995
1999
|
|
|
1996
2000
|
// packages/quassel/src/ChatInputToolbar.tsx
|
|
1997
|
-
import { PaperclipIcon, SendIcon, XIcon as XIcon3 } from "lucide-react";
|
|
2001
|
+
import { PaperclipIcon, SendIcon as SendIcon2, XIcon as XIcon3 } from "lucide-react";
|
|
1998
2002
|
|
|
1999
2003
|
// packages/quassel/src/ui/useFileInput.ts
|
|
2000
2004
|
import { useRef as useRef5, useState as useState6 } from "react";
|
|
@@ -2045,12 +2049,217 @@ function useFileInput({ disabled, onFiles, onPasteText }) {
|
|
|
2045
2049
|
}
|
|
2046
2050
|
|
|
2047
2051
|
// packages/quassel/src/ChatInputToolbar.tsx
|
|
2048
|
-
import { useCallback as useCallback3, useContext as useContext4, useEffect as
|
|
2052
|
+
import { useCallback as useCallback3, useContext as useContext4, useEffect as useEffect6, useImperativeHandle, useLayoutEffect as useLayoutEffect5, useRef as useRef8, useState as useState8 } from "react";
|
|
2053
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
2054
|
+
|
|
2055
|
+
// packages/quassel/src/ComposerPrimaryAction.tsx
|
|
2056
|
+
import { LoaderCircleIcon, MicIcon, SendIcon, SquareIcon as SquareIcon2 } from "lucide-react";
|
|
2057
|
+
import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect4, useRef as useRef7, useState as useState7 } from "react";
|
|
2058
|
+
|
|
2059
|
+
// packages/quassel/src/RecordingAura.tsx
|
|
2060
|
+
import { useLayoutEffect as useLayoutEffect3, useRef as useRef6 } from "react";
|
|
2049
2061
|
import { createPortal as createPortal2 } from "react-dom";
|
|
2050
|
-
import {
|
|
2062
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2063
|
+
function RecordingAura({ anchor, level = 0 }) {
|
|
2064
|
+
const aura = useRef6(null);
|
|
2065
|
+
const volume = Number.isFinite(level) ? Math.max(0, Math.min(1, level)) : 0;
|
|
2066
|
+
useLayoutEffect3(() => {
|
|
2067
|
+
const element = aura.current;
|
|
2068
|
+
const view = anchor.ownerDocument.defaultView;
|
|
2069
|
+
if (!element || !view) return;
|
|
2070
|
+
let frame = 0;
|
|
2071
|
+
let visible = true;
|
|
2072
|
+
const observer = new view.IntersectionObserver(([entry]) => {
|
|
2073
|
+
visible = entry.isIntersecting;
|
|
2074
|
+
});
|
|
2075
|
+
observer.observe(anchor);
|
|
2076
|
+
const update = () => {
|
|
2077
|
+
const rect = anchor.getBoundingClientRect();
|
|
2078
|
+
const style = view.getComputedStyle(anchor);
|
|
2079
|
+
element.style.left = `${rect.left}px`;
|
|
2080
|
+
element.style.top = `${rect.top}px`;
|
|
2081
|
+
element.style.width = `${rect.width}px`;
|
|
2082
|
+
element.style.height = `${rect.height}px`;
|
|
2083
|
+
element.style.visibility = visible && rect.width && rect.height && anchor.checkVisibility() ? "visible" : "hidden";
|
|
2084
|
+
element.style.setProperty("--qsl-pill-aura-color", style.getPropertyValue("--qsl-pill-aura-color") || style.getPropertyValue("--qsl-destructive"));
|
|
2085
|
+
element.style.setProperty("--qsl-pill-aura-ring-color", style.getPropertyValue("--qsl-pill-aura-ring-color") || style.getPropertyValue("--qsl-pill-aura-color") || style.getPropertyValue("--qsl-destructive"));
|
|
2086
|
+
element.style.zIndex = style.getPropertyValue("--qsl-pill-aura-z-index") || "1000";
|
|
2087
|
+
frame = view.requestAnimationFrame(update);
|
|
2088
|
+
};
|
|
2089
|
+
update();
|
|
2090
|
+
return () => {
|
|
2091
|
+
view.cancelAnimationFrame(frame);
|
|
2092
|
+
observer.disconnect();
|
|
2093
|
+
};
|
|
2094
|
+
}, [anchor]);
|
|
2095
|
+
return createPortal2(/* @__PURE__ */ jsx15(
|
|
2096
|
+
"span",
|
|
2097
|
+
{
|
|
2098
|
+
"aria-hidden": "true",
|
|
2099
|
+
className: "qsl:recording-aura",
|
|
2100
|
+
"data-quassel": "",
|
|
2101
|
+
"data-recording-aura": "",
|
|
2102
|
+
ref: aura,
|
|
2103
|
+
style: { transform: `scale(${1.2 + volume * 0.65})`, opacity: 0.4 + volume * 0.4 }
|
|
2104
|
+
}
|
|
2105
|
+
), anchor.ownerDocument.body);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// packages/quassel/src/ComposerPrimaryAction.tsx
|
|
2109
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2110
|
+
function ComposerPrimaryAction({ hasContent, running: running2, sending, disabled, sendDisabled, microphone, texts, onSend, onStop }) {
|
|
2111
|
+
const state = microphone && microphone.state !== "idle" ? microphone.state : hasContent ? "send" : running2 ? "stop" : microphone && !sending ? "microphone" : "send";
|
|
2112
|
+
const voice = state === "microphone" || state === "preparing" || state === "recording";
|
|
2113
|
+
const busy = state === "preparing" || state === "transcribing";
|
|
2114
|
+
const blocked = disabled || state === "transcribing" || state === "send" && (sendDisabled || sending || !hasContent) || state === "stop" && !onStop;
|
|
2115
|
+
const label = state === "microphone" ? microphone?.label ?? texts.microphone : state === "preparing" ? texts.microphonePreparing : state === "recording" ? texts.microphoneRecording : state === "transcribing" ? texts.microphoneTranscribing : state === "stop" ? texts.stop : running2 ? texts.sendIntoRun : texts.send;
|
|
2116
|
+
const [button, setButton] = useState7(null);
|
|
2117
|
+
const press = useRef7(null);
|
|
2118
|
+
const suppressClick = useRef7(false);
|
|
2119
|
+
const clickReset = useRef7(void 0);
|
|
2120
|
+
const currentMicrophone = useRef7(microphone);
|
|
2121
|
+
const resetClick = () => {
|
|
2122
|
+
clearTimeout(clickReset.current);
|
|
2123
|
+
clickReset.current = setTimeout(() => {
|
|
2124
|
+
suppressClick.current = false;
|
|
2125
|
+
}, 0);
|
|
2126
|
+
};
|
|
2127
|
+
const cancel = () => {
|
|
2128
|
+
const active = press.current;
|
|
2129
|
+
press.current = null;
|
|
2130
|
+
if (active) resetClick();
|
|
2131
|
+
const current = currentMicrophone.current;
|
|
2132
|
+
if (active) active.microphone.onCancel();
|
|
2133
|
+
else if (current?.state === "recording" || current?.state === "preparing") current.onCancel();
|
|
2134
|
+
};
|
|
2135
|
+
useLayoutEffect4(() => {
|
|
2136
|
+
currentMicrophone.current = microphone;
|
|
2137
|
+
}, [microphone]);
|
|
2138
|
+
useEffect5(() => {
|
|
2139
|
+
if (disabled) cancel();
|
|
2140
|
+
}, [disabled]);
|
|
2141
|
+
useEffect5(() => {
|
|
2142
|
+
if (!button) return;
|
|
2143
|
+
const document2 = button.ownerDocument;
|
|
2144
|
+
const view = document2.defaultView;
|
|
2145
|
+
const onVisibility = () => {
|
|
2146
|
+
if (document2.hidden) cancel();
|
|
2147
|
+
};
|
|
2148
|
+
const onEscape = (event) => {
|
|
2149
|
+
if (event.key === "Escape" && (press.current || currentMicrophone.current?.state === "recording" || currentMicrophone.current?.state === "preparing")) {
|
|
2150
|
+
event.preventDefault();
|
|
2151
|
+
cancel();
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
view.addEventListener("blur", cancel);
|
|
2155
|
+
document2.addEventListener("visibilitychange", onVisibility);
|
|
2156
|
+
document2.addEventListener("keydown", onEscape);
|
|
2157
|
+
return () => {
|
|
2158
|
+
view.removeEventListener("blur", cancel);
|
|
2159
|
+
document2.removeEventListener("visibilitychange", onVisibility);
|
|
2160
|
+
document2.removeEventListener("keydown", onEscape);
|
|
2161
|
+
cancel();
|
|
2162
|
+
clearTimeout(clickReset.current);
|
|
2163
|
+
};
|
|
2164
|
+
}, [button]);
|
|
2165
|
+
const start = (source, timeStamp, pointerId, key) => {
|
|
2166
|
+
if (!voice || state === "preparing" || blocked || !microphone || press.current) return;
|
|
2167
|
+
press.current = { source, pointerId, key, microphone };
|
|
2168
|
+
clearTimeout(clickReset.current);
|
|
2169
|
+
suppressClick.current = true;
|
|
2170
|
+
microphone.onPressStart({ source, timeStamp });
|
|
2171
|
+
};
|
|
2172
|
+
const end = (timeStamp) => {
|
|
2173
|
+
const active = press.current;
|
|
2174
|
+
press.current = null;
|
|
2175
|
+
resetClick();
|
|
2176
|
+
active?.microphone.onPressEnd({ source: active.source, timeStamp });
|
|
2177
|
+
};
|
|
2178
|
+
const activationKey = (event) => (event.key === " " || event.key === "Enter") && !event.nativeEvent.isComposing && event.nativeEvent.keyCode !== 229;
|
|
2179
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
2180
|
+
state === "recording" && button && /* @__PURE__ */ jsx16(RecordingAura, { anchor: button, level: microphone?.level }),
|
|
2181
|
+
/* @__PURE__ */ jsxs8(
|
|
2182
|
+
"button",
|
|
2183
|
+
{
|
|
2184
|
+
"aria-busy": busy || void 0,
|
|
2185
|
+
"aria-label": label,
|
|
2186
|
+
"aria-pressed": voice ? state === "recording" : void 0,
|
|
2187
|
+
className: "qsl:primary-action",
|
|
2188
|
+
"data-primary-action": state,
|
|
2189
|
+
disabled: blocked,
|
|
2190
|
+
onBlur: () => {
|
|
2191
|
+
if (press.current?.source === "keyboard") cancel();
|
|
2192
|
+
},
|
|
2193
|
+
onClick: (event) => {
|
|
2194
|
+
if (suppressClick.current) {
|
|
2195
|
+
suppressClick.current = false;
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
if (voice && event.detail === 0) {
|
|
2199
|
+
start("virtual", event.timeStamp);
|
|
2200
|
+
end(event.timeStamp);
|
|
2201
|
+
suppressClick.current = false;
|
|
2202
|
+
} else if (state === "send") onSend();
|
|
2203
|
+
else if (state === "stop") onStop?.();
|
|
2204
|
+
},
|
|
2205
|
+
onContextMenu: (event) => {
|
|
2206
|
+
if (voice) event.preventDefault();
|
|
2207
|
+
},
|
|
2208
|
+
onKeyDown: (event) => {
|
|
2209
|
+
if (activationKey(event) && event.repeat) {
|
|
2210
|
+
event.preventDefault();
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
if (!voice) {
|
|
2214
|
+
suppressClick.current = false;
|
|
2215
|
+
return;
|
|
2216
|
+
}
|
|
2217
|
+
if (activationKey(event)) {
|
|
2218
|
+
event.preventDefault();
|
|
2219
|
+
start("keyboard", event.timeStamp, void 0, event.key);
|
|
2220
|
+
}
|
|
2221
|
+
},
|
|
2222
|
+
onKeyUp: (event) => {
|
|
2223
|
+
if (activationKey(event) && (voice || press.current?.source === "keyboard")) {
|
|
2224
|
+
event.preventDefault();
|
|
2225
|
+
if (press.current?.source === "keyboard" && press.current.key === event.key) end(event.timeStamp);
|
|
2226
|
+
}
|
|
2227
|
+
},
|
|
2228
|
+
onLostPointerCapture: (event) => {
|
|
2229
|
+
if (press.current?.pointerId === event.pointerId) cancel();
|
|
2230
|
+
},
|
|
2231
|
+
onPointerCancel: (event) => {
|
|
2232
|
+
if (press.current?.pointerId === event.pointerId) cancel();
|
|
2233
|
+
},
|
|
2234
|
+
onPointerDown: (event) => {
|
|
2235
|
+
suppressClick.current = false;
|
|
2236
|
+
if (event.button !== 0 || event.isPrimary === false) return;
|
|
2237
|
+
start("pointer", event.timeStamp, event.pointerId);
|
|
2238
|
+
if (press.current?.pointerId === event.pointerId) event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
2239
|
+
},
|
|
2240
|
+
onPointerUp: (event) => {
|
|
2241
|
+
if (press.current?.source === "pointer" && press.current.pointerId === event.pointerId) end(event.timeStamp);
|
|
2242
|
+
},
|
|
2243
|
+
ref: setButton,
|
|
2244
|
+
title: state === "microphone" ? texts.microphoneHint : label,
|
|
2245
|
+
type: "button",
|
|
2246
|
+
children: [
|
|
2247
|
+
/* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "qsl:primary-icon", "data-active": state === "microphone" || state === "recording", children: /* @__PURE__ */ jsx16(MicIcon, {}) }),
|
|
2248
|
+
/* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "qsl:primary-icon", "data-active": state === "send", children: /* @__PURE__ */ jsx16(SendIcon, {}) }),
|
|
2249
|
+
/* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "qsl:primary-icon", "data-active": state === "stop", children: /* @__PURE__ */ jsx16(SquareIcon2, { fill: "currentColor" }) }),
|
|
2250
|
+
/* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "qsl:primary-icon", "data-active": busy, children: /* @__PURE__ */ jsx16(LoaderCircleIcon, { className: "qsl:motion-safe:animate-spin" }) }),
|
|
2251
|
+
state === "recording" && /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "qsl:recording-dot" })
|
|
2252
|
+
]
|
|
2253
|
+
}
|
|
2254
|
+
)
|
|
2255
|
+
] });
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
// packages/quassel/src/ChatInputToolbar.tsx
|
|
2259
|
+
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2051
2260
|
var COMPACT_WIDTH_PX = 480;
|
|
2052
|
-
var errorClasses = "qsl:px-3 qsl:py-2 qsl:text-
|
|
2053
|
-
var attachmentItemClasses = "qsl:relative qsl:flex qsl:w-[190px] qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-
|
|
2261
|
+
var errorClasses = "qsl:px-3 qsl:py-2 qsl:text-small qsl:text-destructive";
|
|
2262
|
+
var attachmentItemClasses = "qsl:relative qsl:flex qsl:w-[190px] qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-small";
|
|
2054
2263
|
var attachmentMediaClasses = "qsl:block qsl:h-[112px] qsl:w-full qsl:bg-secondary qsl:object-contain";
|
|
2055
2264
|
function ChatInputToolbar({
|
|
2056
2265
|
onSend,
|
|
@@ -2067,6 +2276,8 @@ function ChatInputToolbar({
|
|
|
2067
2276
|
actions,
|
|
2068
2277
|
toolbarLeft,
|
|
2069
2278
|
toolbarRight,
|
|
2279
|
+
microphone,
|
|
2280
|
+
replaceInput,
|
|
2070
2281
|
texts,
|
|
2071
2282
|
handleRef,
|
|
2072
2283
|
attachments: attachmentsEnabled = true,
|
|
@@ -2082,21 +2293,21 @@ function ChatInputToolbar({
|
|
|
2082
2293
|
const sendScope = useContext4(ChatSendContext);
|
|
2083
2294
|
const allTexts = { ...defaultTexts, ...texts };
|
|
2084
2295
|
const { Button: Button2, StopButton: StopButton2, Toggle: Toggle2 } = useQuasselComponents();
|
|
2085
|
-
const [draft, setDraft] =
|
|
2086
|
-
const [sending, setSending] =
|
|
2087
|
-
const [sendError, setSendError] =
|
|
2088
|
-
const [failedSubmissions, setFailedSubmissions] =
|
|
2089
|
-
const nextFailedId =
|
|
2090
|
-
const pendingSend =
|
|
2091
|
-
const generation =
|
|
2092
|
-
|
|
2296
|
+
const [draft, setDraft] = useState8(initialValue);
|
|
2297
|
+
const [sending, setSending] = useState8(false);
|
|
2298
|
+
const [sendError, setSendError] = useState8();
|
|
2299
|
+
const [failedSubmissions, setFailedSubmissions] = useState8([]);
|
|
2300
|
+
const nextFailedId = useRef8(0);
|
|
2301
|
+
const pendingSend = useRef8(false);
|
|
2302
|
+
const generation = useRef8(0);
|
|
2303
|
+
useLayoutEffect5(() => () => {
|
|
2093
2304
|
generation.current += 1;
|
|
2094
2305
|
}, []);
|
|
2095
|
-
const draftRevision =
|
|
2096
|
-
const [attachments, setAttachments] =
|
|
2097
|
-
const attachmentsRef =
|
|
2098
|
-
const nextAttachmentId =
|
|
2099
|
-
const [attachmentError, setAttachmentError] =
|
|
2306
|
+
const draftRevision = useRef8(0);
|
|
2307
|
+
const [attachments, setAttachments] = useState8([]);
|
|
2308
|
+
const attachmentsRef = useRef8([]);
|
|
2309
|
+
const nextAttachmentId = useRef8(0);
|
|
2310
|
+
const [attachmentError, setAttachmentError] = useState8();
|
|
2100
2311
|
const updateAttachments = (update) => {
|
|
2101
2312
|
attachmentsRef.current = update(attachmentsRef.current);
|
|
2102
2313
|
setAttachments(attachmentsRef.current);
|
|
@@ -2127,10 +2338,11 @@ function ChatInputToolbar({
|
|
|
2127
2338
|
);
|
|
2128
2339
|
}
|
|
2129
2340
|
};
|
|
2130
|
-
const rootRef =
|
|
2131
|
-
const textareaRef =
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2341
|
+
const rootRef = useRef8(null);
|
|
2342
|
+
const textareaRef = useRef8(null);
|
|
2343
|
+
const composing = useRef8(false);
|
|
2344
|
+
const autoFocusSettled = useRef8(false);
|
|
2345
|
+
useEffect6(() => {
|
|
2134
2346
|
if (!autoFocus || autoFocusSettled.current) return;
|
|
2135
2347
|
const input2 = textareaRef.current;
|
|
2136
2348
|
if (!input2) return;
|
|
@@ -2175,8 +2387,8 @@ function ChatInputToolbar({
|
|
|
2175
2387
|
window.removeEventListener("blur", settle);
|
|
2176
2388
|
};
|
|
2177
2389
|
}, [autoFocus, disabled, onAutoFocusSettled]);
|
|
2178
|
-
const [compact, setCompact] =
|
|
2179
|
-
const pendingFocus =
|
|
2390
|
+
const [compact, setCompact] = useState8(false);
|
|
2391
|
+
const pendingFocus = useRef8(false);
|
|
2180
2392
|
const fileInput = useFileInput({
|
|
2181
2393
|
disabled: disabled || sending,
|
|
2182
2394
|
onFiles: addFiles,
|
|
@@ -2192,17 +2404,21 @@ function ChatInputToolbar({
|
|
|
2192
2404
|
});
|
|
2193
2405
|
const toolbar = layout === "toolbar";
|
|
2194
2406
|
const inline = layout === "inline";
|
|
2195
|
-
const
|
|
2196
|
-
const
|
|
2407
|
+
const pill = layout === "pill";
|
|
2408
|
+
const inputRows = inline || toolbar || pill ? 1 : rows;
|
|
2409
|
+
const inputMaxRows = toolbar ? 1 : pill ? maxRows ?? 6 : inline ? maxRows ?? 1 : maxRows;
|
|
2410
|
+
const microphoneBusy = pill && !!microphone && microphone.state !== "idle";
|
|
2411
|
+
const replacingInput = pill && replaceInput !== void 0 && replaceInput !== null && typeof replaceInput !== "boolean";
|
|
2197
2412
|
const rootClasses = cn(
|
|
2198
|
-
"qsl:flex qsl:shrink-0 qsl:flex-col
|
|
2199
|
-
"qsl:in-data-[tone=material]:rounded-xl qsl:in-data-[tone=material]:border-glass-edge/50 qsl:in-data-[tone=material]:bg-background",
|
|
2413
|
+
"qsl:flex qsl:shrink-0 qsl:flex-col",
|
|
2414
|
+
pill ? "qsl:min-w-0" : "qsl:overflow-hidden qsl:rounded-[var(--qsl-input-card-radius,--theme(--radius-xl))] qsl:border qsl:border-border-strong qsl:bg-background qsl:shadow-bar qsl:transition-colors qsl:focus-within:border-primary qsl:in-data-[tone=material]:rounded-xl qsl:in-data-[tone=material]:border-glass-edge/50 qsl:in-data-[tone=material]:bg-background",
|
|
2200
2415
|
toolbar && "qsl:h-full qsl:min-w-0 qsl:flex-row qsl:items-center qsl:rounded-lg qsl:data-[working=true]:animate-working-pulse qsl:data-[working=true]:border-primary qsl:motion-reduce:data-[working=true]:animate-none",
|
|
2201
2416
|
fileInput.dragging && "qsl:outline-2 qsl:outline-offset-[3px] qsl:outline-dashed qsl:outline-primary"
|
|
2202
2417
|
);
|
|
2203
2418
|
const textareaClasses = cn(
|
|
2204
|
-
"qsl:resize-none qsl:overscroll-contain qsl:border-0 qsl:bg-transparent qsl:text-
|
|
2205
|
-
|
|
2419
|
+
"qsl:resize-none qsl:overscroll-contain qsl:border-0 qsl:bg-transparent qsl:text-foreground qsl:placeholder:text-muted-foreground",
|
|
2420
|
+
!pill && "qsl:text-body qsl:focus:outline-none",
|
|
2421
|
+
pill ? "qsl:pill-input" : inline ? "qsl:min-w-0 qsl:flex-1 qsl:px-2.5 qsl:py-2" : toolbar ? "qsl:w-full qsl:min-w-0 qsl:flex-auto qsl:px-2 qsl:py-[3px]" : "qsl:px-3 qsl:pt-3 qsl:pb-2"
|
|
2206
2422
|
);
|
|
2207
2423
|
const toolbarRowClasses = cn(
|
|
2208
2424
|
"qsl:flex qsl:items-center qsl:gap-2 qsl:border-t qsl:border-border-soft qsl:px-2 qsl:py-1.5 qsl:in-data-[tone=overseer-details]:flex-nowrap",
|
|
@@ -2237,10 +2453,10 @@ function ChatInputToolbar({
|
|
|
2237
2453
|
fileInput.clearDragging();
|
|
2238
2454
|
}
|
|
2239
2455
|
}));
|
|
2240
|
-
|
|
2456
|
+
useEffect6(() => {
|
|
2241
2457
|
onDraftChange?.(draft);
|
|
2242
2458
|
}, [draft, onDraftChange]);
|
|
2243
|
-
|
|
2459
|
+
useEffect6(() => {
|
|
2244
2460
|
if (!pendingFocus.current) {
|
|
2245
2461
|
return;
|
|
2246
2462
|
}
|
|
@@ -2257,7 +2473,7 @@ function ChatInputToolbar({
|
|
|
2257
2473
|
return;
|
|
2258
2474
|
}
|
|
2259
2475
|
const style = getComputedStyle(element);
|
|
2260
|
-
const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.
|
|
2476
|
+
const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.5;
|
|
2261
2477
|
const padding = Number.parseFloat(style.paddingTop) + Number.parseFloat(style.paddingBottom);
|
|
2262
2478
|
const maximum = lineHeight * Math.max(inputMaxRows, inputRows) + padding;
|
|
2263
2479
|
element.style.height = "auto";
|
|
@@ -2265,10 +2481,10 @@ function ChatInputToolbar({
|
|
|
2265
2481
|
element.style.height = `${Math.min(contentHeight, maximum)}px`;
|
|
2266
2482
|
element.style.overflowY = contentHeight > maximum ? "auto" : "hidden";
|
|
2267
2483
|
}, [inputMaxRows, inputRows]);
|
|
2268
|
-
|
|
2484
|
+
useEffect6(() => {
|
|
2269
2485
|
applyAutoGrow();
|
|
2270
|
-
}, [draft, applyAutoGrow]);
|
|
2271
|
-
|
|
2486
|
+
}, [draft, replacingInput, applyAutoGrow]);
|
|
2487
|
+
useEffect6(() => {
|
|
2272
2488
|
const element = textareaRef.current;
|
|
2273
2489
|
if (!element || inputMaxRows === void 0) {
|
|
2274
2490
|
return;
|
|
@@ -2282,8 +2498,8 @@ function ChatInputToolbar({
|
|
|
2282
2498
|
});
|
|
2283
2499
|
observer.observe(element);
|
|
2284
2500
|
return () => observer.disconnect();
|
|
2285
|
-
}, [inputMaxRows, applyAutoGrow]);
|
|
2286
|
-
|
|
2501
|
+
}, [inputMaxRows, replacingInput, applyAutoGrow]);
|
|
2502
|
+
useEffect6(() => {
|
|
2287
2503
|
const element = rootRef.current;
|
|
2288
2504
|
if (!element) {
|
|
2289
2505
|
return;
|
|
@@ -2295,7 +2511,7 @@ function ChatInputToolbar({
|
|
|
2295
2511
|
return () => observer.disconnect();
|
|
2296
2512
|
}, []);
|
|
2297
2513
|
const hasAttachments = attachments.length > 0;
|
|
2298
|
-
|
|
2514
|
+
useEffect6(() => {
|
|
2299
2515
|
onAttachmentsChange?.(hasAttachments);
|
|
2300
2516
|
}, [hasAttachments, onAttachmentsChange]);
|
|
2301
2517
|
const capabilityError = hasAttachments && attachmentCapabilitiesError ? attachmentCapabilitiesError : attachmentCapabilities ? attachmentCapabilityError(attachments.map((entry) => ({
|
|
@@ -2306,13 +2522,13 @@ function ChatInputToolbar({
|
|
|
2306
2522
|
const preparing = attachments.some((entry) => entry.status === "reading");
|
|
2307
2523
|
const attachmentBlocked = attachments.some((entry) => entry.status !== "ready");
|
|
2308
2524
|
const currentError = sendError ?? attachmentError ?? capabilityError ?? attachments.find((entry) => entry.status === "error")?.error;
|
|
2309
|
-
|
|
2525
|
+
useEffect6(() => {
|
|
2310
2526
|
onErrorChange?.(currentError);
|
|
2311
2527
|
}, [currentError, onErrorChange]);
|
|
2312
2528
|
const send = async (onSubmit = onSend, allowEmpty = false) => {
|
|
2313
2529
|
const text = draft.trim();
|
|
2314
2530
|
const snapshot = attachmentsRef.current;
|
|
2315
|
-
if (!allowEmpty && !text && !snapshot.length || disabled || sendDisabled || pendingSend.current || capabilityError || snapshot.some((entry) => entry.status !== "ready")) {
|
|
2531
|
+
if (!allowEmpty && !text && !snapshot.length || disabled || sendDisabled || microphoneBusy || replacingInput || pendingSend.current || capabilityError || snapshot.some((entry) => entry.status !== "ready")) {
|
|
2316
2532
|
return;
|
|
2317
2533
|
}
|
|
2318
2534
|
pendingSend.current = true;
|
|
@@ -2357,21 +2573,21 @@ function ChatInputToolbar({
|
|
|
2357
2573
|
}
|
|
2358
2574
|
};
|
|
2359
2575
|
const onKeyDown = (event) => {
|
|
2360
|
-
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing && event.nativeEvent.keyCode !== 229 && (sendShortcut === "enter" || event.metaKey || event.ctrlKey)) {
|
|
2576
|
+
if (event.key === "Enter" && !event.shiftKey && !composing.current && !event.nativeEvent.isComposing && event.nativeEvent.keyCode !== 229 && (sendShortcut === "enter" || event.metaKey || event.ctrlKey)) {
|
|
2361
2577
|
event.preventDefault();
|
|
2362
2578
|
if (!event.repeat) void send();
|
|
2363
2579
|
}
|
|
2364
2580
|
};
|
|
2365
|
-
const attachmentPreviews = attachments.length > 0 && /* @__PURE__ */
|
|
2366
|
-
entry.status === "ready" && entry.input.mediaType.startsWith("image/") && /* @__PURE__ */
|
|
2367
|
-
entry.status === "ready" && entry.input.mediaType.startsWith("video/") && /* @__PURE__ */
|
|
2368
|
-
/* @__PURE__ */
|
|
2369
|
-
/* @__PURE__ */
|
|
2370
|
-
/* @__PURE__ */
|
|
2371
|
-
entry.status === "reading" && /* @__PURE__ */
|
|
2372
|
-
entry.status === "error" && /* @__PURE__ */
|
|
2581
|
+
const attachmentPreviews = attachments.length > 0 && /* @__PURE__ */ jsx17("ul", { className: "qsl:flex qsl:max-h-[240px] qsl:flex-wrap qsl:gap-2 qsl:overflow-y-auto qsl:overscroll-contain qsl:px-3 qsl:pt-2.5 qsl:in-data-[tone=overseer-details]:max-h-40 qsl:in-data-[tone=overseer-details]:overflow-y-auto", "aria-label": allTexts.attachments, children: attachments.map((entry) => /* @__PURE__ */ jsxs9("li", { className: attachmentItemClasses, children: [
|
|
2582
|
+
entry.status === "ready" && entry.input.mediaType.startsWith("image/") && /* @__PURE__ */ jsx17("img", { className: attachmentMediaClasses, src: `data:${entry.input.mediaType};base64,${entry.input.data}`, alt: entry.file.name }),
|
|
2583
|
+
entry.status === "ready" && entry.input.mediaType.startsWith("video/") && /* @__PURE__ */ jsx17("video", { className: attachmentMediaClasses, controls: true, preload: "metadata", "aria-label": entry.file.name, src: `data:${entry.input.mediaType};base64,${entry.input.data}` }),
|
|
2584
|
+
/* @__PURE__ */ jsxs9("div", { className: "qsl:flex qsl:flex-col qsl:gap-1 qsl:p-2 qsl:pr-8 qsl:[overflow-wrap:anywhere]", children: [
|
|
2585
|
+
/* @__PURE__ */ jsx17("span", { className: "qsl:font-medium", title: entry.file.name, children: entry.file.name }),
|
|
2586
|
+
/* @__PURE__ */ jsx17("small", { children: formatAttachmentSize(entry.file.size) }),
|
|
2587
|
+
entry.status === "reading" && /* @__PURE__ */ jsx17("small", { role: "status", children: allTexts.attachmentPreparing }),
|
|
2588
|
+
entry.status === "error" && /* @__PURE__ */ jsx17("small", { role: "alert", children: entry.error })
|
|
2373
2589
|
] }),
|
|
2374
|
-
/* @__PURE__ */
|
|
2590
|
+
/* @__PURE__ */ jsx17(
|
|
2375
2591
|
Button2,
|
|
2376
2592
|
{
|
|
2377
2593
|
"aria-label": fillText(allTexts.removeAttachment, { name: entry.file.name }),
|
|
@@ -2385,16 +2601,16 @@ function ChatInputToolbar({
|
|
|
2385
2601
|
size: "icon-sm",
|
|
2386
2602
|
title: fillText(allTexts.removeAttachment, { name: entry.file.name }),
|
|
2387
2603
|
variant: "outline",
|
|
2388
|
-
children: /* @__PURE__ */
|
|
2604
|
+
children: /* @__PURE__ */ jsx17(XIcon3, {})
|
|
2389
2605
|
}
|
|
2390
2606
|
)
|
|
2391
2607
|
] }, entry.id)) });
|
|
2392
|
-
const errors = /* @__PURE__ */
|
|
2393
|
-
capabilityError && /* @__PURE__ */
|
|
2394
|
-
attachmentError && /* @__PURE__ */
|
|
2395
|
-
sendError && /* @__PURE__ */
|
|
2396
|
-
failedSubmissions.map((failed) => /* @__PURE__ */
|
|
2397
|
-
/* @__PURE__ */
|
|
2608
|
+
const errors = /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2609
|
+
capabilityError && /* @__PURE__ */ jsx17("p", { className: errorClasses, role: "alert", children: capabilityError }),
|
|
2610
|
+
attachmentError && /* @__PURE__ */ jsx17("p", { className: errorClasses, role: "alert", children: attachmentError }),
|
|
2611
|
+
sendError && /* @__PURE__ */ jsx17("p", { className: errorClasses, role: "alert", children: sendError }),
|
|
2612
|
+
failedSubmissions.map((failed) => /* @__PURE__ */ jsxs9("div", { className: cn(errorClasses, "qsl:flex qsl:flex-wrap qsl:items-center qsl:gap-2"), role: "status", children: [
|
|
2613
|
+
/* @__PURE__ */ jsxs9("span", { children: [
|
|
2398
2614
|
allTexts.notSent,
|
|
2399
2615
|
" ",
|
|
2400
2616
|
failed.draft.slice(0, 100),
|
|
@@ -2402,7 +2618,7 @@ function ChatInputToolbar({
|
|
|
2402
2618
|
failed.attachments.length > 0 ? ` ${fillText(allTexts.notSentAttachments, { count: failed.attachments.length })}` : "",
|
|
2403
2619
|
" "
|
|
2404
2620
|
] }),
|
|
2405
|
-
/* @__PURE__ */
|
|
2621
|
+
/* @__PURE__ */ jsx17(Button2, { disabled: disabled || sending, size: "sm", variant: "outline", onClick: () => {
|
|
2406
2622
|
try {
|
|
2407
2623
|
validateAttachmentSelection(attachmentsRef.current.map((entry) => entry.file), failed.attachments.map((entry) => entry.file), allTexts);
|
|
2408
2624
|
} catch (error) {
|
|
@@ -2418,9 +2634,9 @@ function ChatInputToolbar({
|
|
|
2418
2634
|
}, children: allTexts.insertUnsent })
|
|
2419
2635
|
] }, failed.id))
|
|
2420
2636
|
] });
|
|
2421
|
-
const sendButtons = /* @__PURE__ */
|
|
2422
|
-
running2 && onStop && !hasContent && /* @__PURE__ */
|
|
2423
|
-
(!running2 || !onStop || hasContent) && /* @__PURE__ */
|
|
2637
|
+
const sendButtons = /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2638
|
+
running2 && onStop && !hasContent && /* @__PURE__ */ jsx17(StopButton2, { className: "qsl:flex-none", label: allTexts.stop, onClick: onStop, size: "icon-sm" }),
|
|
2639
|
+
(!running2 || !onStop || hasContent) && /* @__PURE__ */ jsx17(
|
|
2424
2640
|
Button2,
|
|
2425
2641
|
{
|
|
2426
2642
|
"aria-label": allTexts.send,
|
|
@@ -2431,53 +2647,62 @@ function ChatInputToolbar({
|
|
|
2431
2647
|
},
|
|
2432
2648
|
size: "icon-sm",
|
|
2433
2649
|
title: running2 ? allTexts.sendIntoRun : allTexts.send,
|
|
2434
|
-
children: /* @__PURE__ */
|
|
2650
|
+
children: /* @__PURE__ */ jsx17(SendIcon2, { size: 14 })
|
|
2435
2651
|
}
|
|
2436
2652
|
)
|
|
2437
2653
|
] });
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2654
|
+
const actionButtons = actions?.map((action, index) => action.active === void 0 ? /* @__PURE__ */ jsxs9(Button2, { "aria-label": action.label ?? action.title, disabled: action.disabled, onClick: action.onClick, size: "sm", title: action.title ?? action.label, variant: "ghost", children: [
|
|
2655
|
+
action.icon,
|
|
2656
|
+
action.label && /* @__PURE__ */ jsx17("span", { className: action.icon ? "qsl:in-data-[compact=true]:hidden" : void 0, children: action.label })
|
|
2657
|
+
] }, index) : /* @__PURE__ */ jsxs9(Toggle2, { "aria-label": action.label ?? action.title, disabled: action.disabled, onPressedChange: () => action.onClick(), pressed: action.active, size: "sm", title: action.title ?? action.label, children: [
|
|
2658
|
+
action.icon,
|
|
2659
|
+
action.label && /* @__PURE__ */ jsx17("span", { className: action.icon ? "qsl:in-data-[compact=true]:hidden" : void 0, children: action.label })
|
|
2660
|
+
] }, index));
|
|
2661
|
+
const attachButton = attachmentsEnabled && /* @__PURE__ */ jsx17(
|
|
2662
|
+
Button2,
|
|
2663
|
+
{
|
|
2664
|
+
"aria-label": allTexts.attachFiles,
|
|
2665
|
+
disabled: disabled || sending,
|
|
2666
|
+
onClick: () => fileInput.inputRef.current?.click(),
|
|
2667
|
+
size: "icon-sm",
|
|
2668
|
+
title: fillText(allTexts.attachFilesHint, { count: MAX_CHAT_ATTACHMENTS, size: maxAttachmentSizeLabel }),
|
|
2669
|
+
variant: "ghost",
|
|
2670
|
+
children: /* @__PURE__ */ jsx17(PaperclipIcon, {})
|
|
2671
|
+
}
|
|
2672
|
+
);
|
|
2673
|
+
const detailToolbar = /* @__PURE__ */ jsxs9("div", { className: toolbarRowClasses, "data-input": "controls", children: [
|
|
2674
|
+
/* @__PURE__ */ jsxs9("div", { className: cn(toolbarSideClasses, "qsl:in-data-[tone=overseer-details]:flex-none", inline || toolbar ? "qsl:flex-none" : "qsl:flex-auto"), children: [
|
|
2675
|
+
attachButton,
|
|
2676
|
+
preparing && /* @__PURE__ */ jsx17("span", { className: cn("qsl:text-small qsl:text-muted-foreground", inline && "qsl:sr-only"), role: "status", children: allTexts.attachmentsPreparing }),
|
|
2677
|
+
actionButtons,
|
|
2460
2678
|
toolbarLeft
|
|
2461
2679
|
] }),
|
|
2462
|
-
/* @__PURE__ */
|
|
2680
|
+
/* @__PURE__ */ jsxs9("div", { className: cn(toolbarSideClasses, "qsl:in-data-[tone=overseer-details]:flex-1", inline || toolbar ? "qsl:flex-none" : "qsl:flex-[0_1_auto]"), children: [
|
|
2463
2681
|
toolbarRight,
|
|
2464
2682
|
!toolbar && sendButtons
|
|
2465
2683
|
] })
|
|
2466
2684
|
] });
|
|
2467
|
-
const details = /* @__PURE__ */
|
|
2685
|
+
const details = /* @__PURE__ */ jsxs9("div", { className: "qsl:min-w-0", "data-compact": compact, "data-quassel": "", children: [
|
|
2468
2686
|
attachmentPreviews,
|
|
2469
2687
|
errors,
|
|
2470
2688
|
detailToolbar
|
|
2471
2689
|
] });
|
|
2472
|
-
const input = /* @__PURE__ */
|
|
2690
|
+
const input = /* @__PURE__ */ jsx17(
|
|
2473
2691
|
"textarea",
|
|
2474
2692
|
{
|
|
2475
2693
|
"aria-controls": inputAriaControls,
|
|
2476
2694
|
className: textareaClasses,
|
|
2477
2695
|
"aria-label": allTexts.placeholder,
|
|
2478
|
-
disabled: !toolbar && disabled,
|
|
2696
|
+
disabled: !toolbar && (disabled || microphoneBusy),
|
|
2697
|
+
hidden: replacingInput,
|
|
2479
2698
|
readOnly: toolbar && disabled,
|
|
2480
2699
|
onChange: (event) => changeDraft(event.target.value),
|
|
2700
|
+
onCompositionStart: () => {
|
|
2701
|
+
composing.current = true;
|
|
2702
|
+
},
|
|
2703
|
+
onCompositionEnd: () => {
|
|
2704
|
+
composing.current = false;
|
|
2705
|
+
},
|
|
2481
2706
|
onKeyDown,
|
|
2482
2707
|
placeholder: running2 ? allTexts.steeringPlaceholder : allTexts.placeholder,
|
|
2483
2708
|
ref: textareaRef,
|
|
@@ -2485,7 +2710,7 @@ function ChatInputToolbar({
|
|
|
2485
2710
|
value: draft
|
|
2486
2711
|
}
|
|
2487
2712
|
);
|
|
2488
|
-
return /* @__PURE__ */
|
|
2713
|
+
return /* @__PURE__ */ jsxs9(
|
|
2489
2714
|
"div",
|
|
2490
2715
|
{
|
|
2491
2716
|
className: rootClasses,
|
|
@@ -2496,7 +2721,7 @@ function ChatInputToolbar({
|
|
|
2496
2721
|
ref: rootRef,
|
|
2497
2722
|
...attachmentsEnabled ? fileInput.dropProps : {},
|
|
2498
2723
|
children: [
|
|
2499
|
-
attachmentsEnabled && /* @__PURE__ */
|
|
2724
|
+
attachmentsEnabled && /* @__PURE__ */ jsx17(
|
|
2500
2725
|
"input",
|
|
2501
2726
|
{
|
|
2502
2727
|
"aria-label": allTexts.attachFiles,
|
|
@@ -2507,17 +2732,48 @@ function ChatInputToolbar({
|
|
|
2507
2732
|
}
|
|
2508
2733
|
),
|
|
2509
2734
|
!toolbar && attachmentPreviews,
|
|
2510
|
-
|
|
2735
|
+
pill ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2511
2736
|
errors,
|
|
2512
|
-
/* @__PURE__ */
|
|
2737
|
+
preparing && /* @__PURE__ */ jsx17("span", { className: "qsl:sr-only", role: "status", children: allTexts.attachmentsPreparing }),
|
|
2738
|
+
/* @__PURE__ */ jsxs9("div", { className: "qsl:pill-row", "data-input": "pill", children: [
|
|
2739
|
+
(actionButtons?.length || toolbarLeft) && /* @__PURE__ */ jsxs9("div", { className: "qsl:pill-slot", "data-input": "left", children: [
|
|
2740
|
+
actionButtons,
|
|
2741
|
+
toolbarLeft
|
|
2742
|
+
] }),
|
|
2743
|
+
input,
|
|
2744
|
+
replacingInput && /* @__PURE__ */ jsx17("div", { className: "qsl:pill-replacement", "data-input": "replacement", children: replaceInput }),
|
|
2745
|
+
(toolbarRight || attachmentsEnabled) && /* @__PURE__ */ jsxs9("div", { className: "qsl:pill-slot", "data-input": "right", children: [
|
|
2746
|
+
toolbarRight,
|
|
2747
|
+
attachButton
|
|
2748
|
+
] }),
|
|
2749
|
+
/* @__PURE__ */ jsx17(
|
|
2750
|
+
ComposerPrimaryAction,
|
|
2751
|
+
{
|
|
2752
|
+
disabled,
|
|
2753
|
+
hasContent,
|
|
2754
|
+
microphone,
|
|
2755
|
+
onSend: () => {
|
|
2756
|
+
void send();
|
|
2757
|
+
},
|
|
2758
|
+
onStop,
|
|
2759
|
+
running: running2,
|
|
2760
|
+
sendDisabled: sendDisabled || attachmentBlocked || !!capabilityError || replacingInput,
|
|
2761
|
+
sending,
|
|
2762
|
+
texts: allTexts
|
|
2763
|
+
}
|
|
2764
|
+
)
|
|
2765
|
+
] })
|
|
2766
|
+
] }) : inline ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2767
|
+
errors,
|
|
2768
|
+
/* @__PURE__ */ jsxs9("div", { className: "qsl:flex qsl:min-w-0 qsl:items-end", children: [
|
|
2513
2769
|
input,
|
|
2514
2770
|
detailToolbar
|
|
2515
2771
|
] })
|
|
2516
2772
|
] }) : input,
|
|
2517
|
-
toolbar ? /* @__PURE__ */
|
|
2518
|
-
/* @__PURE__ */
|
|
2519
|
-
detailsContainer &&
|
|
2520
|
-
] }) : !inline && /* @__PURE__ */
|
|
2773
|
+
toolbar ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2774
|
+
/* @__PURE__ */ jsx17("div", { className: "qsl:flex qsl:flex-none qsl:items-center qsl:gap-1 qsl:p-1", children: sendButtons }),
|
|
2775
|
+
detailsContainer && createPortal3(details, detailsContainer)
|
|
2776
|
+
] }) : !inline && !pill && /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2521
2777
|
errors,
|
|
2522
2778
|
detailToolbar
|
|
2523
2779
|
] })
|
|
@@ -2528,7 +2784,7 @@ function ChatInputToolbar({
|
|
|
2528
2784
|
|
|
2529
2785
|
// packages/quassel/src/DetailModeSwitch.tsx
|
|
2530
2786
|
import { CircleDotIcon, EyeOffIcon, ListCollapseIcon, ListIcon, ShapesIcon, TagsIcon, TextAlignJustifyIcon } from "lucide-react";
|
|
2531
|
-
import { jsx as
|
|
2787
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
2532
2788
|
var DETAIL_MODES = ["off", "current", "icons", "chips", "grouped", "compact", "full"];
|
|
2533
2789
|
var TEXT_KEYS = {
|
|
2534
2790
|
off: "detailModeOff",
|
|
@@ -2562,18 +2818,18 @@ function DetailModeSwitch({
|
|
|
2562
2818
|
const next2 = modes[(current < 0 ? 0 : current + 1) % modes.length];
|
|
2563
2819
|
const Icon = ICONS[mode];
|
|
2564
2820
|
const title = `${allTexts.detailModeTitle}: ${detailModeLabel(mode, texts)}`;
|
|
2565
|
-
return /* @__PURE__ */
|
|
2821
|
+
return /* @__PURE__ */ jsx18(Button2, { "aria-label": title, className, onClick: () => onChange(next2), size: "icon-sm", title, variant: "ghost", children: /* @__PURE__ */ jsx18(Icon, {}) });
|
|
2566
2822
|
}
|
|
2567
2823
|
|
|
2568
2824
|
// packages/quassel/src/TranscriptModeSwitch.tsx
|
|
2569
2825
|
import { MessagesSquareIcon, MessageSquareIcon } from "lucide-react";
|
|
2570
|
-
import { jsx as
|
|
2826
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
2571
2827
|
function TranscriptModeSwitch({ mode, onChange, texts, className }) {
|
|
2572
2828
|
const labels = { ...defaultTexts, ...texts };
|
|
2573
2829
|
const { Button: Button2 } = useQuasselComponents();
|
|
2574
2830
|
const latest = mode === "latest";
|
|
2575
2831
|
const title = latest ? labels.showAllMessages : labels.showLatestExchange;
|
|
2576
|
-
return /* @__PURE__ */
|
|
2832
|
+
return /* @__PURE__ */ jsx19(
|
|
2577
2833
|
Button2,
|
|
2578
2834
|
{
|
|
2579
2835
|
"aria-label": title,
|
|
@@ -2583,19 +2839,19 @@ function TranscriptModeSwitch({ mode, onChange, texts, className }) {
|
|
|
2583
2839
|
size: "icon-sm",
|
|
2584
2840
|
title,
|
|
2585
2841
|
variant: "ghost",
|
|
2586
|
-
children: latest ? /* @__PURE__ */
|
|
2842
|
+
children: latest ? /* @__PURE__ */ jsx19(MessageSquareIcon, {}) : /* @__PURE__ */ jsx19(MessagesSquareIcon, {})
|
|
2587
2843
|
}
|
|
2588
2844
|
);
|
|
2589
2845
|
}
|
|
2590
2846
|
|
|
2591
2847
|
// packages/quassel/src/TimestampSwitch.tsx
|
|
2592
2848
|
import { ClockFadingIcon, ClockIcon } from "lucide-react";
|
|
2593
|
-
import { jsx as
|
|
2849
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2594
2850
|
function TimestampSwitch({ showTimestamps, onChange, texts, className }) {
|
|
2595
2851
|
const labels = { ...defaultTexts, ...texts };
|
|
2596
2852
|
const { Button: Button2 } = useQuasselComponents();
|
|
2597
2853
|
const title = showTimestamps ? labels.hideTimestamps : labels.showTimestamps;
|
|
2598
|
-
return /* @__PURE__ */
|
|
2854
|
+
return /* @__PURE__ */ jsx20(
|
|
2599
2855
|
Button2,
|
|
2600
2856
|
{
|
|
2601
2857
|
"aria-label": title,
|
|
@@ -2605,7 +2861,7 @@ function TimestampSwitch({ showTimestamps, onChange, texts, className }) {
|
|
|
2605
2861
|
size: "icon-sm",
|
|
2606
2862
|
title,
|
|
2607
2863
|
variant: "ghost",
|
|
2608
|
-
children: showTimestamps ? /* @__PURE__ */
|
|
2864
|
+
children: showTimestamps ? /* @__PURE__ */ jsx20(ClockIcon, {}) : /* @__PURE__ */ jsx20(ClockFadingIcon, {})
|
|
2609
2865
|
}
|
|
2610
2866
|
);
|
|
2611
2867
|
}
|