@iota-uz/sdk 0.4.10 → 0.4.12
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/bichat/index.cjs +898 -416
- package/dist/bichat/index.cjs.map +1 -1
- package/dist/bichat/index.d.cts +49 -1
- package/dist/bichat/index.d.ts +49 -1
- package/dist/bichat/index.mjs +897 -419
- package/dist/bichat/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tailwind/compiled.css +1 -1
- package/tailwind/create-config.cjs +23 -4
package/dist/bichat/index.cjs
CHANGED
|
@@ -7089,6 +7089,19 @@ var SessionItem = React.memo(
|
|
|
7089
7089
|
const [menuAnchor, setMenuAnchor] = React.useState(null);
|
|
7090
7090
|
const [isTouch, setIsTouch] = React.useState(false);
|
|
7091
7091
|
const { t } = useTranslation();
|
|
7092
|
+
const isDraggingRef = React.useRef(false);
|
|
7093
|
+
const dragX = framerMotion.useMotionValue(0);
|
|
7094
|
+
const archiveOpacity = framerMotion.useTransform(dragX, [-80, -40, 0], [1, 0.5, 0]);
|
|
7095
|
+
const archiveScale = framerMotion.useTransform(dragX, [-80, -40, 0], [1, 0.8, 0.6]);
|
|
7096
|
+
const canDragArchive = !!onArchive;
|
|
7097
|
+
const handleDragEnd = (_, info) => {
|
|
7098
|
+
if (info.offset.x < -80 && onArchive) {
|
|
7099
|
+
onArchive();
|
|
7100
|
+
}
|
|
7101
|
+
requestAnimationFrame(() => {
|
|
7102
|
+
isDraggingRef.current = false;
|
|
7103
|
+
});
|
|
7104
|
+
};
|
|
7092
7105
|
React.useEffect(() => {
|
|
7093
7106
|
setIsTouch("ontouchend" in document);
|
|
7094
7107
|
}, []);
|
|
@@ -7107,17 +7120,15 @@ var SessionItem = React.memo(
|
|
|
7107
7120
|
const element = itemRef.current;
|
|
7108
7121
|
if (!element) return;
|
|
7109
7122
|
const isIPad = /iPad|Macintosh/i.test(navigator.userAgent) && "ontouchend" in document;
|
|
7110
|
-
if (isIPad)
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
}
|
|
7120
|
-
return void 0;
|
|
7123
|
+
if (!isIPad) return;
|
|
7124
|
+
const handleContextMenu = (e) => {
|
|
7125
|
+
e.preventDefault();
|
|
7126
|
+
const target = e.currentTarget;
|
|
7127
|
+
setMenuAnchor(target.getBoundingClientRect());
|
|
7128
|
+
setMenuOpen(true);
|
|
7129
|
+
};
|
|
7130
|
+
element.addEventListener("contextmenu", handleContextMenu);
|
|
7131
|
+
return () => element.removeEventListener("contextmenu", handleContextMenu);
|
|
7121
7132
|
}, [itemRef]);
|
|
7122
7133
|
const contextMenuItems = mode === "archived" ? [
|
|
7123
7134
|
...onRestore ? [{
|
|
@@ -7168,7 +7179,7 @@ var SessionItem = React.memo(
|
|
|
7168
7179
|
];
|
|
7169
7180
|
const hasContextMenu = contextMenuItems.length > 0;
|
|
7170
7181
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7171
|
-
/* @__PURE__ */ jsxRuntime.
|
|
7182
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7172
7183
|
framerMotion.motion.div,
|
|
7173
7184
|
{
|
|
7174
7185
|
variants: sessionItemVariants,
|
|
@@ -7176,165 +7187,196 @@ var SessionItem = React.memo(
|
|
|
7176
7187
|
animate: "animate",
|
|
7177
7188
|
whileHover: "hover",
|
|
7178
7189
|
exit: "exit",
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7190
|
+
className: "relative overflow-hidden rounded-lg",
|
|
7191
|
+
children: [
|
|
7192
|
+
canDragArchive && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7193
|
+
framerMotion.motion.div,
|
|
7194
|
+
{
|
|
7195
|
+
className: "absolute inset-y-0 right-0 w-20 flex items-center justify-center bg-gray-500 dark:bg-gray-600 rounded-r-lg",
|
|
7196
|
+
style: { opacity: archiveOpacity, scale: archiveScale },
|
|
7197
|
+
"aria-hidden": "true",
|
|
7198
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 20, className: "text-white" })
|
|
7199
|
+
}
|
|
7200
|
+
),
|
|
7201
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7202
|
+
framerMotion.motion.div,
|
|
7203
|
+
{
|
|
7204
|
+
drag: canDragArchive ? "x" : false,
|
|
7205
|
+
dragDirectionLock: true,
|
|
7206
|
+
dragConstraints: { left: -100, right: 0 },
|
|
7207
|
+
dragElastic: { left: 0.2, right: 0.5 },
|
|
7208
|
+
dragSnapToOrigin: true,
|
|
7209
|
+
style: { x: canDragArchive ? dragX : void 0 },
|
|
7210
|
+
onDragStart: () => {
|
|
7211
|
+
isDraggingRef.current = true;
|
|
7212
|
+
},
|
|
7213
|
+
onDragEnd: canDragArchive ? handleDragEnd : void 0,
|
|
7214
|
+
className: "relative",
|
|
7215
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7216
|
+
"div",
|
|
7200
7217
|
{
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
{
|
|
7211
|
-
onClick: (e) => {
|
|
7218
|
+
role: "button",
|
|
7219
|
+
tabIndex: 0,
|
|
7220
|
+
ref: itemRef,
|
|
7221
|
+
onClick: () => {
|
|
7222
|
+
if (isDraggingRef.current) return;
|
|
7223
|
+
onSelect(session.id);
|
|
7224
|
+
},
|
|
7225
|
+
onKeyDown: (e) => {
|
|
7226
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7212
7227
|
e.preventDefault();
|
|
7213
|
-
|
|
7214
|
-
}
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
}
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
},
|
|
7235
|
-
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7236
|
-
"aria-label": session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat"),
|
|
7237
|
-
"data-testid": `${testIdPrefix}-session-pin-${session.id}`,
|
|
7238
|
-
children: [
|
|
7239
|
-
session.pinned ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 16, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Bookmark, { size: 16, className: "w-4 h-4" }),
|
|
7240
|
-
session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat")
|
|
7241
|
-
]
|
|
7242
|
-
}
|
|
7243
|
-
) }),
|
|
7244
|
-
onRename && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7245
|
-
"button",
|
|
7246
|
-
{
|
|
7247
|
-
onClick: (e) => {
|
|
7248
|
-
e.preventDefault();
|
|
7249
|
-
e.stopPropagation();
|
|
7250
|
-
editableTitleRef.current?.startEditing();
|
|
7251
|
-
close();
|
|
7252
|
-
},
|
|
7253
|
-
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7254
|
-
"aria-label": t("BiChat.Sidebar.RenameChat"),
|
|
7255
|
-
"data-testid": `${testIdPrefix}-session-rename-${session.id}`,
|
|
7256
|
-
children: [
|
|
7257
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { size: 16, className: "w-4 h-4" }),
|
|
7258
|
-
t("BiChat.Sidebar.RenameChat")
|
|
7259
|
-
]
|
|
7260
|
-
}
|
|
7261
|
-
) }),
|
|
7262
|
-
mode !== "archived" && onRegenerateTitle && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7263
|
-
"button",
|
|
7264
|
-
{
|
|
7265
|
-
onClick: (e) => {
|
|
7266
|
-
e.preventDefault();
|
|
7267
|
-
e.stopPropagation();
|
|
7268
|
-
onRegenerateTitle();
|
|
7269
|
-
close();
|
|
7270
|
-
},
|
|
7271
|
-
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7272
|
-
"aria-label": t("BiChat.Sidebar.RegenerateTitle"),
|
|
7273
|
-
"data-testid": `${testIdPrefix}-session-regenerate-${session.id}`,
|
|
7274
|
-
children: [
|
|
7275
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.ArrowsClockwise, { size: 16, className: "w-4 h-4" }),
|
|
7276
|
-
t("BiChat.Sidebar.RegenerateTitle")
|
|
7277
|
-
]
|
|
7278
|
-
}
|
|
7279
|
-
) }),
|
|
7280
|
-
mode === "archived" && onRestore && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7281
|
-
"button",
|
|
7282
|
-
{
|
|
7283
|
-
onClick: (e) => {
|
|
7284
|
-
e.preventDefault();
|
|
7285
|
-
e.stopPropagation();
|
|
7286
|
-
onRestore();
|
|
7287
|
-
},
|
|
7288
|
-
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-900/20 ring-1 ring-green-200/70 dark:ring-green-500/30" : "text-green-700 dark:text-green-300 hover:bg-green-50/70 dark:hover:bg-green-900/10"}`,
|
|
7289
|
-
"aria-label": t("BiChat.Archived.RestoreButton"),
|
|
7290
|
-
"data-testid": `${testIdPrefix}-session-restore-${session.id}`,
|
|
7291
|
-
children: [
|
|
7292
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.ArrowUUpLeft, { size: 16, className: "w-4 h-4" }),
|
|
7293
|
-
t("BiChat.Archived.RestoreButton")
|
|
7294
|
-
]
|
|
7295
|
-
}
|
|
7296
|
-
) }),
|
|
7297
|
-
mode !== "archived" && onArchive && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7298
|
-
"button",
|
|
7228
|
+
onSelect(session.id);
|
|
7229
|
+
}
|
|
7230
|
+
},
|
|
7231
|
+
className: `block w-full text-left px-3 py-2 rounded-lg transition-smooth group relative touch-tap cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 ${isActive ? "bg-primary-50/50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 border-l-4 border-primary-400 dark:border-primary-600" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 border-l-4 border-transparent"} ${className}`,
|
|
7232
|
+
"aria-current": isActive ? "page" : void 0,
|
|
7233
|
+
"data-session-item": true,
|
|
7234
|
+
"data-testid": `${testIdPrefix}-session-${session.id}`,
|
|
7235
|
+
...longPressHandlers,
|
|
7236
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
7237
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7238
|
+
MemoizedEditableText,
|
|
7239
|
+
{
|
|
7240
|
+
ref: editableTitleRef,
|
|
7241
|
+
value: displayTitle,
|
|
7242
|
+
onSave: (newTitle) => onRename?.(newTitle),
|
|
7243
|
+
isLoading: isTitleGenerating
|
|
7244
|
+
}
|
|
7245
|
+
) }),
|
|
7246
|
+
!isTouch && hasContextMenu && /* @__PURE__ */ jsxRuntime.jsxs(react$1.Menu, { children: [
|
|
7247
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7248
|
+
react$1.MenuButton,
|
|
7299
7249
|
{
|
|
7300
7250
|
onClick: (e) => {
|
|
7301
7251
|
e.preventDefault();
|
|
7302
7252
|
e.stopPropagation();
|
|
7303
|
-
onArchive();
|
|
7304
7253
|
},
|
|
7305
|
-
className:
|
|
7306
|
-
"aria-label": t("BiChat.Sidebar.
|
|
7307
|
-
"data-testid": `${testIdPrefix}-session-
|
|
7308
|
-
children:
|
|
7309
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 16, className: "w-4 h-4" }),
|
|
7310
|
-
t("BiChat.Sidebar.ArchiveChat")
|
|
7311
|
-
]
|
|
7254
|
+
className: "opacity-0 group-hover:opacity-100 p-1.5 rounded hover:bg-gray-200 dark:hover:bg-gray-700 transition-smooth flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
7255
|
+
"aria-label": t("BiChat.Sidebar.ChatOptions"),
|
|
7256
|
+
"data-testid": `${testIdPrefix}-session-options-${session.id}`,
|
|
7257
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.DotsThree, { size: 16, className: "w-4 h-4", weight: "bold" })
|
|
7312
7258
|
}
|
|
7313
|
-
)
|
|
7314
|
-
|
|
7315
|
-
|
|
7259
|
+
),
|
|
7260
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7261
|
+
react$1.MenuItems,
|
|
7316
7262
|
{
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
e.stopPropagation();
|
|
7320
|
-
onDelete();
|
|
7321
|
-
},
|
|
7322
|
-
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 ring-1 ring-red-200/70 dark:ring-red-500/30" : "text-red-600 dark:text-red-400 hover:bg-red-50/70 dark:hover:bg-red-900/10"}`,
|
|
7323
|
-
"aria-label": t("BiChat.Sidebar.DeleteChat"),
|
|
7324
|
-
"data-testid": `${testIdPrefix}-session-delete-${session.id}`,
|
|
7263
|
+
anchor: "bottom start",
|
|
7264
|
+
className: "w-52 bg-white/95 dark:bg-gray-900/95 backdrop-blur rounded-xl shadow-xl border border-gray-200 dark:border-gray-700 z-30 [--anchor-gap:8px] mt-1 p-2 space-y-1",
|
|
7325
7265
|
children: [
|
|
7326
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.
|
|
7327
|
-
|
|
7266
|
+
mode !== "archived" && onPin && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7267
|
+
"button",
|
|
7268
|
+
{
|
|
7269
|
+
onClick: (e) => {
|
|
7270
|
+
e.preventDefault();
|
|
7271
|
+
e.stopPropagation();
|
|
7272
|
+
onPin();
|
|
7273
|
+
},
|
|
7274
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7275
|
+
"aria-label": session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat"),
|
|
7276
|
+
"data-testid": `${testIdPrefix}-session-pin-${session.id}`,
|
|
7277
|
+
children: [
|
|
7278
|
+
session.pinned ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 16, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Bookmark, { size: 16, className: "w-4 h-4" }),
|
|
7279
|
+
session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat")
|
|
7280
|
+
]
|
|
7281
|
+
}
|
|
7282
|
+
) }),
|
|
7283
|
+
onRename && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7284
|
+
"button",
|
|
7285
|
+
{
|
|
7286
|
+
onClick: (e) => {
|
|
7287
|
+
e.preventDefault();
|
|
7288
|
+
e.stopPropagation();
|
|
7289
|
+
editableTitleRef.current?.startEditing();
|
|
7290
|
+
close();
|
|
7291
|
+
},
|
|
7292
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7293
|
+
"aria-label": t("BiChat.Sidebar.RenameChat"),
|
|
7294
|
+
"data-testid": `${testIdPrefix}-session-rename-${session.id}`,
|
|
7295
|
+
children: [
|
|
7296
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { size: 16, className: "w-4 h-4" }),
|
|
7297
|
+
t("BiChat.Sidebar.RenameChat")
|
|
7298
|
+
]
|
|
7299
|
+
}
|
|
7300
|
+
) }),
|
|
7301
|
+
mode !== "archived" && onRegenerateTitle && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7302
|
+
"button",
|
|
7303
|
+
{
|
|
7304
|
+
onClick: (e) => {
|
|
7305
|
+
e.preventDefault();
|
|
7306
|
+
e.stopPropagation();
|
|
7307
|
+
onRegenerateTitle();
|
|
7308
|
+
close();
|
|
7309
|
+
},
|
|
7310
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
|
|
7311
|
+
"aria-label": t("BiChat.Sidebar.RegenerateTitle"),
|
|
7312
|
+
"data-testid": `${testIdPrefix}-session-regenerate-${session.id}`,
|
|
7313
|
+
children: [
|
|
7314
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.ArrowsClockwise, { size: 16, className: "w-4 h-4" }),
|
|
7315
|
+
t("BiChat.Sidebar.RegenerateTitle")
|
|
7316
|
+
]
|
|
7317
|
+
}
|
|
7318
|
+
) }),
|
|
7319
|
+
mode === "archived" && onRestore && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7320
|
+
"button",
|
|
7321
|
+
{
|
|
7322
|
+
onClick: (e) => {
|
|
7323
|
+
e.preventDefault();
|
|
7324
|
+
e.stopPropagation();
|
|
7325
|
+
onRestore();
|
|
7326
|
+
},
|
|
7327
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-900/20 ring-1 ring-green-200/70 dark:ring-green-500/30" : "text-green-700 dark:text-green-300 hover:bg-green-50/70 dark:hover:bg-green-900/10"}`,
|
|
7328
|
+
"aria-label": t("BiChat.Archived.RestoreButton"),
|
|
7329
|
+
"data-testid": `${testIdPrefix}-session-restore-${session.id}`,
|
|
7330
|
+
children: [
|
|
7331
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.ArrowUUpLeft, { size: 16, className: "w-4 h-4" }),
|
|
7332
|
+
t("BiChat.Archived.RestoreButton")
|
|
7333
|
+
]
|
|
7334
|
+
}
|
|
7335
|
+
) }),
|
|
7336
|
+
mode !== "archived" && onArchive && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7337
|
+
"button",
|
|
7338
|
+
{
|
|
7339
|
+
onClick: (e) => {
|
|
7340
|
+
e.preventDefault();
|
|
7341
|
+
e.stopPropagation();
|
|
7342
|
+
onArchive();
|
|
7343
|
+
},
|
|
7344
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 ring-1 ring-amber-200/70 dark:ring-amber-500/30" : "text-amber-600 dark:text-amber-400 hover:bg-amber-50/70 dark:hover:bg-amber-900/10"}`,
|
|
7345
|
+
"aria-label": t("BiChat.Sidebar.ArchiveChat"),
|
|
7346
|
+
"data-testid": `${testIdPrefix}-session-archive-${session.id}`,
|
|
7347
|
+
children: [
|
|
7348
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 16, className: "w-4 h-4" }),
|
|
7349
|
+
t("BiChat.Sidebar.ArchiveChat")
|
|
7350
|
+
]
|
|
7351
|
+
}
|
|
7352
|
+
) }),
|
|
7353
|
+
onDelete && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7354
|
+
"button",
|
|
7355
|
+
{
|
|
7356
|
+
onClick: (e) => {
|
|
7357
|
+
e.preventDefault();
|
|
7358
|
+
e.stopPropagation();
|
|
7359
|
+
onDelete();
|
|
7360
|
+
},
|
|
7361
|
+
className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 ring-1 ring-red-200/70 dark:ring-red-500/30" : "text-red-600 dark:text-red-400 hover:bg-red-50/70 dark:hover:bg-red-900/10"}`,
|
|
7362
|
+
"aria-label": t("BiChat.Sidebar.DeleteChat"),
|
|
7363
|
+
"data-testid": `${testIdPrefix}-session-delete-${session.id}`,
|
|
7364
|
+
children: [
|
|
7365
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Trash, { size: 16, className: "w-4 h-4" }),
|
|
7366
|
+
t("BiChat.Sidebar.DeleteChat")
|
|
7367
|
+
]
|
|
7368
|
+
}
|
|
7369
|
+
) })
|
|
7328
7370
|
]
|
|
7329
7371
|
}
|
|
7330
|
-
)
|
|
7331
|
-
]
|
|
7332
|
-
}
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7372
|
+
)
|
|
7373
|
+
] })
|
|
7374
|
+
] })
|
|
7375
|
+
}
|
|
7376
|
+
)
|
|
7377
|
+
}
|
|
7378
|
+
)
|
|
7379
|
+
]
|
|
7338
7380
|
}
|
|
7339
7381
|
),
|
|
7340
7382
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7854,6 +7896,113 @@ function groupSessionsByDate(sessions, t) {
|
|
|
7854
7896
|
});
|
|
7855
7897
|
return groups;
|
|
7856
7898
|
}
|
|
7899
|
+
|
|
7900
|
+
// ui/src/bichat/utils/errorDisplay.ts
|
|
7901
|
+
function isPermissionDeniedError(error) {
|
|
7902
|
+
if (!error) return false;
|
|
7903
|
+
if (error instanceof Error) {
|
|
7904
|
+
const msg = error.message.toLowerCase();
|
|
7905
|
+
if (msg.includes("forbidden") || msg.includes("permission denied")) return true;
|
|
7906
|
+
}
|
|
7907
|
+
if (typeof error === "object" && error !== null) {
|
|
7908
|
+
const obj = error;
|
|
7909
|
+
if (obj.code === "forbidden" || obj.code === 403) return true;
|
|
7910
|
+
if (obj.status === 403) return true;
|
|
7911
|
+
if (obj.statusCode === 403) return true;
|
|
7912
|
+
if (typeof obj.response === "object" && obj.response !== null) {
|
|
7913
|
+
const resp = obj.response;
|
|
7914
|
+
if (resp.status === 403) return true;
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7917
|
+
if (typeof error === "string") {
|
|
7918
|
+
const lower = error.toLowerCase();
|
|
7919
|
+
if (lower.includes("forbidden") || lower.includes("permission denied")) return true;
|
|
7920
|
+
}
|
|
7921
|
+
return false;
|
|
7922
|
+
}
|
|
7923
|
+
function toErrorDisplay(error, fallbackTitle) {
|
|
7924
|
+
const permDenied = isPermissionDeniedError(error);
|
|
7925
|
+
let title = fallbackTitle;
|
|
7926
|
+
let description = "";
|
|
7927
|
+
if (error instanceof Error) {
|
|
7928
|
+
description = error.message;
|
|
7929
|
+
} else if (typeof error === "object" && error !== null) {
|
|
7930
|
+
const obj = error;
|
|
7931
|
+
if (typeof obj.message === "string" && obj.message) description = obj.message;
|
|
7932
|
+
if (typeof obj.title === "string" && obj.title) title = obj.title;
|
|
7933
|
+
if (typeof obj.detail === "string" && obj.detail) description = obj.detail;
|
|
7934
|
+
} else if (typeof error === "string") {
|
|
7935
|
+
description = error;
|
|
7936
|
+
}
|
|
7937
|
+
if (permDenied && !description) {
|
|
7938
|
+
description = "Your account does not have permission for this action.";
|
|
7939
|
+
}
|
|
7940
|
+
return { title, description, isPermissionDenied: permDenied };
|
|
7941
|
+
}
|
|
7942
|
+
function ErrorAlert({ error }) {
|
|
7943
|
+
const amber = error.isPermissionDenied;
|
|
7944
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7945
|
+
"div",
|
|
7946
|
+
{
|
|
7947
|
+
className: `mx-2 mt-4 p-3 border rounded-xl cursor-default ${amber ? "bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800" : "bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800"}`,
|
|
7948
|
+
children: [
|
|
7949
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7950
|
+
"p",
|
|
7951
|
+
{
|
|
7952
|
+
className: `text-xs font-medium ${amber ? "text-amber-700 dark:text-amber-300" : "text-red-600 dark:text-red-400"}`,
|
|
7953
|
+
children: error.title
|
|
7954
|
+
}
|
|
7955
|
+
),
|
|
7956
|
+
error.description && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7957
|
+
"p",
|
|
7958
|
+
{
|
|
7959
|
+
className: `mt-1 text-xs ${amber ? "text-amber-600 dark:text-amber-400" : "text-red-500 dark:text-red-300"}`,
|
|
7960
|
+
children: error.description
|
|
7961
|
+
}
|
|
7962
|
+
)
|
|
7963
|
+
]
|
|
7964
|
+
}
|
|
7965
|
+
);
|
|
7966
|
+
}
|
|
7967
|
+
var COLLAPSE_STORAGE_KEY = "bichat-sidebar-collapsed";
|
|
7968
|
+
function useSidebarCollapse() {
|
|
7969
|
+
const [isCollapsed, setIsCollapsed] = React.useState(() => {
|
|
7970
|
+
try {
|
|
7971
|
+
return localStorage.getItem(COLLAPSE_STORAGE_KEY) === "true";
|
|
7972
|
+
} catch {
|
|
7973
|
+
return false;
|
|
7974
|
+
}
|
|
7975
|
+
});
|
|
7976
|
+
const isCollapsedRef = React.useRef(isCollapsed);
|
|
7977
|
+
React.useEffect(() => {
|
|
7978
|
+
isCollapsedRef.current = isCollapsed;
|
|
7979
|
+
}, [isCollapsed]);
|
|
7980
|
+
const toggle = React.useCallback(() => {
|
|
7981
|
+
setIsCollapsed((prev) => {
|
|
7982
|
+
const next = !prev;
|
|
7983
|
+
try {
|
|
7984
|
+
localStorage.setItem(COLLAPSE_STORAGE_KEY, String(next));
|
|
7985
|
+
} catch {
|
|
7986
|
+
}
|
|
7987
|
+
return next;
|
|
7988
|
+
});
|
|
7989
|
+
}, []);
|
|
7990
|
+
const expand = React.useCallback(() => {
|
|
7991
|
+
setIsCollapsed(false);
|
|
7992
|
+
try {
|
|
7993
|
+
localStorage.setItem(COLLAPSE_STORAGE_KEY, "false");
|
|
7994
|
+
} catch {
|
|
7995
|
+
}
|
|
7996
|
+
}, []);
|
|
7997
|
+
const collapse = React.useCallback(() => {
|
|
7998
|
+
setIsCollapsed(true);
|
|
7999
|
+
try {
|
|
8000
|
+
localStorage.setItem(COLLAPSE_STORAGE_KEY, "true");
|
|
8001
|
+
} catch {
|
|
8002
|
+
}
|
|
8003
|
+
}, []);
|
|
8004
|
+
return { isCollapsed, isCollapsedRef, toggle, expand, collapse };
|
|
8005
|
+
}
|
|
7857
8006
|
function Sidebar2({
|
|
7858
8007
|
dataSource,
|
|
7859
8008
|
onSessionSelect,
|
|
@@ -7872,11 +8021,64 @@ function Sidebar2({
|
|
|
7872
8021
|
const toast = useToast();
|
|
7873
8022
|
const shouldReduceMotion = framerMotion.useReducedMotion();
|
|
7874
8023
|
const sessionListRef = React.useRef(null);
|
|
8024
|
+
const searchContainerRef = React.useRef(null);
|
|
8025
|
+
const { isCollapsed, isCollapsedRef, toggle, expand, collapse } = useSidebarCollapse();
|
|
8026
|
+
const collapsible = !onClose;
|
|
8027
|
+
const handleSidebarClick = React.useCallback(
|
|
8028
|
+
(e) => {
|
|
8029
|
+
if (!collapsible) return;
|
|
8030
|
+
const interactive = 'a, button, input, summary, [role="button"]';
|
|
8031
|
+
if (e.target.closest(interactive)) return;
|
|
8032
|
+
toggle();
|
|
8033
|
+
},
|
|
8034
|
+
[collapsible, toggle]
|
|
8035
|
+
);
|
|
8036
|
+
const focusSearch = React.useCallback(() => {
|
|
8037
|
+
if (!collapsible) return;
|
|
8038
|
+
if (isCollapsedRef.current) {
|
|
8039
|
+
expand();
|
|
8040
|
+
setTimeout(() => {
|
|
8041
|
+
searchContainerRef.current?.querySelector("input")?.focus();
|
|
8042
|
+
}, 250);
|
|
8043
|
+
} else {
|
|
8044
|
+
searchContainerRef.current?.querySelector("input")?.focus();
|
|
8045
|
+
}
|
|
8046
|
+
}, [collapsible, expand, isCollapsedRef]);
|
|
8047
|
+
React.useEffect(() => {
|
|
8048
|
+
if (!collapsible) return;
|
|
8049
|
+
const handleKeyDown = (e) => {
|
|
8050
|
+
const isMod = e.metaKey || e.ctrlKey;
|
|
8051
|
+
if (isMod && e.key === "b") {
|
|
8052
|
+
e.preventDefault();
|
|
8053
|
+
toggle();
|
|
8054
|
+
}
|
|
8055
|
+
if (isMod && e.key === "k") {
|
|
8056
|
+
e.preventDefault();
|
|
8057
|
+
focusSearch();
|
|
8058
|
+
}
|
|
8059
|
+
};
|
|
8060
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
8061
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
8062
|
+
}, [collapsible, toggle, focusSearch]);
|
|
8063
|
+
React.useEffect(() => {
|
|
8064
|
+
if (!collapsible) return;
|
|
8065
|
+
const handler = (e) => {
|
|
8066
|
+
const detail = e.detail;
|
|
8067
|
+
if (detail?.expanded) {
|
|
8068
|
+
collapse();
|
|
8069
|
+
}
|
|
8070
|
+
};
|
|
8071
|
+
window.addEventListener("bichat:artifacts-panel-expanded", handler);
|
|
8072
|
+
return () => window.removeEventListener("bichat:artifacts-panel-expanded", handler);
|
|
8073
|
+
}, [collapsible, collapse]);
|
|
8074
|
+
const showCollapsed = collapsible && isCollapsed;
|
|
7875
8075
|
const [activeTab, setActiveTab] = React.useState("my-chats");
|
|
7876
8076
|
const [searchQuery, setSearchQuery] = React.useState("");
|
|
7877
8077
|
const [sessions, setSessions] = React.useState([]);
|
|
7878
8078
|
const [loading, setLoading] = React.useState(true);
|
|
7879
|
-
const [
|
|
8079
|
+
const [loadError, setLoadError] = React.useState(null);
|
|
8080
|
+
const [actionError, setActionError] = React.useState(null);
|
|
8081
|
+
const accessDenied = loadError?.isPermissionDenied === true;
|
|
7880
8082
|
const [refreshKey, setRefreshKey] = React.useState(0);
|
|
7881
8083
|
const [showConfirm, setShowConfirm] = React.useState(false);
|
|
7882
8084
|
const [sessionToArchive, setSessionToArchive] = React.useState(null);
|
|
@@ -7890,12 +8092,13 @@ function Sidebar2({
|
|
|
7890
8092
|
const fetchSessions = React.useCallback(async () => {
|
|
7891
8093
|
try {
|
|
7892
8094
|
setLoading(true);
|
|
7893
|
-
|
|
8095
|
+
setLoadError(null);
|
|
8096
|
+
setActionError(null);
|
|
7894
8097
|
const result = await dataSource.listSessions({ limit: 50 });
|
|
7895
8098
|
setSessions(result.sessions);
|
|
7896
8099
|
} catch (err) {
|
|
7897
8100
|
console.error("Failed to load sessions:", err);
|
|
7898
|
-
|
|
8101
|
+
setLoadError(toErrorDisplay(err, t("BiChat.Sidebar.FailedToLoadSessions")));
|
|
7899
8102
|
} finally {
|
|
7900
8103
|
setLoading(false);
|
|
7901
8104
|
}
|
|
@@ -7940,7 +8143,9 @@ function Sidebar2({
|
|
|
7940
8143
|
}
|
|
7941
8144
|
} catch (err) {
|
|
7942
8145
|
console.error("Failed to archive session:", err);
|
|
7943
|
-
|
|
8146
|
+
const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToArchiveChat"));
|
|
8147
|
+
setActionError(display);
|
|
8148
|
+
toast.error(display.title);
|
|
7944
8149
|
} finally {
|
|
7945
8150
|
setShowConfirm(false);
|
|
7946
8151
|
setSessionToArchive(null);
|
|
@@ -7956,7 +8161,9 @@ function Sidebar2({
|
|
|
7956
8161
|
setRefreshKey((k) => k + 1);
|
|
7957
8162
|
} catch (err) {
|
|
7958
8163
|
console.error("Failed to toggle pin:", err);
|
|
7959
|
-
|
|
8164
|
+
const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToTogglePin"));
|
|
8165
|
+
setActionError(display);
|
|
8166
|
+
toast.error(display.title);
|
|
7960
8167
|
}
|
|
7961
8168
|
};
|
|
7962
8169
|
const handleRenameSession = async (sessionId, newTitle) => {
|
|
@@ -7966,7 +8173,9 @@ function Sidebar2({
|
|
|
7966
8173
|
setRefreshKey((k) => k + 1);
|
|
7967
8174
|
} catch (err) {
|
|
7968
8175
|
console.error("Failed to update session title:", err);
|
|
7969
|
-
|
|
8176
|
+
const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToRenameChat"));
|
|
8177
|
+
setActionError(display);
|
|
8178
|
+
toast.error(display.title);
|
|
7970
8179
|
}
|
|
7971
8180
|
};
|
|
7972
8181
|
const handleRegenerateTitle = async (sessionId) => {
|
|
@@ -7976,7 +8185,9 @@ function Sidebar2({
|
|
|
7976
8185
|
setRefreshKey((k) => k + 1);
|
|
7977
8186
|
} catch (err) {
|
|
7978
8187
|
console.error("Failed to regenerate title:", err);
|
|
7979
|
-
|
|
8188
|
+
const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToRegenerateTitle"));
|
|
8189
|
+
setActionError(display);
|
|
8190
|
+
toast.error(display.title);
|
|
7980
8191
|
}
|
|
7981
8192
|
};
|
|
7982
8193
|
const filteredSessions = React.useMemo(() => {
|
|
@@ -8039,176 +8250,311 @@ function Sidebar2({
|
|
|
8039
8250
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8040
8251
|
"aside",
|
|
8041
8252
|
{
|
|
8042
|
-
|
|
8253
|
+
onClick: collapsible ? handleSidebarClick : void 0,
|
|
8254
|
+
className: `relative bg-surface-300 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 h-full min-h-0 flex flex-col overflow-hidden transition-[width] duration-300 ease-in-out ${showCollapsed ? "w-16 cursor-e-resize" : collapsible ? "w-64 cursor-w-resize" : "w-64"} ${className}`,
|
|
8255
|
+
style: { willChange: "width" },
|
|
8043
8256
|
role: "navigation",
|
|
8044
8257
|
"aria-label": t("BiChat.Sidebar.ChatSessions"),
|
|
8045
8258
|
children: [
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8049
|
-
framerMotion.motion.button,
|
|
8050
|
-
{
|
|
8051
|
-
onClick: onClose,
|
|
8052
|
-
className: "cursor-pointer p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-smooth text-gray-600 dark:text-gray-400",
|
|
8053
|
-
title: t("BiChat.Sidebar.CloseSidebar"),
|
|
8054
|
-
"aria-label": t("BiChat.Sidebar.CloseSidebar"),
|
|
8055
|
-
whileHover: "hover",
|
|
8056
|
-
whileTap: "tap",
|
|
8057
|
-
variants: buttonVariants,
|
|
8058
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 20, className: "w-5 h-5" })
|
|
8059
|
-
}
|
|
8060
|
-
)
|
|
8061
|
-
] }),
|
|
8062
|
-
showAllChatsTab && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8063
|
-
TabBar_default,
|
|
8259
|
+
collapsible && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8260
|
+
"div",
|
|
8064
8261
|
{
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8262
|
+
className: `absolute inset-x-0 top-0 bottom-0 z-10 flex flex-col items-center pt-3 gap-3 transition-opacity ${showCollapsed ? "opacity-100 duration-150 delay-100" : "opacity-0 pointer-events-none duration-100"}`,
|
|
8263
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/tooltip relative", children: [
|
|
8264
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8265
|
+
framerMotion.motion.button,
|
|
8266
|
+
{
|
|
8267
|
+
onClick: (e) => {
|
|
8268
|
+
e.stopPropagation();
|
|
8269
|
+
onNewChat();
|
|
8270
|
+
},
|
|
8271
|
+
disabled: creating || loading || accessDenied,
|
|
8272
|
+
className: "w-10 h-10 rounded-lg bg-primary-600 hover:bg-primary-700 active:bg-primary-800 text-white shadow-sm flex items-center justify-center disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer transition-colors focus-visible:ring-2 focus-visible:ring-primary-400/50",
|
|
8273
|
+
title: t("BiChat.Chat.NewChat"),
|
|
8274
|
+
"aria-label": t("BiChat.Sidebar.CreateNewChat"),
|
|
8275
|
+
whileTap: { scale: 0.95 },
|
|
8276
|
+
children: creating ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 border-2 border-white/50 border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Plus, { size: 18, weight: "bold" })
|
|
8277
|
+
}
|
|
8278
|
+
),
|
|
8279
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-full ml-2 top-1/2 -translate-y-1/2 rounded-md bg-gray-900 dark:bg-gray-100 px-2 py-1 text-xs font-medium text-white dark:text-gray-900 opacity-0 group-hover/tooltip:opacity-100 transition-opacity whitespace-nowrap shadow-lg", children: t("BiChat.Chat.NewChat") })
|
|
8280
|
+
] })
|
|
8068
8281
|
}
|
|
8069
8282
|
),
|
|
8070
|
-
|
|
8071
|
-
|
|
8283
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8284
|
+
"div",
|
|
8072
8285
|
{
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
}
|
|
8130
|
-
|
|
8131
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8132
|
-
|
|
8133
|
-
{
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8286
|
+
className: `flex flex-col flex-1 min-h-0 w-64 shrink-0 transition-opacity ${showCollapsed ? "opacity-0 pointer-events-none duration-100" : collapsible ? "opacity-100 duration-150 delay-[200ms]" : ""}`,
|
|
8287
|
+
children: [
|
|
8288
|
+
(headerSlot || onClose) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
|
|
8289
|
+
headerSlot,
|
|
8290
|
+
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8291
|
+
framerMotion.motion.button,
|
|
8292
|
+
{
|
|
8293
|
+
onClick: onClose,
|
|
8294
|
+
className: "cursor-pointer p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-smooth text-gray-600 dark:text-gray-400",
|
|
8295
|
+
title: t("BiChat.Sidebar.CloseSidebar"),
|
|
8296
|
+
"aria-label": t("BiChat.Sidebar.CloseSidebar"),
|
|
8297
|
+
whileHover: "hover",
|
|
8298
|
+
whileTap: "tap",
|
|
8299
|
+
variants: buttonVariants,
|
|
8300
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 20, className: "w-5 h-5" })
|
|
8301
|
+
}
|
|
8302
|
+
)
|
|
8303
|
+
] }),
|
|
8304
|
+
showAllChatsTab && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8305
|
+
TabBar_default,
|
|
8306
|
+
{
|
|
8307
|
+
tabs,
|
|
8308
|
+
activeTab,
|
|
8309
|
+
onTabChange: (id) => setActiveTab(id)
|
|
8310
|
+
}
|
|
8311
|
+
),
|
|
8312
|
+
activeTab === "all-chats" && showAllChatsTab ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8313
|
+
AllChatsList,
|
|
8314
|
+
{
|
|
8315
|
+
dataSource,
|
|
8316
|
+
onSessionSelect,
|
|
8317
|
+
activeSessionId
|
|
8318
|
+
}
|
|
8319
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8320
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: searchContainerRef, className: "mt-3 px-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8321
|
+
SearchInput_default,
|
|
8322
|
+
{
|
|
8323
|
+
value: searchQuery,
|
|
8324
|
+
onChange: setSearchQuery,
|
|
8325
|
+
placeholder: t("BiChat.Sidebar.SearchChats")
|
|
8326
|
+
}
|
|
8327
|
+
) }),
|
|
8328
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8329
|
+
framerMotion.motion.button,
|
|
8330
|
+
{
|
|
8331
|
+
onClick: (e) => {
|
|
8332
|
+
e.stopPropagation();
|
|
8333
|
+
onNewChat();
|
|
8334
|
+
},
|
|
8335
|
+
disabled: creating || loading || accessDenied,
|
|
8336
|
+
className: "cursor-pointer w-full px-4 py-2.5 bg-primary-600 dark:bg-primary-700 text-white rounded-lg hover:bg-primary-700 hover:-translate-y-0.5 active:bg-primary-800 transition-all duration-150 font-medium shadow-sm disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center gap-2 focus-visible:ring-2 focus-visible:ring-primary-400/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900",
|
|
8337
|
+
title: accessDenied ? t("BiChat.Sidebar.MissingPermission") : t("BiChat.Chat.NewChat"),
|
|
8338
|
+
"aria-label": t("BiChat.Sidebar.CreateNewChat"),
|
|
8339
|
+
whileHover: shouldReduceMotion ? {} : { y: -1 },
|
|
8340
|
+
whileTap: shouldReduceMotion ? {} : { scale: 0.98 },
|
|
8341
|
+
children: creating ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8342
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }),
|
|
8343
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t("BiChat.Common.Creating") })
|
|
8344
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8345
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Plus, { size: 16, weight: "bold" }),
|
|
8346
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t("BiChat.Chat.NewChat") })
|
|
8347
|
+
] })
|
|
8348
|
+
}
|
|
8349
|
+
) }),
|
|
8350
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8351
|
+
"nav",
|
|
8352
|
+
{
|
|
8353
|
+
ref: sessionListRef,
|
|
8354
|
+
className: "flex-1 overflow-y-auto px-2 pb-4 hide-scrollbar",
|
|
8355
|
+
"aria-label": t("BiChat.Sidebar.ChatHistory"),
|
|
8356
|
+
onKeyDown: handleSessionListKeyDown,
|
|
8357
|
+
children: [
|
|
8358
|
+
loading && sessions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(SessionSkeleton, { count: 5 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8359
|
+
pinnedSessions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
|
|
8360
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8361
|
+
DateGroupHeader,
|
|
8362
|
+
{
|
|
8363
|
+
groupName: t("BiChat.Common.Pinned"),
|
|
8364
|
+
count: pinnedSessions.length
|
|
8365
|
+
}
|
|
8366
|
+
),
|
|
8367
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8368
|
+
framerMotion.motion.div,
|
|
8369
|
+
{
|
|
8370
|
+
className: "space-y-1 mt-2",
|
|
8371
|
+
variants: staggerContainerVariants,
|
|
8372
|
+
initial: "hidden",
|
|
8373
|
+
animate: "visible",
|
|
8374
|
+
role: "list",
|
|
8375
|
+
"aria-label": t("BiChat.Sidebar.PinnedChats"),
|
|
8376
|
+
children: pinnedSessions.map((session) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8377
|
+
SessionItem_default,
|
|
8378
|
+
{
|
|
8379
|
+
session,
|
|
8380
|
+
isActive: session.id === activeSessionId,
|
|
8381
|
+
onSelect: () => onSessionSelect(session.id),
|
|
8382
|
+
onArchive: () => handleArchiveRequest(session.id),
|
|
8383
|
+
onPin: () => handleTogglePin(session.id, session.pinned),
|
|
8384
|
+
onRename: (newTitle) => handleRenameSession(session.id, newTitle),
|
|
8385
|
+
onRegenerateTitle: () => handleRegenerateTitle(session.id)
|
|
8386
|
+
},
|
|
8387
|
+
session.id
|
|
8388
|
+
))
|
|
8389
|
+
}
|
|
8390
|
+
),
|
|
8391
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
|
|
8392
|
+
] }),
|
|
8393
|
+
sessionGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
|
|
8394
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8395
|
+
DateGroupHeader,
|
|
8396
|
+
{
|
|
8397
|
+
groupName: group.name,
|
|
8398
|
+
count: group.sessions.length
|
|
8399
|
+
}
|
|
8400
|
+
),
|
|
8401
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8402
|
+
framerMotion.motion.div,
|
|
8403
|
+
{
|
|
8404
|
+
className: "space-y-1 mt-2",
|
|
8405
|
+
variants: staggerContainerVariants,
|
|
8406
|
+
initial: "hidden",
|
|
8407
|
+
animate: "visible",
|
|
8408
|
+
role: "list",
|
|
8409
|
+
"aria-label": `${group.name} chats`,
|
|
8410
|
+
children: group.sessions.map((session) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8411
|
+
SessionItem_default,
|
|
8412
|
+
{
|
|
8413
|
+
session,
|
|
8414
|
+
isActive: session.id === activeSessionId,
|
|
8415
|
+
onSelect: () => onSessionSelect(session.id),
|
|
8416
|
+
onArchive: () => handleArchiveRequest(session.id),
|
|
8417
|
+
onPin: () => handleTogglePin(session.id, session.pinned),
|
|
8418
|
+
onRename: (newTitle) => handleRenameSession(session.id, newTitle),
|
|
8419
|
+
onRegenerateTitle: () => handleRegenerateTitle(session.id)
|
|
8420
|
+
},
|
|
8421
|
+
session.id
|
|
8422
|
+
))
|
|
8423
|
+
}
|
|
8424
|
+
)
|
|
8425
|
+
] }, group.name)),
|
|
8426
|
+
filteredSessions.length === 0 && !loading && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8427
|
+
MemoizedEmptyState,
|
|
8176
8428
|
{
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8429
|
+
title: searchQuery ? t("BiChat.Sidebar.NoChatsFound", { query: searchQuery }) : t("BiChat.Sidebar.NoChatsYet"),
|
|
8430
|
+
description: searchQuery ? void 0 : t("BiChat.Sidebar.CreateOneToGetStarted"),
|
|
8431
|
+
action: searchQuery ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8432
|
+
"button",
|
|
8433
|
+
{
|
|
8434
|
+
onClick: () => setSearchQuery(""),
|
|
8435
|
+
className: "cursor-pointer text-sm text-primary-600 dark:text-primary-400 hover:underline",
|
|
8436
|
+
children: t("BiChat.Common.Clear")
|
|
8437
|
+
}
|
|
8438
|
+
) : void 0
|
|
8439
|
+
}
|
|
8440
|
+
)
|
|
8441
|
+
] }),
|
|
8442
|
+
loadError && /* @__PURE__ */ jsxRuntime.jsx(ErrorAlert, { error: loadError }),
|
|
8443
|
+
actionError && !loadError && /* @__PURE__ */ jsxRuntime.jsx(ErrorAlert, { error: actionError })
|
|
8444
|
+
]
|
|
8445
|
+
}
|
|
8446
|
+
),
|
|
8447
|
+
footerSlot
|
|
8448
|
+
] }),
|
|
8449
|
+
collapsible && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto border-t border-gray-100 dark:border-gray-800/80 px-4 py-3 flex items-center justify-between", children: [
|
|
8450
|
+
onArchivedView || showAllChatsTab ? /* @__PURE__ */ jsxRuntime.jsxs(react$1.Menu, { children: [
|
|
8451
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8452
|
+
react$1.MenuButton,
|
|
8192
8453
|
{
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8454
|
+
onClick: (e) => {
|
|
8455
|
+
e.stopPropagation();
|
|
8456
|
+
},
|
|
8457
|
+
disabled: loading || accessDenied,
|
|
8458
|
+
className: "flex items-center justify-center rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors disabled:opacity-40 disabled:cursor-not-allowed cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 p-2",
|
|
8459
|
+
"aria-label": t("BiChat.Sidebar.Settings"),
|
|
8460
|
+
title: t("BiChat.Sidebar.Settings"),
|
|
8461
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.Gear, { size: 20 })
|
|
8462
|
+
}
|
|
8463
|
+
),
|
|
8464
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8465
|
+
react$1.MenuItems,
|
|
8466
|
+
{
|
|
8467
|
+
anchor: "top start",
|
|
8468
|
+
className: "w-48 bg-white/95 dark:bg-gray-900/95 backdrop-blur-lg rounded-xl shadow-lg border border-gray-200/80 dark:border-gray-700/60 z-30 [--anchor-gap:8px] mb-1 p-1.5",
|
|
8469
|
+
children: [
|
|
8470
|
+
onArchivedView && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8471
|
+
"button",
|
|
8472
|
+
{
|
|
8473
|
+
onClick: (e) => {
|
|
8474
|
+
e.preventDefault();
|
|
8475
|
+
e.stopPropagation();
|
|
8476
|
+
onArchivedView();
|
|
8477
|
+
},
|
|
8478
|
+
className: `cursor-pointer flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-[13px] text-gray-600 dark:text-gray-300 transition-colors ${focus ? "bg-gray-100 dark:bg-gray-800/70" : ""}`,
|
|
8479
|
+
"aria-label": t("BiChat.Sidebar.ArchivedChats"),
|
|
8480
|
+
children: [
|
|
8481
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
|
|
8482
|
+
t("BiChat.Sidebar.ArchivedChats")
|
|
8483
|
+
]
|
|
8484
|
+
}
|
|
8485
|
+
) }),
|
|
8486
|
+
showAllChatsTab && activeTab !== "all-chats" && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8487
|
+
"button",
|
|
8488
|
+
{
|
|
8489
|
+
onClick: (e) => {
|
|
8490
|
+
e.preventDefault();
|
|
8491
|
+
e.stopPropagation();
|
|
8492
|
+
setActiveTab("all-chats");
|
|
8493
|
+
},
|
|
8494
|
+
className: `cursor-pointer flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-[13px] text-gray-600 dark:text-gray-300 transition-colors ${focus ? "bg-gray-100 dark:bg-gray-800/70" : ""}`,
|
|
8495
|
+
"aria-label": t("BiChat.Sidebar.AllChats"),
|
|
8496
|
+
children: [
|
|
8497
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Users, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
|
|
8498
|
+
t("BiChat.Sidebar.AllChats")
|
|
8499
|
+
]
|
|
8500
|
+
}
|
|
8501
|
+
) }),
|
|
8502
|
+
showAllChatsTab && activeTab === "all-chats" && /* @__PURE__ */ jsxRuntime.jsx(react$1.MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8503
|
+
"button",
|
|
8504
|
+
{
|
|
8505
|
+
onClick: (e) => {
|
|
8506
|
+
e.preventDefault();
|
|
8507
|
+
e.stopPropagation();
|
|
8508
|
+
setActiveTab("my-chats");
|
|
8509
|
+
},
|
|
8510
|
+
className: `cursor-pointer flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-[13px] text-gray-600 dark:text-gray-300 transition-colors ${focus ? "bg-gray-100 dark:bg-gray-800/70" : ""}`,
|
|
8511
|
+
"aria-label": t("BiChat.Sidebar.MyChats"),
|
|
8512
|
+
children: [
|
|
8513
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.List, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
|
|
8514
|
+
t("BiChat.Sidebar.MyChats")
|
|
8515
|
+
]
|
|
8516
|
+
}
|
|
8517
|
+
) })
|
|
8518
|
+
]
|
|
8203
8519
|
}
|
|
8204
8520
|
)
|
|
8205
|
-
] }),
|
|
8206
|
-
|
|
8207
|
-
|
|
8521
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
|
|
8522
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8523
|
+
"button",
|
|
8524
|
+
{
|
|
8525
|
+
onClick: (e) => {
|
|
8526
|
+
e.stopPropagation();
|
|
8527
|
+
toggle();
|
|
8528
|
+
},
|
|
8529
|
+
className: "flex items-center gap-2 rounded-lg px-3 py-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
8530
|
+
title: t("BiChat.Sidebar.CollapseSidebar"),
|
|
8531
|
+
"aria-label": t("BiChat.Sidebar.CollapseSidebar"),
|
|
8532
|
+
children: [
|
|
8533
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.CaretLineLeft, { size: 16 }),
|
|
8534
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: t("BiChat.Sidebar.Collapse") })
|
|
8535
|
+
]
|
|
8536
|
+
}
|
|
8537
|
+
)
|
|
8538
|
+
] })
|
|
8539
|
+
]
|
|
8540
|
+
}
|
|
8541
|
+
),
|
|
8542
|
+
collapsible && showCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 inset-x-0 z-10 border-t border-gray-100 dark:border-gray-800/80 py-3 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/tooltip relative", children: [
|
|
8543
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8544
|
+
"button",
|
|
8545
|
+
{
|
|
8546
|
+
onClick: (e) => {
|
|
8547
|
+
e.stopPropagation();
|
|
8548
|
+
toggle();
|
|
8549
|
+
},
|
|
8550
|
+
className: "w-10 h-10 flex items-center justify-center rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
8551
|
+
title: t("BiChat.Sidebar.ExpandSidebar"),
|
|
8552
|
+
"aria-label": t("BiChat.Sidebar.ExpandSidebar"),
|
|
8553
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.CaretLineRight, { size: 16 })
|
|
8208
8554
|
}
|
|
8209
8555
|
),
|
|
8210
|
-
|
|
8211
|
-
] })
|
|
8556
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-full ml-2 top-1/2 -translate-y-1/2 rounded-md bg-gray-900 dark:bg-gray-100 px-2 py-1 text-xs font-medium text-white dark:text-gray-900 opacity-0 group-hover/tooltip:opacity-100 transition-opacity whitespace-nowrap shadow-lg", children: t("BiChat.Sidebar.Expand") })
|
|
8557
|
+
] }) })
|
|
8212
8558
|
]
|
|
8213
8559
|
}
|
|
8214
8560
|
),
|
|
@@ -8425,6 +8771,231 @@ function ArchivedChatList({
|
|
|
8425
8771
|
}
|
|
8426
8772
|
);
|
|
8427
8773
|
}
|
|
8774
|
+
|
|
8775
|
+
// ui/src/bichat/components/SkipLink.tsx
|
|
8776
|
+
init_useTranslation();
|
|
8777
|
+
function SkipLink() {
|
|
8778
|
+
const { t } = useTranslation();
|
|
8779
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8780
|
+
"a",
|
|
8781
|
+
{
|
|
8782
|
+
href: "#main-content",
|
|
8783
|
+
className: "sr-only focus-visible:not-sr-only focus-visible:absolute focus-visible:top-4 focus-visible:left-4 focus-visible:z-50 focus-visible:bg-primary-600 focus-visible:text-white focus-visible:px-4 focus-visible:py-2 focus-visible:rounded-lg focus-visible:shadow-lg",
|
|
8784
|
+
children: t("BiChat.SkipLink.Label")
|
|
8785
|
+
}
|
|
8786
|
+
);
|
|
8787
|
+
}
|
|
8788
|
+
var MOBILE_QUERY = "(max-width: 767px)";
|
|
8789
|
+
function getIsMobile() {
|
|
8790
|
+
if (typeof window === "undefined") return false;
|
|
8791
|
+
return window.matchMedia(MOBILE_QUERY).matches;
|
|
8792
|
+
}
|
|
8793
|
+
function useSidebarState() {
|
|
8794
|
+
const [isMobile, setIsMobile] = React.useState(getIsMobile);
|
|
8795
|
+
const [isMobileOpen, setIsMobileOpen] = React.useState(false);
|
|
8796
|
+
React.useEffect(() => {
|
|
8797
|
+
if (typeof window === "undefined") return;
|
|
8798
|
+
const mql = window.matchMedia(MOBILE_QUERY);
|
|
8799
|
+
const handler = (e) => {
|
|
8800
|
+
setIsMobile(e.matches);
|
|
8801
|
+
if (!e.matches) setIsMobileOpen(false);
|
|
8802
|
+
};
|
|
8803
|
+
if (mql.addEventListener) {
|
|
8804
|
+
mql.addEventListener("change", handler);
|
|
8805
|
+
} else if (mql.addListener) {
|
|
8806
|
+
mql.addListener(handler);
|
|
8807
|
+
}
|
|
8808
|
+
return () => {
|
|
8809
|
+
if (mql.removeEventListener) {
|
|
8810
|
+
mql.removeEventListener("change", handler);
|
|
8811
|
+
} else if (mql.removeListener) {
|
|
8812
|
+
mql.removeListener(handler);
|
|
8813
|
+
}
|
|
8814
|
+
};
|
|
8815
|
+
}, []);
|
|
8816
|
+
const openMobile = React.useCallback(() => setIsMobileOpen(true), []);
|
|
8817
|
+
const closeMobile = React.useCallback(() => setIsMobileOpen(false), []);
|
|
8818
|
+
const toggleMobile = React.useCallback(() => setIsMobileOpen((v) => !v), []);
|
|
8819
|
+
return { isMobile, isMobileOpen, openMobile, closeMobile, toggleMobile };
|
|
8820
|
+
}
|
|
8821
|
+
function useFocusTrap(containerRef, isActive, restoreFocusOnDeactivate) {
|
|
8822
|
+
React.useEffect(() => {
|
|
8823
|
+
if (!isActive || !containerRef.current) return;
|
|
8824
|
+
const container = containerRef.current;
|
|
8825
|
+
const previouslyFocused = document.activeElement;
|
|
8826
|
+
const getFocusableElements = () => {
|
|
8827
|
+
const selector = [
|
|
8828
|
+
"button:not([disabled])",
|
|
8829
|
+
"[href]",
|
|
8830
|
+
"input:not([disabled])",
|
|
8831
|
+
"select:not([disabled])",
|
|
8832
|
+
"textarea:not([disabled])",
|
|
8833
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
8834
|
+
].join(", ");
|
|
8835
|
+
return Array.from(container.querySelectorAll(selector));
|
|
8836
|
+
};
|
|
8837
|
+
const focusableElements = getFocusableElements();
|
|
8838
|
+
if (focusableElements.length > 0) {
|
|
8839
|
+
focusableElements[0].focus();
|
|
8840
|
+
}
|
|
8841
|
+
const handleTabKey = (e) => {
|
|
8842
|
+
if (e.key !== "Tab") return;
|
|
8843
|
+
const focusableElements2 = getFocusableElements();
|
|
8844
|
+
if (focusableElements2.length === 0) return;
|
|
8845
|
+
const firstElement = focusableElements2[0];
|
|
8846
|
+
const lastElement = focusableElements2[focusableElements2.length - 1];
|
|
8847
|
+
if (e.shiftKey) {
|
|
8848
|
+
if (document.activeElement === firstElement) {
|
|
8849
|
+
e.preventDefault();
|
|
8850
|
+
lastElement.focus();
|
|
8851
|
+
}
|
|
8852
|
+
} else {
|
|
8853
|
+
if (document.activeElement === lastElement) {
|
|
8854
|
+
e.preventDefault();
|
|
8855
|
+
firstElement.focus();
|
|
8856
|
+
}
|
|
8857
|
+
}
|
|
8858
|
+
};
|
|
8859
|
+
container.addEventListener("keydown", handleTabKey);
|
|
8860
|
+
return () => {
|
|
8861
|
+
container.removeEventListener("keydown", handleTabKey);
|
|
8862
|
+
if (restoreFocusOnDeactivate) {
|
|
8863
|
+
restoreFocusOnDeactivate.focus();
|
|
8864
|
+
} else if (previouslyFocused instanceof HTMLElement) {
|
|
8865
|
+
previouslyFocused.focus();
|
|
8866
|
+
}
|
|
8867
|
+
};
|
|
8868
|
+
}, [containerRef, isActive, restoreFocusOnDeactivate]);
|
|
8869
|
+
}
|
|
8870
|
+
function useKeyboardShortcuts(shortcuts) {
|
|
8871
|
+
React.useEffect(() => {
|
|
8872
|
+
const handleKeyDown = (e) => {
|
|
8873
|
+
const target = e.target;
|
|
8874
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target.isContentEditable) {
|
|
8875
|
+
const allowInInput = shortcuts.find(
|
|
8876
|
+
(s) => s.key.toLowerCase() === e.key.toLowerCase() && s.key.toLowerCase() === "escape"
|
|
8877
|
+
);
|
|
8878
|
+
if (!allowInInput) {
|
|
8879
|
+
return;
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8882
|
+
const matchingShortcut = shortcuts.find((s) => {
|
|
8883
|
+
const keyMatches = e.key.toLowerCase() === s.key.toLowerCase();
|
|
8884
|
+
const modMatches = s.meta ? e.metaKey && !e.ctrlKey : s.ctrl ? e.ctrlKey || e.metaKey : !e.ctrlKey && !e.metaKey;
|
|
8885
|
+
const shiftMatches = s.shift ? e.shiftKey : !e.shiftKey;
|
|
8886
|
+
const altMatches = s.alt ? e.altKey : !e.altKey;
|
|
8887
|
+
return keyMatches && modMatches && shiftMatches && altMatches;
|
|
8888
|
+
});
|
|
8889
|
+
if (matchingShortcut) {
|
|
8890
|
+
if (matchingShortcut.preventDefault !== false) {
|
|
8891
|
+
e.preventDefault();
|
|
8892
|
+
}
|
|
8893
|
+
matchingShortcut.callback();
|
|
8894
|
+
}
|
|
8895
|
+
};
|
|
8896
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
8897
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
8898
|
+
}, [shortcuts]);
|
|
8899
|
+
}
|
|
8900
|
+
|
|
8901
|
+
// ui/src/bichat/components/BiChatLayout.tsx
|
|
8902
|
+
init_useTranslation();
|
|
8903
|
+
function BiChatLayout({
|
|
8904
|
+
renderSidebar,
|
|
8905
|
+
children,
|
|
8906
|
+
onNewChat,
|
|
8907
|
+
routeKey,
|
|
8908
|
+
className = ""
|
|
8909
|
+
}) {
|
|
8910
|
+
const { t } = useTranslation();
|
|
8911
|
+
const { isMobile, isMobileOpen, openMobile, closeMobile } = useSidebarState();
|
|
8912
|
+
const drawerRef = React.useRef(null);
|
|
8913
|
+
const menuButtonRef = React.useRef(null);
|
|
8914
|
+
useFocusTrap(drawerRef, isMobile && isMobileOpen, menuButtonRef.current);
|
|
8915
|
+
const shortcuts = React.useMemo(() => {
|
|
8916
|
+
if (!onNewChat) return [];
|
|
8917
|
+
return [{ key: "n", ctrl: true, callback: onNewChat, description: "New chat" }];
|
|
8918
|
+
}, [onNewChat]);
|
|
8919
|
+
useKeyboardShortcuts(shortcuts);
|
|
8920
|
+
React.useEffect(() => {
|
|
8921
|
+
if (!isMobile || !isMobileOpen) return;
|
|
8922
|
+
const onKeyDown = (e) => {
|
|
8923
|
+
if (e.key === "Escape") {
|
|
8924
|
+
e.preventDefault();
|
|
8925
|
+
closeMobile();
|
|
8926
|
+
}
|
|
8927
|
+
};
|
|
8928
|
+
document.addEventListener("keydown", onKeyDown);
|
|
8929
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
8930
|
+
}, [closeMobile, isMobile, isMobileOpen]);
|
|
8931
|
+
const handleDrawerDragEnd = (_, info) => {
|
|
8932
|
+
if (info.offset.x < -80) {
|
|
8933
|
+
closeMobile();
|
|
8934
|
+
}
|
|
8935
|
+
};
|
|
8936
|
+
const content = routeKey ? /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", initial: false, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8937
|
+
framerMotion.motion.div,
|
|
8938
|
+
{
|
|
8939
|
+
className: "flex flex-1 min-h-0",
|
|
8940
|
+
initial: { opacity: 0, y: 4 },
|
|
8941
|
+
animate: { opacity: 1, y: 0 },
|
|
8942
|
+
exit: { opacity: 0, y: -4 },
|
|
8943
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
8944
|
+
children
|
|
8945
|
+
},
|
|
8946
|
+
routeKey
|
|
8947
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 min-h-0", children });
|
|
8948
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative flex flex-1 w-full h-full min-h-0 overflow-hidden ${className}`, children: [
|
|
8949
|
+
/* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
|
|
8950
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block", children: renderSidebar({}) }),
|
|
8951
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isMobile && isMobileOpen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8952
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8953
|
+
framerMotion.motion.div,
|
|
8954
|
+
{
|
|
8955
|
+
className: "fixed inset-0 z-40 bg-black/40",
|
|
8956
|
+
initial: { opacity: 0 },
|
|
8957
|
+
animate: { opacity: 1 },
|
|
8958
|
+
exit: { opacity: 0 },
|
|
8959
|
+
onClick: closeMobile,
|
|
8960
|
+
"aria-hidden": "true"
|
|
8961
|
+
},
|
|
8962
|
+
"sidebar-backdrop"
|
|
8963
|
+
),
|
|
8964
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8965
|
+
framerMotion.motion.div,
|
|
8966
|
+
{
|
|
8967
|
+
className: "fixed inset-y-0 left-0 z-50 w-[18rem] max-w-[85vw] shadow-2xl",
|
|
8968
|
+
initial: { x: "-100%" },
|
|
8969
|
+
animate: { x: 0 },
|
|
8970
|
+
exit: { x: "-100%" },
|
|
8971
|
+
transition: { type: "spring", stiffness: 320, damping: 32 },
|
|
8972
|
+
drag: "x",
|
|
8973
|
+
dragDirectionLock: true,
|
|
8974
|
+
dragConstraints: { left: -120, right: 0 },
|
|
8975
|
+
dragElastic: { left: 0.2, right: 0 },
|
|
8976
|
+
onDragEnd: handleDrawerDragEnd,
|
|
8977
|
+
onClick: (e) => e.stopPropagation(),
|
|
8978
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: drawerRef, className: "h-full bg-white dark:bg-gray-900", children: renderSidebar({ onClose: closeMobile }) })
|
|
8979
|
+
},
|
|
8980
|
+
"sidebar-drawer"
|
|
8981
|
+
)
|
|
8982
|
+
] }) }),
|
|
8983
|
+
/* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "relative flex-1 flex flex-col min-h-0 overflow-hidden", children: [
|
|
8984
|
+
isMobile && !isMobileOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8985
|
+
"button",
|
|
8986
|
+
{
|
|
8987
|
+
ref: menuButtonRef,
|
|
8988
|
+
onClick: openMobile,
|
|
8989
|
+
className: "md:hidden absolute top-3 left-3 z-30 w-10 h-10 rounded-xl bg-white/90 dark:bg-gray-900/90 text-gray-700 dark:text-gray-200 border border-gray-200/60 dark:border-gray-800/80 shadow-sm flex items-center justify-center hover:bg-white dark:hover:bg-gray-900 transition-colors cursor-pointer focus-visible:ring-2 focus-visible:ring-primary-400/50",
|
|
8990
|
+
"aria-label": t("BiChat.Layout.OpenSidebar"),
|
|
8991
|
+
title: t("BiChat.Layout.OpenSidebar"),
|
|
8992
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.List, { size: 20, weight: "bold" })
|
|
8993
|
+
}
|
|
8994
|
+
),
|
|
8995
|
+
content
|
|
8996
|
+
] })
|
|
8997
|
+
] });
|
|
8998
|
+
}
|
|
8428
8999
|
init_useTranslation();
|
|
8429
9000
|
var variantStyles = {
|
|
8430
9001
|
error: {
|
|
@@ -8978,20 +9549,6 @@ function ScreenReaderAnnouncer({
|
|
|
8978
9549
|
);
|
|
8979
9550
|
}
|
|
8980
9551
|
|
|
8981
|
-
// ui/src/bichat/components/SkipLink.tsx
|
|
8982
|
-
init_useTranslation();
|
|
8983
|
-
function SkipLink() {
|
|
8984
|
-
const { t } = useTranslation();
|
|
8985
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8986
|
-
"a",
|
|
8987
|
-
{
|
|
8988
|
-
href: "#main-content",
|
|
8989
|
-
className: "sr-only focus-visible:not-sr-only focus-visible:absolute focus-visible:top-4 focus-visible:left-4 focus-visible:z-50 focus-visible:bg-primary-600 focus-visible:text-white focus-visible:px-4 focus-visible:py-2 focus-visible:rounded-lg focus-visible:shadow-lg",
|
|
8990
|
-
children: t("BiChat.SkipLink.Label")
|
|
8991
|
-
}
|
|
8992
|
-
);
|
|
8993
|
-
}
|
|
8994
|
-
|
|
8995
9552
|
// ui/src/bichat/components/QuestionForm.tsx
|
|
8996
9553
|
init_useTranslation();
|
|
8997
9554
|
|
|
@@ -9690,55 +10247,6 @@ function useModalLock(isOpen) {
|
|
|
9690
10247
|
};
|
|
9691
10248
|
}, [isOpen]);
|
|
9692
10249
|
}
|
|
9693
|
-
function useFocusTrap(containerRef, isActive, restoreFocusOnDeactivate) {
|
|
9694
|
-
React.useEffect(() => {
|
|
9695
|
-
if (!isActive || !containerRef.current) return;
|
|
9696
|
-
const container = containerRef.current;
|
|
9697
|
-
const previouslyFocused = document.activeElement;
|
|
9698
|
-
const getFocusableElements = () => {
|
|
9699
|
-
const selector = [
|
|
9700
|
-
"button:not([disabled])",
|
|
9701
|
-
"[href]",
|
|
9702
|
-
"input:not([disabled])",
|
|
9703
|
-
"select:not([disabled])",
|
|
9704
|
-
"textarea:not([disabled])",
|
|
9705
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
9706
|
-
].join(", ");
|
|
9707
|
-
return Array.from(container.querySelectorAll(selector));
|
|
9708
|
-
};
|
|
9709
|
-
const focusableElements = getFocusableElements();
|
|
9710
|
-
if (focusableElements.length > 0) {
|
|
9711
|
-
focusableElements[0].focus();
|
|
9712
|
-
}
|
|
9713
|
-
const handleTabKey = (e) => {
|
|
9714
|
-
if (e.key !== "Tab") return;
|
|
9715
|
-
const focusableElements2 = getFocusableElements();
|
|
9716
|
-
if (focusableElements2.length === 0) return;
|
|
9717
|
-
const firstElement = focusableElements2[0];
|
|
9718
|
-
const lastElement = focusableElements2[focusableElements2.length - 1];
|
|
9719
|
-
if (e.shiftKey) {
|
|
9720
|
-
if (document.activeElement === firstElement) {
|
|
9721
|
-
e.preventDefault();
|
|
9722
|
-
lastElement.focus();
|
|
9723
|
-
}
|
|
9724
|
-
} else {
|
|
9725
|
-
if (document.activeElement === lastElement) {
|
|
9726
|
-
e.preventDefault();
|
|
9727
|
-
firstElement.focus();
|
|
9728
|
-
}
|
|
9729
|
-
}
|
|
9730
|
-
};
|
|
9731
|
-
container.addEventListener("keydown", handleTabKey);
|
|
9732
|
-
return () => {
|
|
9733
|
-
container.removeEventListener("keydown", handleTabKey);
|
|
9734
|
-
if (restoreFocusOnDeactivate) {
|
|
9735
|
-
restoreFocusOnDeactivate.focus();
|
|
9736
|
-
} else if (previouslyFocused instanceof HTMLElement) {
|
|
9737
|
-
previouslyFocused.focus();
|
|
9738
|
-
}
|
|
9739
|
-
};
|
|
9740
|
-
}, [containerRef, isActive, restoreFocusOnDeactivate]);
|
|
9741
|
-
}
|
|
9742
10250
|
function useImageGallery(options = {}) {
|
|
9743
10251
|
const { images: initialImages = [], wrap = false, onOpen, onClose, onNavigate } = options;
|
|
9744
10252
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
@@ -10274,36 +10782,6 @@ function useScrollToBottom(items) {
|
|
|
10274
10782
|
scrollToBottom
|
|
10275
10783
|
};
|
|
10276
10784
|
}
|
|
10277
|
-
function useKeyboardShortcuts(shortcuts) {
|
|
10278
|
-
React.useEffect(() => {
|
|
10279
|
-
const handleKeyDown = (e) => {
|
|
10280
|
-
const target = e.target;
|
|
10281
|
-
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target.isContentEditable) {
|
|
10282
|
-
const allowInInput = shortcuts.find(
|
|
10283
|
-
(s) => s.key.toLowerCase() === e.key.toLowerCase() && s.key.toLowerCase() === "escape"
|
|
10284
|
-
);
|
|
10285
|
-
if (!allowInInput) {
|
|
10286
|
-
return;
|
|
10287
|
-
}
|
|
10288
|
-
}
|
|
10289
|
-
const matchingShortcut = shortcuts.find((s) => {
|
|
10290
|
-
const keyMatches = e.key.toLowerCase() === s.key.toLowerCase();
|
|
10291
|
-
const modMatches = s.meta ? e.metaKey && !e.ctrlKey : s.ctrl ? e.ctrlKey || e.metaKey : !e.ctrlKey && !e.metaKey;
|
|
10292
|
-
const shiftMatches = s.shift ? e.shiftKey : !e.shiftKey;
|
|
10293
|
-
const altMatches = s.alt ? e.altKey : !e.altKey;
|
|
10294
|
-
return keyMatches && modMatches && shiftMatches && altMatches;
|
|
10295
|
-
});
|
|
10296
|
-
if (matchingShortcut) {
|
|
10297
|
-
if (matchingShortcut.preventDefault !== false) {
|
|
10298
|
-
e.preventDefault();
|
|
10299
|
-
}
|
|
10300
|
-
matchingShortcut.callback();
|
|
10301
|
-
}
|
|
10302
|
-
};
|
|
10303
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
10304
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
10305
|
-
}, [shortcuts]);
|
|
10306
|
-
}
|
|
10307
10785
|
|
|
10308
10786
|
// ui/src/bichat/index.ts
|
|
10309
10787
|
init_IotaContext();
|
|
@@ -11225,6 +11703,7 @@ exports.AttachmentGrid = MemoizedAttachmentGrid;
|
|
|
11225
11703
|
exports.AttachmentPreview = AttachmentPreview_default;
|
|
11226
11704
|
exports.AttachmentUpload = AttachmentUpload_default;
|
|
11227
11705
|
exports.Avatar = Avatar;
|
|
11706
|
+
exports.BiChatLayout = BiChatLayout;
|
|
11228
11707
|
exports.Bubble = Bubble;
|
|
11229
11708
|
exports.CHART_VISUAL = CHART_VISUAL;
|
|
11230
11709
|
exports.ChartCard = ChartCard;
|
|
@@ -11311,6 +11790,7 @@ exports.getValidChildren = getValidChildren;
|
|
|
11311
11790
|
exports.groupSessionsByDate = groupSessionsByDate;
|
|
11312
11791
|
exports.hasPermission = hasPermission;
|
|
11313
11792
|
exports.isImageMimeType = isImageMimeType;
|
|
11793
|
+
exports.isPermissionDeniedError = isPermissionDeniedError;
|
|
11314
11794
|
exports.lightTheme = lightTheme;
|
|
11315
11795
|
exports.listItemVariants = listItemVariants;
|
|
11316
11796
|
exports.messageContainerVariants = messageContainerVariants;
|
|
@@ -11318,6 +11798,7 @@ exports.messageVariants = messageVariants;
|
|
|
11318
11798
|
exports.scaleFadeVariants = scaleFadeVariants;
|
|
11319
11799
|
exports.sessionItemVariants = sessionItemVariants;
|
|
11320
11800
|
exports.staggerContainerVariants = staggerContainerVariants;
|
|
11801
|
+
exports.toErrorDisplay = toErrorDisplay;
|
|
11321
11802
|
exports.toastVariants = toastVariants;
|
|
11322
11803
|
exports.typingDotVariants = typingDotVariants;
|
|
11323
11804
|
exports.useActionButtonContext = useActionButtonContext;
|
|
@@ -11340,6 +11821,7 @@ exports.useModalLock = useModalLock;
|
|
|
11340
11821
|
exports.useOptionalChatMessaging = useOptionalChatMessaging;
|
|
11341
11822
|
exports.useRequiredConfig = useRequiredConfig;
|
|
11342
11823
|
exports.useScrollToBottom = useScrollToBottom;
|
|
11824
|
+
exports.useSidebarState = useSidebarState;
|
|
11343
11825
|
exports.useStreaming = useStreaming;
|
|
11344
11826
|
exports.useTheme = useTheme;
|
|
11345
11827
|
exports.useToast = useToast;
|