@dust-tt/sparkle 0.2.617-rc-1 → 0.2.618-rc-1
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/cjs/index.js +1 -1
- package/dist/esm/components/Avatar.d.ts +1 -1
- package/dist/esm/components/Avatar.js +4 -4
- package/dist/esm/components/Avatar.js.map +1 -1
- package/dist/esm/components/Button.d.ts +3 -0
- package/dist/esm/components/Button.d.ts.map +1 -1
- package/dist/esm/components/Button.js +21 -10
- package/dist/esm/components/Button.js.map +1 -1
- package/dist/esm/components/Card.d.ts +1 -0
- package/dist/esm/components/Card.d.ts.map +1 -1
- package/dist/esm/components/ConversationMessage.d.ts +4 -0
- package/dist/esm/components/ConversationMessage.d.ts.map +1 -1
- package/dist/esm/components/ConversationMessage.js +9 -4
- package/dist/esm/components/ConversationMessage.js.map +1 -1
- package/dist/esm/components/DataTable.d.ts.map +1 -1
- package/dist/esm/components/DataTable.js +12 -50
- package/dist/esm/components/DataTable.js.map +1 -1
- package/dist/esm/components/Input.d.ts.map +1 -1
- package/dist/esm/components/Input.js +6 -2
- package/dist/esm/components/Input.js.map +1 -1
- package/dist/esm/components/NavigationList.d.ts +4 -1
- package/dist/esm/components/NavigationList.d.ts.map +1 -1
- package/dist/esm/components/NavigationList.js +2 -2
- package/dist/esm/components/NavigationList.js.map +1 -1
- package/dist/esm/components/ScrollArea.d.ts +1 -0
- package/dist/esm/components/ScrollArea.d.ts.map +1 -1
- package/dist/esm/components/ScrollArea.js +7 -4
- package/dist/esm/components/ScrollArea.js.map +1 -1
- package/dist/esm/components/Spinner.d.ts +1 -1
- package/dist/esm/components/Spinner.js +7 -7
- package/dist/esm/components/Spinner.js.map +1 -1
- package/dist/esm/components/TextArea.d.ts.map +1 -1
- package/dist/esm/components/TextArea.js +7 -3
- package/dist/esm/components/TextArea.js.map +1 -1
- package/dist/esm/components/ToolCard.d.ts +6 -0
- package/dist/esm/components/ToolCard.d.ts.map +1 -1
- package/dist/esm/components/ToolCard.js +18 -11
- package/dist/esm/components/ToolCard.js.map +1 -1
- package/dist/esm/components/Tooltip.d.ts.map +1 -1
- package/dist/esm/components/Tooltip.js.map +1 -1
- package/dist/esm/components/WindowUtility.d.ts +3 -2
- package/dist/esm/components/WindowUtility.d.ts.map +1 -1
- package/dist/esm/components/WindowUtility.js +25 -17
- package/dist/esm/components/WindowUtility.js.map +1 -1
- package/dist/esm/components/markdown/CodeBlock.d.ts +2 -1
- package/dist/esm/components/markdown/CodeBlock.d.ts.map +1 -1
- package/dist/esm/components/markdown/CodeBlock.js +9 -2
- package/dist/esm/components/markdown/CodeBlock.js.map +1 -1
- package/dist/esm/icons/app/Mic.d.ts +5 -0
- package/dist/esm/icons/app/Mic.d.ts.map +1 -0
- package/dist/esm/icons/app/Mic.js +6 -0
- package/dist/esm/icons/app/Mic.js.map +1 -0
- package/dist/esm/icons/app/index.d.ts +1 -0
- package/dist/esm/icons/app/index.d.ts.map +1 -1
- package/dist/esm/icons/app/index.js +1 -0
- package/dist/esm/icons/app/index.js.map +1 -1
- package/dist/esm/icons/src/app/mic.svg +3 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/stories/Avatar.stories.js +4 -4
- package/dist/esm/stories/CodeBlock.stories.d.ts +17 -0
- package/dist/esm/stories/CodeBlock.stories.d.ts.map +1 -0
- package/dist/esm/stories/CodeBlock.stories.js +125 -0
- package/dist/esm/stories/CodeBlock.stories.js.map +1 -0
- package/dist/esm/stories/ConversationMessage.stories.d.ts.map +1 -1
- package/dist/esm/stories/ConversationMessage.stories.js +3 -3
- package/dist/esm/stories/ConversationMessage.stories.js.map +1 -1
- package/dist/esm/stories/MultiPageDialog.stories.js +1 -1
- package/dist/esm/stories/MultiPageDialog.stories.js.map +1 -1
- package/dist/esm/stories/Playground.stories.d.ts.map +1 -1
- package/dist/esm/stories/Playground.stories.js +166 -29
- package/dist/esm/stories/Playground.stories.js.map +1 -1
- package/dist/esm/stories/Spinner.stories.js +3 -3
- package/dist/esm/stories/ToolCard.stories.d.ts.map +1 -1
- package/dist/esm/stories/ToolCard.stories.js +14 -6
- package/dist/esm/stories/ToolCard.stories.js.map +1 -1
- package/dist/sparkle.css +100 -0
- package/package.json +1 -1
- package/src/components/Avatar.tsx +4 -4
- package/src/components/Button.tsx +35 -7
- package/src/components/ConversationMessage.tsx +26 -7
- package/src/components/DataTable.tsx +7 -46
- package/src/components/Input.tsx +5 -2
- package/src/components/NavigationList.tsx +7 -2
- package/src/components/ScrollArea.tsx +9 -3
- package/src/components/Spinner.tsx +7 -7
- package/src/components/TextArea.tsx +7 -4
- package/src/components/ToolCard.tsx +60 -35
- package/src/components/Tooltip.tsx +49 -38
- package/src/components/WindowUtility.tsx +11 -18
- package/src/components/markdown/CodeBlock.tsx +10 -0
- package/src/icons/app/Mic.tsx +18 -0
- package/src/icons/app/index.ts +1 -0
- package/src/icons/src/app/mic.svg +3 -0
- package/src/index.ts +1 -0
- package/src/stories/Avatar.stories.tsx +4 -4
- package/src/stories/CodeBlock.stories.tsx +361 -0
- package/src/stories/ConversationMessage.stories.tsx +6 -0
- package/src/stories/MultiPageDialog.stories.tsx +1 -1
- package/src/stories/Playground.stories.tsx +311 -56
- package/src/stories/Spinner.stories.tsx +3 -3
- package/src/stories/ToolCard.stories.tsx +49 -35
|
@@ -35,8 +35,10 @@ interface ConversationMessageProps
|
|
|
35
35
|
citations?: React.ReactElement[];
|
|
36
36
|
isDisabled?: boolean;
|
|
37
37
|
name?: string;
|
|
38
|
+
timestamp?: string;
|
|
38
39
|
pictureUrl?: string | React.ReactNode | null;
|
|
39
40
|
renderName?: (name: string | null) => React.ReactNode;
|
|
41
|
+
infoChip?: React.ReactNode;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
const messageVariants = cva("s-flex s-w-full s-flex-col s-rounded-2xl", {
|
|
@@ -81,8 +83,10 @@ export const ConversationMessage = React.forwardRef<
|
|
|
81
83
|
citations,
|
|
82
84
|
isDisabled = false,
|
|
83
85
|
name,
|
|
86
|
+
timestamp,
|
|
84
87
|
pictureUrl,
|
|
85
88
|
renderName = (name) => <span>{name}</span>,
|
|
89
|
+
infoChip,
|
|
86
90
|
type,
|
|
87
91
|
className,
|
|
88
92
|
...props
|
|
@@ -95,9 +99,11 @@ export const ConversationMessage = React.forwardRef<
|
|
|
95
99
|
<ConversationMessageHeader
|
|
96
100
|
avatarUrl={pictureUrl}
|
|
97
101
|
name={name}
|
|
102
|
+
timestamp={timestamp}
|
|
98
103
|
isBusy={avatarBusy}
|
|
99
104
|
isDisabled={isDisabled}
|
|
100
105
|
renderName={renderName}
|
|
106
|
+
infoChip={infoChip}
|
|
101
107
|
/>
|
|
102
108
|
|
|
103
109
|
<ConversationMessageContent citations={citations}>
|
|
@@ -158,6 +164,8 @@ interface ConversationMessageHeaderProps
|
|
|
158
164
|
isBusy?: boolean;
|
|
159
165
|
isDisabled?: boolean;
|
|
160
166
|
name?: string;
|
|
167
|
+
timestamp?: string;
|
|
168
|
+
infoChip?: React.ReactNode;
|
|
161
169
|
renderName: (name: string | null) => React.ReactNode;
|
|
162
170
|
}
|
|
163
171
|
|
|
@@ -171,6 +179,8 @@ export const ConversationMessageHeader = React.forwardRef<
|
|
|
171
179
|
isBusy,
|
|
172
180
|
isDisabled,
|
|
173
181
|
name = "",
|
|
182
|
+
timestamp,
|
|
183
|
+
infoChip,
|
|
174
184
|
renderName,
|
|
175
185
|
className,
|
|
176
186
|
...props
|
|
@@ -202,13 +212,22 @@ export const ConversationMessageHeader = React.forwardRef<
|
|
|
202
212
|
disabled={isDisabled}
|
|
203
213
|
size="sm"
|
|
204
214
|
/>
|
|
205
|
-
<div
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
<div className="s-flex s-w-full s-flex-row s-justify-between s-gap-0.5">
|
|
216
|
+
<div
|
|
217
|
+
className={cn(
|
|
218
|
+
"s-text-sm s-font-semibold @sm:s-text-base",
|
|
219
|
+
"s-text-foreground dark:s-text-foreground-night",
|
|
220
|
+
"s-flex s-flex-row s-items-center s-gap-2"
|
|
221
|
+
)}
|
|
222
|
+
>
|
|
223
|
+
{renderName(name)}
|
|
224
|
+
{infoChip}
|
|
225
|
+
</div>
|
|
226
|
+
<div>
|
|
227
|
+
<span className="s-text-xs s-font-normal s-text-muted-foreground dark:s-text-muted-foreground-night">
|
|
228
|
+
{timestamp}
|
|
229
|
+
</span>
|
|
230
|
+
</div>
|
|
212
231
|
</div>
|
|
213
232
|
</div>
|
|
214
233
|
);
|
|
@@ -15,13 +15,7 @@ import {
|
|
|
15
15
|
useReactTable,
|
|
16
16
|
} from "@tanstack/react-table";
|
|
17
17
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
18
|
-
import React, {
|
|
19
|
-
ReactNode,
|
|
20
|
-
useEffect,
|
|
21
|
-
useLayoutEffect,
|
|
22
|
-
useRef,
|
|
23
|
-
useState,
|
|
24
|
-
} from "react";
|
|
18
|
+
import React, { ReactNode, useEffect, useRef, useState } from "react";
|
|
25
19
|
|
|
26
20
|
import {
|
|
27
21
|
Avatar,
|
|
@@ -345,24 +339,6 @@ export interface ScrollableDataTableProps<TData extends TBaseData>
|
|
|
345
339
|
const COLUMN_HEIGHT = 48;
|
|
346
340
|
const MIN_COLUMN_WIDTH = 40;
|
|
347
341
|
|
|
348
|
-
// Helper function to compare column sizing objects
|
|
349
|
-
function shallowEqualSizing(
|
|
350
|
-
a: Record<string, number>,
|
|
351
|
-
b: Record<string, number>
|
|
352
|
-
) {
|
|
353
|
-
const aKeys = Object.keys(a);
|
|
354
|
-
const bKeys = Object.keys(b);
|
|
355
|
-
if (aKeys.length !== bKeys.length) {
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
358
|
-
for (const k of aKeys) {
|
|
359
|
-
if (a[k] !== b[k]) {
|
|
360
|
-
return false;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
return true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
342
|
export function ScrollableDataTable<TData extends TBaseData>({
|
|
367
343
|
data,
|
|
368
344
|
totalRowCount,
|
|
@@ -384,7 +360,7 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
384
360
|
const loadMoreRef = useRef<HTMLDivElement>(null);
|
|
385
361
|
const [tableWidth, setTableWidth] = useState(0);
|
|
386
362
|
|
|
387
|
-
// Monitor table width changes
|
|
363
|
+
// Monitor table width changes
|
|
388
364
|
useEffect(() => {
|
|
389
365
|
if (!tableContainerRef.current) {
|
|
390
366
|
return;
|
|
@@ -392,8 +368,7 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
392
368
|
|
|
393
369
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
394
370
|
for (const entry of entries) {
|
|
395
|
-
|
|
396
|
-
setTableWidth((prev) => (prev !== w ? w : prev)); // update only on real change
|
|
371
|
+
setTableWidth(entry.contentRect.width);
|
|
397
372
|
}
|
|
398
373
|
});
|
|
399
374
|
|
|
@@ -430,20 +405,12 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
430
405
|
getRowId,
|
|
431
406
|
});
|
|
432
407
|
|
|
433
|
-
|
|
408
|
+
useEffect(() => {
|
|
434
409
|
if (!tableContainerRef.current || !table || !tableWidth) {
|
|
435
410
|
return;
|
|
436
411
|
}
|
|
437
412
|
const columns = table.getAllColumns();
|
|
438
413
|
|
|
439
|
-
// Skip sizing if no columns have ratios defined
|
|
440
|
-
const hasRatios = columns.some(
|
|
441
|
-
(c) => (c.columnDef.meta?.sizeRatio ?? 0) > 0
|
|
442
|
-
);
|
|
443
|
-
if (!hasRatios) {
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
414
|
// Calculate ideal widths and handle minimums
|
|
448
415
|
const idealSizing = columns.reduce(
|
|
449
416
|
(acc, column) => {
|
|
@@ -452,8 +419,7 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
452
419
|
Math.floor((ratio / 100) * tableWidth),
|
|
453
420
|
MIN_COLUMN_WIDTH
|
|
454
421
|
);
|
|
455
|
-
acc[column.id]
|
|
456
|
-
return acc;
|
|
422
|
+
return { ...acc, [column.id]: calculated };
|
|
457
423
|
},
|
|
458
424
|
{} as Record<string, number>
|
|
459
425
|
);
|
|
@@ -473,13 +439,8 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
473
439
|
|
|
474
440
|
idealSizing[adjustColumnId] += widthDifference;
|
|
475
441
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const currentSizing = table.getState().columnSizing;
|
|
479
|
-
if (!shallowEqualSizing(idealSizing, currentSizing)) {
|
|
480
|
-
table.setColumnSizing(idealSizing);
|
|
481
|
-
}
|
|
482
|
-
}, [tableWidth]); // intentionally remove `table` from deps
|
|
442
|
+
table.setColumnSizing(idealSizing);
|
|
443
|
+
}, [table, tableWidth]);
|
|
483
444
|
|
|
484
445
|
// Get the current column sizing from the table for rendering
|
|
485
446
|
const columnSizing = table.getState().columnSizing;
|
package/src/components/Input.tsx
CHANGED
|
@@ -42,7 +42,9 @@ const stateVariantStyles: Record<InputStateType, string> = {
|
|
|
42
42
|
disabled: cn(
|
|
43
43
|
"disabled:s-cursor-not-allowed",
|
|
44
44
|
"disabled:s-text-muted-foreground dark:disabled:s-text-muted-foreground-night",
|
|
45
|
-
"disabled:s-border-border dark:disabled:s-border-border-night"
|
|
45
|
+
"disabled:s-border-border dark:disabled:s-border-border-night",
|
|
46
|
+
// Use muted background only when disabled
|
|
47
|
+
"s-bg-muted-background dark:s-bg-muted-background-night"
|
|
46
48
|
),
|
|
47
49
|
error: cn(
|
|
48
50
|
"s-border-border-warning/40 dark:s-border-border-warning-night/60",
|
|
@@ -66,7 +68,8 @@ const inputStyleClasses = cva(
|
|
|
66
68
|
cn(
|
|
67
69
|
"dark:s-text-primary-50",
|
|
68
70
|
"s-text-sm s-rounded-xl s-flex s-h-9 s-w-full s-px-3 s-py-1.5 ",
|
|
69
|
-
|
|
71
|
+
// Default to plain background; disabled state will override to muted
|
|
72
|
+
"s-bg-background dark:s-bg-background-night",
|
|
70
73
|
"s-border focus-visible:s-ring",
|
|
71
74
|
"file:s-border-0 file:s-bg-transparent file:s-text-sm file:s-font-medium file:s-text-foreground",
|
|
72
75
|
"placeholder:s-text-muted-foreground placeholder:s-italic dark:placeholder:s-text-muted-foreground-night"
|
|
@@ -41,13 +41,18 @@ const NavigationListItemStyles = cva(
|
|
|
41
41
|
}
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
+
interface NavigationListProps {
|
|
45
|
+
viewportRef?: React.RefObject<HTMLDivElement>;
|
|
46
|
+
}
|
|
44
47
|
const NavigationList = React.forwardRef<
|
|
45
48
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
|
46
|
-
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
|
47
|
-
|
|
49
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> &
|
|
50
|
+
NavigationListProps
|
|
51
|
+
>(({ className, children, viewportRef, ...props }, ref) => {
|
|
48
52
|
return (
|
|
49
53
|
<ScrollArea
|
|
50
54
|
ref={ref}
|
|
55
|
+
viewportRef={viewportRef}
|
|
51
56
|
className={cn(className, "s-transition-all s-duration-300")}
|
|
52
57
|
{...props}
|
|
53
58
|
>
|
|
@@ -14,6 +14,7 @@ interface ScrollAreaProps
|
|
|
14
14
|
active?: string;
|
|
15
15
|
inactive?: string;
|
|
16
16
|
};
|
|
17
|
+
viewportRef?: React.RefObject<HTMLDivElement>;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
const ScrollArea = React.forwardRef<
|
|
@@ -29,11 +30,12 @@ const ScrollArea = React.forwardRef<
|
|
|
29
30
|
scrollBarClassName,
|
|
30
31
|
viewportClassName,
|
|
31
32
|
scrollStyles,
|
|
33
|
+
viewportRef,
|
|
32
34
|
...props
|
|
33
35
|
},
|
|
34
36
|
ref
|
|
35
37
|
) => {
|
|
36
|
-
const
|
|
38
|
+
const localViewportRef = React.useRef<HTMLDivElement>(null);
|
|
37
39
|
const [isScrolled, setIsScrolled] = React.useState(false);
|
|
38
40
|
|
|
39
41
|
const hasCustomScrollBar = useMemo(
|
|
@@ -50,9 +52,13 @@ const ScrollArea = React.forwardRef<
|
|
|
50
52
|
const shouldHideDefaultScrollBar = hideScrollBar || hasCustomScrollBar;
|
|
51
53
|
|
|
52
54
|
const handleScroll = React.useCallback(() => {
|
|
53
|
-
if (viewportRef.current) {
|
|
55
|
+
if (viewportRef && viewportRef.current) {
|
|
54
56
|
setIsScrolled(viewportRef.current.scrollTop > 0);
|
|
55
57
|
}
|
|
58
|
+
|
|
59
|
+
if (localViewportRef.current) {
|
|
60
|
+
setIsScrolled(localViewportRef.current.scrollTop > 0);
|
|
61
|
+
}
|
|
56
62
|
}, []);
|
|
57
63
|
|
|
58
64
|
return (
|
|
@@ -66,7 +72,7 @@ const ScrollArea = React.forwardRef<
|
|
|
66
72
|
{...props}
|
|
67
73
|
>
|
|
68
74
|
<ScrollAreaPrimitive.Viewport
|
|
69
|
-
ref={viewportRef}
|
|
75
|
+
ref={viewportRef || localViewportRef}
|
|
70
76
|
onScroll={handleScroll}
|
|
71
77
|
className={cn(
|
|
72
78
|
"s-h-full s-w-full s-rounded-[inherit]",
|
|
@@ -13,7 +13,7 @@ import animLightLG from "@sparkle/lottie/spinnerLightLG";
|
|
|
13
13
|
import animLightXS from "@sparkle/lottie/spinnerLightXS";
|
|
14
14
|
|
|
15
15
|
type SpinnerSizeType = (typeof SPINNER_SIZES)[number];
|
|
16
|
-
const SPINNER_SIZES = ["xs", "sm", "md", "lg", "xl", "
|
|
16
|
+
const SPINNER_SIZES = ["xs", "sm", "md", "lg", "xl", "2xl"] as const;
|
|
17
17
|
|
|
18
18
|
type SpinnerVariant =
|
|
19
19
|
| "mono"
|
|
@@ -43,7 +43,7 @@ const pxSizeClasses: Record<SpinnerSizeType, string> = {
|
|
|
43
43
|
md: "24",
|
|
44
44
|
lg: "32",
|
|
45
45
|
xl: "128",
|
|
46
|
-
|
|
46
|
+
"2xl": "192",
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
type LottieColorType = [number, number, number, number];
|
|
@@ -111,7 +111,7 @@ const Spinner: React.FC<SpinnerProps> = ({ size = "md", variant = "mono" }) => {
|
|
|
111
111
|
anim = animLightXS;
|
|
112
112
|
break;
|
|
113
113
|
case "xl":
|
|
114
|
-
case "
|
|
114
|
+
case "2xl":
|
|
115
115
|
anim = animLightLG;
|
|
116
116
|
break;
|
|
117
117
|
default:
|
|
@@ -139,7 +139,7 @@ const Spinner: React.FC<SpinnerProps> = ({ size = "md", variant = "mono" }) => {
|
|
|
139
139
|
anim = animColorXS;
|
|
140
140
|
break;
|
|
141
141
|
case "xl":
|
|
142
|
-
case "
|
|
142
|
+
case "2xl":
|
|
143
143
|
anim = animColorLG;
|
|
144
144
|
break;
|
|
145
145
|
default:
|
|
@@ -162,7 +162,7 @@ const Spinner: React.FC<SpinnerProps> = ({ size = "md", variant = "mono" }) => {
|
|
|
162
162
|
anim = animLightXS;
|
|
163
163
|
break;
|
|
164
164
|
case "xl":
|
|
165
|
-
case "
|
|
165
|
+
case "2xl":
|
|
166
166
|
anim = animLightLG;
|
|
167
167
|
break;
|
|
168
168
|
default:
|
|
@@ -185,7 +185,7 @@ const Spinner: React.FC<SpinnerProps> = ({ size = "md", variant = "mono" }) => {
|
|
|
185
185
|
anim = animDarkXS;
|
|
186
186
|
break;
|
|
187
187
|
case "xl":
|
|
188
|
-
case "
|
|
188
|
+
case "2xl":
|
|
189
189
|
anim = animDarkLG;
|
|
190
190
|
break;
|
|
191
191
|
default:
|
|
@@ -210,7 +210,7 @@ const Spinner: React.FC<SpinnerProps> = ({ size = "md", variant = "mono" }) => {
|
|
|
210
210
|
darkAnim = animDarkXS;
|
|
211
211
|
break;
|
|
212
212
|
case "xl":
|
|
213
|
-
case "
|
|
213
|
+
case "2xl":
|
|
214
214
|
lightAnim = animLightLG;
|
|
215
215
|
darkAnim = animDarkLG;
|
|
216
216
|
break;
|
|
@@ -20,7 +20,8 @@ const textAreaVariants = cva(
|
|
|
20
20
|
cn(
|
|
21
21
|
"s-flex s-w-full s-px-3 s-py-2 s-text-sm",
|
|
22
22
|
"s-text-foreground dark:s-text-foreground-night",
|
|
23
|
-
|
|
23
|
+
// Default to plain background; disabled variant will set muted background
|
|
24
|
+
"s-bg-background dark:s-bg-background-night",
|
|
24
25
|
"s-ring-offset-background",
|
|
25
26
|
"s-border s-rounded-xl s-transition s-duration-100 focus-visible:s-outline-none",
|
|
26
27
|
"focus-visible:s-border-border dark:focus-visible:s-border-border-night focus-visible:s-ring"
|
|
@@ -52,7 +53,9 @@ const textAreaVariants = cva(
|
|
|
52
53
|
disabled: {
|
|
53
54
|
true: cn(
|
|
54
55
|
"disabled:s-cursor-not-allowed",
|
|
55
|
-
"disabled:s-text-muted-foreground dark:disabled:s-text-muted-foreground-night"
|
|
56
|
+
"disabled:s-text-muted-foreground dark:disabled:s-text-muted-foreground-night",
|
|
57
|
+
// Use muted background only when disabled
|
|
58
|
+
"s-bg-muted-background dark:s-bg-muted-background-night"
|
|
56
59
|
),
|
|
57
60
|
false: "",
|
|
58
61
|
},
|
|
@@ -117,8 +120,8 @@ const ReadOnlyTextArea = ({ content }: { content: string | null }) => {
|
|
|
117
120
|
isDisplay
|
|
118
121
|
className={cn(
|
|
119
122
|
"s-copy-sm s-h-full s-min-h-60 s-w-full s-min-w-0 s-rounded-xl",
|
|
120
|
-
"s-resize-none s-border-border
|
|
121
|
-
"dark:s-border-border-night
|
|
123
|
+
"s-resize-none s-border-border",
|
|
124
|
+
"dark:s-border-border-night"
|
|
122
125
|
)}
|
|
123
126
|
defaultValue={content ?? ""}
|
|
124
127
|
/>
|
|
@@ -15,10 +15,13 @@ export interface ToolCardProps {
|
|
|
15
15
|
isSelected: boolean;
|
|
16
16
|
canAdd: boolean;
|
|
17
17
|
cantAddReason?: string;
|
|
18
|
+
toolInfo?: { label: string; onClick: () => void };
|
|
18
19
|
onClick?: () => void;
|
|
19
20
|
className?: string;
|
|
21
|
+
cardContainerClassName?: string;
|
|
20
22
|
mountPortal?: boolean;
|
|
21
23
|
mountPortalContainer?: HTMLElement;
|
|
24
|
+
descriptionLineClamp?: number;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export const ToolCard = React.forwardRef<HTMLDivElement, ToolCardProps>(
|
|
@@ -30,10 +33,13 @@ export const ToolCard = React.forwardRef<HTMLDivElement, ToolCardProps>(
|
|
|
30
33
|
isSelected,
|
|
31
34
|
canAdd,
|
|
32
35
|
cantAddReason,
|
|
36
|
+
toolInfo,
|
|
33
37
|
onClick,
|
|
34
38
|
className,
|
|
39
|
+
cardContainerClassName,
|
|
35
40
|
mountPortal,
|
|
36
41
|
mountPortalContainer,
|
|
42
|
+
descriptionLineClamp = 2,
|
|
37
43
|
},
|
|
38
44
|
ref
|
|
39
45
|
) => {
|
|
@@ -43,44 +49,63 @@ export const ToolCard = React.forwardRef<HTMLDivElement, ToolCardProps>(
|
|
|
43
49
|
variant={isSelected ? "secondary" : "primary"}
|
|
44
50
|
onClick={onClick}
|
|
45
51
|
disabled={!canAdd}
|
|
46
|
-
|
|
52
|
+
containerClassName={cardContainerClassName}
|
|
53
|
+
className={cn("s-p-3", className)}
|
|
47
54
|
>
|
|
48
|
-
<div className="s-flex s-w-full s-flex-col">
|
|
49
|
-
<div className="s-
|
|
50
|
-
<div className="s-flex s-items-center s-gap-2">
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{cantAddReason
|
|
55
|
+
<div className="s-flex s-h-full s-w-full s-flex-col s-justify-between">
|
|
56
|
+
<div className="s-flex s-flex-col">
|
|
57
|
+
<div className="s-mb-2 s-flex s-items-center s-justify-between s-gap-2">
|
|
58
|
+
<div className="s-flex s-items-center s-gap-2">
|
|
59
|
+
<Avatar icon={icon} size="sm" />
|
|
60
|
+
<span className="s-text-sm s-font-medium">{label}</span>
|
|
61
|
+
{isSelected && (
|
|
62
|
+
<Chip
|
|
63
|
+
size="xs"
|
|
64
|
+
color="green"
|
|
65
|
+
label="ADDED"
|
|
66
|
+
className={cn(FADE_TRANSITION_CLASSES, "s-opacity-100")}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
<div className="s-flex s-flex-shrink-0 s-items-center s-gap-2">
|
|
71
|
+
{canAdd && (
|
|
72
|
+
<Button
|
|
73
|
+
size="xs"
|
|
74
|
+
variant="outline"
|
|
75
|
+
icon={PlusIcon}
|
|
76
|
+
label="Add"
|
|
77
|
+
className={cn(FADE_TRANSITION_CLASSES, "s-flex-shrink-0")}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
{cantAddReason && (
|
|
81
|
+
<div className="s-flex-shrink-0 s-text-xs s-italic s-text-muted-foreground dark:s-text-muted-foreground-night">
|
|
82
|
+
{cantAddReason}
|
|
83
|
+
</div>
|
|
84
|
+
)}
|
|
74
85
|
</div>
|
|
75
|
-
|
|
86
|
+
</div>
|
|
87
|
+
<TruncatedText
|
|
88
|
+
className="s-text-sm s-text-muted-foreground dark:s-text-muted-foreground-night"
|
|
89
|
+
mountPortal={mountPortal}
|
|
90
|
+
mountPortalContainer={mountPortalContainer}
|
|
91
|
+
lineClamp={descriptionLineClamp}
|
|
92
|
+
>
|
|
93
|
+
{description}
|
|
94
|
+
</TruncatedText>
|
|
76
95
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
{toolInfo && (
|
|
97
|
+
<div>
|
|
98
|
+
<a
|
|
99
|
+
onClick={(e) => {
|
|
100
|
+
e.stopPropagation();
|
|
101
|
+
toolInfo.onClick();
|
|
102
|
+
}}
|
|
103
|
+
className="hover:s-underline-offset-2 dark:s-text-muted-foreground-night s-cursor-pointer s-text-sm s-font-semibold s-text-muted-foreground hover:s-text-highlight-light hover:s-underline dark:hover:s-text-highlight-light-night"
|
|
104
|
+
>
|
|
105
|
+
{toolInfo.label}
|
|
106
|
+
</a>
|
|
107
|
+
</div>
|
|
108
|
+
)}
|
|
84
109
|
</div>
|
|
85
110
|
</Card>
|
|
86
111
|
);
|
|
@@ -20,47 +20,58 @@ interface TooltipContentProps
|
|
|
20
20
|
const TooltipContent = React.forwardRef<
|
|
21
21
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
22
22
|
TooltipContentProps
|
|
23
|
-
>(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
sideOffset=
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
>(
|
|
24
|
+
(
|
|
25
|
+
{
|
|
26
|
+
className,
|
|
27
|
+
sideOffset = 4,
|
|
28
|
+
mountPortal = true,
|
|
29
|
+
mountPortalContainer,
|
|
30
|
+
...props
|
|
31
|
+
},
|
|
32
|
+
ref
|
|
33
|
+
) => {
|
|
34
|
+
const content = (
|
|
35
|
+
<TooltipPrimitive.Content
|
|
36
|
+
ref={ref}
|
|
37
|
+
sideOffset={sideOffset}
|
|
38
|
+
className={classNames(
|
|
39
|
+
"s-z-50 s-max-w-sm s-overflow-hidden s-whitespace-pre-wrap s-break-words s-rounded-md s-border",
|
|
40
|
+
"s-bg-background dark:s-bg-background-night",
|
|
41
|
+
"s-text-foreground dark:s-text-foreground-night",
|
|
42
|
+
"s-border-border dark:s-border-border-night",
|
|
43
|
+
"s-px-3 s-py-1.5 s-text-sm s-shadow-md",
|
|
44
|
+
"s-animate-in s-fade-in-0 s-zoom-in-95",
|
|
45
|
+
"data-[state=closed]:s-animate-out data-[state=closed]:s-fade-out-0 data-[state=closed]:s-zoom-out-95 data-[side=bottom]:s-slide-in-from-top-2 data-[side=left]:s-slide-in-from-right-2 data-[side=right]:s-slide-in-from-left-2 data-[side=top]:s-slide-in-from-bottom-2",
|
|
46
|
+
className || ""
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
const [container, setContainer] = useState<Element | undefined>(
|
|
53
|
+
mountPortalContainer
|
|
54
|
+
);
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (mountPortal && !container) {
|
|
58
|
+
const dialogElements = document.querySelectorAll(
|
|
59
|
+
".s-sheet[role=dialog][data-state=open]"
|
|
60
|
+
);
|
|
61
|
+
const defaultContainer = dialogElements[dialogElements.length - 1];
|
|
62
|
+
setContainer(defaultContainer);
|
|
63
|
+
}
|
|
64
|
+
}, [mountPortal, container]);
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
66
|
+
return mountPortal ? (
|
|
67
|
+
<TooltipPrimitive.Portal container={container}>
|
|
68
|
+
{content}
|
|
69
|
+
</TooltipPrimitive.Portal>
|
|
70
|
+
) : (
|
|
71
|
+
content
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
);
|
|
64
75
|
|
|
65
76
|
interface TooltipProps extends TooltipContentProps {
|
|
66
77
|
trigger: React.ReactNode;
|
|
@@ -2,30 +2,25 @@ import { useEffect, useState } from "react";
|
|
|
2
2
|
|
|
3
3
|
// Define breakpoints
|
|
4
4
|
export const breakpoints = {
|
|
5
|
-
|
|
5
|
+
xxs: 0,
|
|
6
|
+
xs: 512,
|
|
6
7
|
sm: 640,
|
|
7
8
|
md: 768,
|
|
8
9
|
lg: 1024,
|
|
9
10
|
xl: 1280,
|
|
10
|
-
|
|
11
|
+
"2xl": 1536,
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
// Helper function to determine active breakpoint
|
|
14
15
|
function getActiveBreakpoint(width: number): keyof typeof breakpoints {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (width >= breakpoints.md) {
|
|
25
|
-
return "md";
|
|
26
|
-
}
|
|
27
|
-
if (width >= breakpoints.sm) {
|
|
28
|
-
return "sm";
|
|
16
|
+
const breakpointEntries = Object.entries(breakpoints) as [keyof typeof breakpoints, number][];
|
|
17
|
+
// Sort breakpoints from largest to smallest
|
|
18
|
+
const sortedBreakpoints = breakpointEntries.sort(([, a], [, b]) => b - a);
|
|
19
|
+
|
|
20
|
+
for (const [breakpoint, minWidth] of sortedBreakpoints) {
|
|
21
|
+
if (width >= minWidth) {
|
|
22
|
+
return breakpoint;
|
|
23
|
+
}
|
|
29
24
|
}
|
|
30
25
|
return "xs";
|
|
31
26
|
}
|
|
@@ -62,5 +57,3 @@ export function useWindowSize() {
|
|
|
62
57
|
|
|
63
58
|
return windowSize;
|
|
64
59
|
}
|
|
65
|
-
|
|
66
|
-
export default useWindowSize;
|