@copilotz/chat-ui 0.9.3 → 0.9.5
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/index.cjs +165 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +165 -95
- package/dist/index.js.map +1 -1
- package/dist/styles.css +0 -33
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1179,6 +1179,7 @@ var Message = (0, import_react2.memo)(({
|
|
|
1179
1179
|
const [isEditing, setIsEditing] = (0, import_react2.useState)(false);
|
|
1180
1180
|
const [editContent, setEditContent] = (0, import_react2.useState)(message.content);
|
|
1181
1181
|
const [showActions, setShowActions] = (0, import_react2.useState)(false);
|
|
1182
|
+
const [actionsFocused, setActionsFocused] = (0, import_react2.useState)(false);
|
|
1182
1183
|
const [copied, setCopied] = (0, import_react2.useState)(false);
|
|
1183
1184
|
const messageIsUser = isUser ?? message.role === "user";
|
|
1184
1185
|
if (!hasRenderableAssistantBody(message)) {
|
|
@@ -1192,7 +1193,6 @@ var Message = (0, import_react2.memo)(({
|
|
|
1192
1193
|
compactMode
|
|
1193
1194
|
});
|
|
1194
1195
|
const canEdit = enableEdit && messageIsUser;
|
|
1195
|
-
const canRegenerate = enableRegenerate && !messageIsUser;
|
|
1196
1196
|
const normalizedPreviewChars = Math.max(longMessagePreviewChars, 1);
|
|
1197
1197
|
const normalizedChunkChars = Math.max(longMessageChunkChars, 1);
|
|
1198
1198
|
const previewOverride = typeof message.metadata?.previewContent === "string" ? message.metadata.previewContent : void 0;
|
|
@@ -1226,9 +1226,6 @@ var Message = (0, import_react2.memo)(({
|
|
|
1226
1226
|
setEditContent(message.content);
|
|
1227
1227
|
setIsEditing(false);
|
|
1228
1228
|
};
|
|
1229
|
-
const handleRegenerate = () => {
|
|
1230
|
-
onAction?.({ action: "regenerate", messageId: message.id });
|
|
1231
|
-
};
|
|
1232
1229
|
const handleToggleExpanded = () => {
|
|
1233
1230
|
onToggleExpanded?.(message.id);
|
|
1234
1231
|
};
|
|
@@ -1244,6 +1241,12 @@ var Message = (0, import_react2.memo)(({
|
|
|
1244
1241
|
className: `flex w-full flex-col ${className} max-w-[800px] mx-auto`,
|
|
1245
1242
|
onMouseEnter: () => setShowActions(true),
|
|
1246
1243
|
onMouseLeave: () => setShowActions(false),
|
|
1244
|
+
onFocusCapture: () => setActionsFocused(true),
|
|
1245
|
+
onBlurCapture: (event) => {
|
|
1246
|
+
if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
1247
|
+
setActionsFocused(false);
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1247
1250
|
children: [
|
|
1248
1251
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `flex gap-3 ${messageIsUser ? "flex-row-reverse" : "flex-row"} w-full mb-1`, children: [
|
|
1249
1252
|
showAvatar && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `flex-shrink-0 ${compactMode ? "mt-1" : "mt-0"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
@@ -1269,8 +1272,8 @@ var Message = (0, import_react2.memo)(({
|
|
|
1269
1272
|
message.isEdited && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Badge, { variant: "outline", className: "text-xs", children: "editado" })
|
|
1270
1273
|
] })
|
|
1271
1274
|
] }),
|
|
1272
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.
|
|
1273
|
-
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `flex-1 min-w-0 ${messageIsUser ? "text-right" : "text-left"} ${horizontalOffsetClass}`, children: [
|
|
1276
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `relative overflow-hidden text-left ${messageIsUser ? "ml-auto inline-flex max-w-[85%] flex-col rounded-lg bg-primary p-3 text-primary-foreground" : "flex w-full max-w-full flex-col"}`, children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-2", children: [
|
|
1274
1277
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1275
1278
|
Textarea,
|
|
1276
1279
|
{
|
|
@@ -1323,49 +1326,44 @@ var Message = (0, import_react2.memo)(({
|
|
|
1323
1326
|
}
|
|
1324
1327
|
) }),
|
|
1325
1328
|
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mt-3 space-y-2", children: message.attachments.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MediaRenderer, { attachment }, index)) })
|
|
1326
|
-
] }),
|
|
1327
|
-
!isEditing && (showActions || copied) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
) }),
|
|
1365
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { children: "Regenerar" })
|
|
1366
|
-
] })
|
|
1367
|
-
] })
|
|
1368
|
-
] }) })
|
|
1329
|
+
] }) }),
|
|
1330
|
+
!isEditing && (showActions || actionsFocused || copied) && (enableCopy || canEdit) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1331
|
+
"div",
|
|
1332
|
+
{
|
|
1333
|
+
className: `mt-1 flex items-center gap-1 text-muted-foreground transition-opacity ${messageIsUser ? "justify-end" : "justify-start"}`,
|
|
1334
|
+
children: [
|
|
1335
|
+
canEdit && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
|
|
1336
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1337
|
+
Button,
|
|
1338
|
+
{
|
|
1339
|
+
type: "button",
|
|
1340
|
+
variant: "ghost",
|
|
1341
|
+
size: "icon",
|
|
1342
|
+
className: "h-7 w-7",
|
|
1343
|
+
onClick: handleEdit,
|
|
1344
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Edit, { className: "h-3.5 w-3.5" })
|
|
1345
|
+
}
|
|
1346
|
+
) }),
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { children: labels?.editMessage || "Edit" })
|
|
1348
|
+
] }),
|
|
1349
|
+
enableCopy && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1351
|
+
Button,
|
|
1352
|
+
{
|
|
1353
|
+
type: "button",
|
|
1354
|
+
variant: "ghost",
|
|
1355
|
+
size: "icon",
|
|
1356
|
+
className: "h-7 w-7",
|
|
1357
|
+
onClick: handleCopy,
|
|
1358
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Check, { className: "h-3.5 w-3.5 text-green-500" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Copy, { className: "h-3.5 w-3.5" })
|
|
1359
|
+
}
|
|
1360
|
+
) }),
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { children: copied ? "Copied" : labels?.copyMessage || "Copy" })
|
|
1362
|
+
] })
|
|
1363
|
+
]
|
|
1364
|
+
}
|
|
1365
|
+
)
|
|
1366
|
+
] })
|
|
1369
1367
|
]
|
|
1370
1368
|
}
|
|
1371
1369
|
);
|
|
@@ -2466,14 +2464,6 @@ var ThreadInitialsIcon = ({ title }) => {
|
|
|
2466
2464
|
const initials = title?.split(" ").map((n) => n[0]).slice(0, 2).join("").toUpperCase() || "?";
|
|
2467
2465
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted text-[10px] font-medium text-muted-foreground", children: initials });
|
|
2468
2466
|
};
|
|
2469
|
-
var TAG_COLOR_CLASSES = [
|
|
2470
|
-
"bg-sky-500",
|
|
2471
|
-
"bg-emerald-500",
|
|
2472
|
-
"bg-violet-500",
|
|
2473
|
-
"bg-amber-500",
|
|
2474
|
-
"bg-rose-500",
|
|
2475
|
-
"bg-cyan-500"
|
|
2476
|
-
];
|
|
2477
2467
|
function slugTagName(name) {
|
|
2478
2468
|
const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
2479
2469
|
return slug || "tag";
|
|
@@ -2505,31 +2495,125 @@ function collectThreadTags(threads) {
|
|
|
2505
2495
|
}
|
|
2506
2496
|
return tags.sort((a, b) => a.name.localeCompare(b.name));
|
|
2507
2497
|
}
|
|
2508
|
-
function
|
|
2498
|
+
function normalizeTagColorKey(tag) {
|
|
2499
|
+
return (tag.name || tag.id || "tag").trim().toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
|
|
2500
|
+
}
|
|
2501
|
+
function hashTagColorKey(value) {
|
|
2509
2502
|
let hash = 0;
|
|
2510
|
-
for (const char of
|
|
2503
|
+
for (const char of value) {
|
|
2511
2504
|
hash = hash * 31 + char.charCodeAt(0) >>> 0;
|
|
2512
2505
|
}
|
|
2513
|
-
return hash
|
|
2506
|
+
return hash;
|
|
2514
2507
|
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2508
|
+
function hslToRgb(hue, saturation, lightness) {
|
|
2509
|
+
const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
|
|
2510
|
+
const x = chroma * (1 - Math.abs(hue / 60 % 2 - 1));
|
|
2511
|
+
const match = lightness - chroma / 2;
|
|
2512
|
+
let red = 0;
|
|
2513
|
+
let green = 0;
|
|
2514
|
+
let blue = 0;
|
|
2515
|
+
if (hue < 60) {
|
|
2516
|
+
red = chroma;
|
|
2517
|
+
green = x;
|
|
2518
|
+
} else if (hue < 120) {
|
|
2519
|
+
red = x;
|
|
2520
|
+
green = chroma;
|
|
2521
|
+
} else if (hue < 180) {
|
|
2522
|
+
green = chroma;
|
|
2523
|
+
blue = x;
|
|
2524
|
+
} else if (hue < 240) {
|
|
2525
|
+
green = x;
|
|
2526
|
+
blue = chroma;
|
|
2527
|
+
} else if (hue < 300) {
|
|
2528
|
+
red = x;
|
|
2529
|
+
blue = chroma;
|
|
2530
|
+
} else {
|
|
2531
|
+
red = chroma;
|
|
2532
|
+
blue = x;
|
|
2520
2533
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2534
|
+
return {
|
|
2535
|
+
red: Math.round((red + match) * 255),
|
|
2536
|
+
green: Math.round((green + match) * 255),
|
|
2537
|
+
blue: Math.round((blue + match) * 255)
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2540
|
+
function tagColor(tag) {
|
|
2541
|
+
if (tag.color) {
|
|
2542
|
+
return {
|
|
2543
|
+
accent: tag.color,
|
|
2544
|
+
background: `color-mix(in srgb, ${tag.color} 12%, transparent)`,
|
|
2545
|
+
border: `color-mix(in srgb, ${tag.color} 24%, transparent)`
|
|
2546
|
+
};
|
|
2531
2547
|
}
|
|
2532
|
-
);
|
|
2548
|
+
const hue = hashTagColorKey(normalizeTagColorKey(tag)) % 360;
|
|
2549
|
+
const { red, green, blue } = hslToRgb(hue, 0.68, 0.48);
|
|
2550
|
+
return {
|
|
2551
|
+
accent: `rgb(${red} ${green} ${blue})`,
|
|
2552
|
+
background: `rgb(${red} ${green} ${blue} / 0.12)`,
|
|
2553
|
+
border: `rgb(${red} ${green} ${blue} / 0.24)`
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
var TagDot = ({ tag }) => {
|
|
2557
|
+
const color = tagColor(tag);
|
|
2558
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2559
|
+
"span",
|
|
2560
|
+
{
|
|
2561
|
+
"aria-hidden": "true",
|
|
2562
|
+
className: "h-2 w-2 shrink-0 rounded-full",
|
|
2563
|
+
style: { backgroundColor: color.accent }
|
|
2564
|
+
}
|
|
2565
|
+
);
|
|
2566
|
+
};
|
|
2567
|
+
var ThreadTagBadge = ({ tag }) => {
|
|
2568
|
+
const color = tagColor(tag);
|
|
2569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2570
|
+
Badge,
|
|
2571
|
+
{
|
|
2572
|
+
variant: "secondary",
|
|
2573
|
+
className: "h-4 max-w-24 gap-1 rounded border px-1.5 py-0 text-[10px] font-normal text-muted-foreground",
|
|
2574
|
+
style: {
|
|
2575
|
+
backgroundColor: color.background,
|
|
2576
|
+
borderColor: color.border
|
|
2577
|
+
},
|
|
2578
|
+
children: [
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TagDot, { tag }),
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate", children: tag.name })
|
|
2581
|
+
]
|
|
2582
|
+
}
|
|
2583
|
+
);
|
|
2584
|
+
};
|
|
2585
|
+
var ThreadTagEditorBadge = ({
|
|
2586
|
+
tag,
|
|
2587
|
+
removeLabel,
|
|
2588
|
+
onRemove
|
|
2589
|
+
}) => {
|
|
2590
|
+
const color = tagColor(tag);
|
|
2591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2592
|
+
Badge,
|
|
2593
|
+
{
|
|
2594
|
+
variant: "secondary",
|
|
2595
|
+
className: "gap-1 rounded-md border py-1 text-sm font-normal",
|
|
2596
|
+
style: {
|
|
2597
|
+
backgroundColor: color.background,
|
|
2598
|
+
borderColor: color.border
|
|
2599
|
+
},
|
|
2600
|
+
children: [
|
|
2601
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TagDot, { tag }),
|
|
2602
|
+
tag.name,
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2604
|
+
"button",
|
|
2605
|
+
{
|
|
2606
|
+
type: "button",
|
|
2607
|
+
className: "rounded-sm hover:bg-background/80",
|
|
2608
|
+
onClick: onRemove,
|
|
2609
|
+
"aria-label": removeLabel,
|
|
2610
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { className: "h-3 w-3" })
|
|
2611
|
+
}
|
|
2612
|
+
)
|
|
2613
|
+
]
|
|
2614
|
+
}
|
|
2615
|
+
);
|
|
2616
|
+
};
|
|
2533
2617
|
var Sidebar2 = ({
|
|
2534
2618
|
threads,
|
|
2535
2619
|
currentThreadId,
|
|
@@ -2996,25 +3080,12 @@ var Sidebar2 = ({
|
|
|
2996
3080
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-4", children: [
|
|
2997
3081
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-2", children: [
|
|
2998
3082
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-sm font-medium", children: config.labels?.tags || "Tags" }),
|
|
2999
|
-
(tagDialogThread.tags ?? []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-muted-foreground", children: config.labels?.untagged || "Untagged" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-wrap gap-2", children: (tagDialogThread.tags ?? []).map((tag) => /* @__PURE__ */ (0, import_jsx_runtime18.
|
|
3000
|
-
|
|
3083
|
+
(tagDialogThread.tags ?? []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-muted-foreground", children: config.labels?.untagged || "Untagged" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-wrap gap-2", children: (tagDialogThread.tags ?? []).map((tag) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3084
|
+
ThreadTagEditorBadge,
|
|
3001
3085
|
{
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TagDot, { tag }),
|
|
3006
|
-
tag.name,
|
|
3007
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3008
|
-
"button",
|
|
3009
|
-
{
|
|
3010
|
-
type: "button",
|
|
3011
|
-
className: "rounded-sm hover:bg-background/80",
|
|
3012
|
-
onClick: () => removeTagFromThread(tagDialogThread, tag.id),
|
|
3013
|
-
"aria-label": config.labels?.removeTag || "Remove tag",
|
|
3014
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { className: "h-3 w-3" })
|
|
3015
|
-
}
|
|
3016
|
-
)
|
|
3017
|
-
]
|
|
3086
|
+
tag,
|
|
3087
|
+
removeLabel: config.labels?.removeTag || "Remove tag",
|
|
3088
|
+
onRemove: () => removeTagFromThread(tagDialogThread, tag.id)
|
|
3018
3089
|
},
|
|
3019
3090
|
tag.id
|
|
3020
3091
|
)) })
|