@iota-uz/sdk 0.4.9 → 0.4.11

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.
@@ -2,12 +2,12 @@ import React, { createContext, lazy, memo, forwardRef, useState, useRef, useMemo
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import ReactApexChart from 'react-apexcharts';
4
4
  import ApexCharts from 'apexcharts';
5
- import { X, Bug, ArrowUp, ArrowDown, Stack, Paperclip, PaperPlaneRight, CircleNotch, ArrowUUpLeft, PencilSimple, Check, Bookmark, ArrowsClockwise, Archive, Trash, DotsThree, Warning, ArrowClockwise, Image, ImageBroken, CaretLeft, CaretRight, MagnifyingGlass, WarningCircle, CaretDown, Info, CheckCircle, XCircle, Spinner, Copy, FilePdf, FileXls, FileCsv, FileDoc, FileCode, FileText, File, ChartBar, DownloadSimple, Download, ChatCircleDots, PencilSimpleLine, ArrowLeft, PaperPlaneTilt, ArrowRight, Timer, Lightning, Database, Wrench, ClockCounterClockwise, Lightbulb, Package, Plus, ArrowsCounterClockwise, Code, ArrowSquareOut, SpinnerGap, FloppyDisk, Sidebar } from '@phosphor-icons/react';
5
+ import { X, Bug, ArrowUp, ArrowDown, Stack, Paperclip, PaperPlaneRight, CircleNotch, ArrowUUpLeft, PencilSimple, Check, Bookmark, ArrowsClockwise, Archive, Trash, DotsThree, Warning, ArrowClockwise, Image, ImageBroken, CaretLeft, CaretRight, MagnifyingGlass, WarningCircle, CaretDown, Info, CheckCircle, XCircle, Spinner, Copy, FilePdf, FileXls, FileCsv, FileDoc, FileCode, FileText, File, ChartBar, DownloadSimple, Download, ChatCircleDots, PencilSimpleLine, ArrowLeft, PaperPlaneTilt, ArrowRight, Timer, Lightning, Database, Wrench, ClockCounterClockwise, Lightbulb, Package, Plus, Gear, Users, List, CaretLineLeft, CaretLineRight, ArrowsCounterClockwise, Code, ArrowSquareOut, SpinnerGap, FloppyDisk, Sidebar } from '@phosphor-icons/react';
6
6
  import { Prism } from 'react-syntax-highlighter';
7
7
  import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
8
8
  import ReactMarkdown from 'react-markdown';
9
9
  import remarkGfm from 'remark-gfm';
10
- import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
10
+ import { useMotionValue, useTransform, motion, AnimatePresence, useReducedMotion } from 'framer-motion';
11
11
  import { formatDistanceToNow, startOfDay, differenceInDays } from 'date-fns';
12
12
  import { Menu, MenuButton, MenuItems, MenuItem, Dialog, DialogBackdrop, DialogPanel, DialogTitle, Description, Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react';
13
13
  import { createPortal } from 'react-dom';
@@ -49,23 +49,25 @@ var init_IotaContext = __esm({
49
49
  IotaContext = createContext(null);
50
50
  }
51
51
  });
52
-
53
- // ui/src/bichat/hooks/useTranslation.ts
54
52
  function useTranslation() {
55
53
  const { locale } = useIotaContext();
56
- const t = (key2, params) => {
57
- let text = locale.translations[key2] || key2;
58
- if (params) {
59
- Object.keys(params).forEach((paramKey) => {
60
- const value = params[paramKey];
61
- text = text.replace(new RegExp(`{{${paramKey}}}`, "g"), String(value));
62
- });
63
- }
64
- return text;
65
- };
54
+ const { translations, language } = locale;
55
+ const t = useCallback(
56
+ (key2, params) => {
57
+ let text = translations[key2] || key2;
58
+ if (params) {
59
+ Object.keys(params).forEach((paramKey) => {
60
+ const value = params[paramKey];
61
+ text = text.replace(new RegExp(`{{${paramKey}}}`, "g"), String(value));
62
+ });
63
+ }
64
+ return text;
65
+ },
66
+ [translations]
67
+ );
66
68
  return {
67
69
  t,
68
- locale: locale.language
70
+ locale: language
69
71
  };
70
72
  }
71
73
  var init_useTranslation = __esm({
@@ -85,7 +87,7 @@ function ChartCard({ chartData }) {
85
87
  title,
86
88
  ": "
87
89
  ] }),
88
- t("Chart.NoData")
90
+ t("BiChat.Chart.NoData")
89
91
  ] }) });
90
92
  }
91
93
  const apexSeries = chartType === "pie" || chartType === "donut" ? series[0]?.data ?? [] : series.map((s) => ({ name: s.name, data: s.data }));
@@ -161,10 +163,10 @@ function ChartCard({ chartData }) {
161
163
  onClick: handleExportPNG,
162
164
  disabled: isExporting,
163
165
  className: "inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-gray-400 opacity-0 transition-all duration-150 hover:bg-gray-100 hover:text-gray-600 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 group-hover/chart:opacity-100 disabled:opacity-50 dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-gray-300",
164
- title: t("Chart.Download"),
165
- children: isExporting ? /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400", children: t("Chart.Exporting") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
166
+ title: t("BiChat.Chart.Download"),
167
+ children: isExporting ? /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400", children: t("BiChat.Chart.Exporting") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
166
168
  /* @__PURE__ */ jsx(DownloadSimple, { className: "h-3.5 w-3.5", weight: "bold" }),
167
- /* @__PURE__ */ jsx("span", { children: t("Chart.DownloadPNG") })
169
+ /* @__PURE__ */ jsx("span", { children: t("BiChat.Chart.DownloadPNG") })
168
170
  ] })
169
171
  }
170
172
  ) })
@@ -1496,8 +1498,8 @@ function useBranding() {
1496
1498
  appName: customBranding.appName || "BiChat",
1497
1499
  logoUrl: customBranding.logoUrl,
1498
1500
  welcome: {
1499
- title: customBranding.welcome?.title || t("Welcome.Title"),
1500
- description: customBranding.welcome?.description || t("Welcome.Description"),
1501
+ title: customBranding.welcome?.title || t("BiChat.Welcome.Title"),
1502
+ description: customBranding.welcome?.description || t("BiChat.Welcome.Description"),
1501
1503
  examplePrompts
1502
1504
  },
1503
1505
  theme: customBranding.theme
@@ -1513,7 +1515,7 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1513
1515
  {
1514
1516
  onClick: onBack,
1515
1517
  className: "cursor-pointer p-2 hover:bg-gray-100 dark:hover:bg-gray-700 active:bg-gray-200 dark:active:bg-gray-600 rounded-lg transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
1516
- "aria-label": t("Chat.GoBack"),
1518
+ "aria-label": t("BiChat.Chat.GoBack"),
1517
1519
  children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1518
1520
  }
1519
1521
  ) : null;
@@ -1523,7 +1525,7 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1523
1525
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1524
1526
  BackButton,
1525
1527
  Logo,
1526
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)]", children: t("Chat.NewChat") })
1528
+ /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)]", children: t("BiChat.Chat.NewChat") })
1527
1529
  ] }),
1528
1530
  actionsSlot && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: actionsSlot })
1529
1531
  ] }) });
@@ -1539,14 +1541,14 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1539
1541
  className: "w-4 h-4 text-[var(--bichat-primary)]",
1540
1542
  fill: "currentColor",
1541
1543
  viewBox: "0 0 20 20",
1542
- "aria-label": t("Chat.Pinned"),
1544
+ "aria-label": t("BiChat.Chat.Pinned"),
1543
1545
  children: /* @__PURE__ */ jsx("path", { d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1z" })
1544
1546
  }
1545
1547
  )
1546
1548
  ] }),
1547
1549
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1548
- readOnly && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("Chat.ReadOnly") }),
1549
- session.status === "archived" && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("Chat.Archived") }),
1550
+ readOnly && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("BiChat.Chat.ReadOnly") }),
1551
+ session.status === "archived" && /* @__PURE__ */ jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("BiChat.Chat.Archived") }),
1550
1552
  actionsSlot
1551
1553
  ] })
1552
1554
  ] }) });
@@ -1963,6 +1965,7 @@ function AttachmentGrid({
1963
1965
  var MemoizedAttachmentGrid = React.memo(AttachmentGrid);
1964
1966
  MemoizedAttachmentGrid.displayName = "AttachmentGrid";
1965
1967
  var AttachmentGrid_default = MemoizedAttachmentGrid;
1968
+ init_useTranslation();
1966
1969
  function ImageModal({
1967
1970
  isOpen,
1968
1971
  onClose,
@@ -1971,6 +1974,7 @@ function ImageModal({
1971
1974
  currentIndex = 0,
1972
1975
  onNavigate
1973
1976
  }) {
1977
+ const { t } = useTranslation();
1974
1978
  const [isImageLoaded, setIsImageLoaded] = useState(false);
1975
1979
  const [imageError, setImageError] = useState(false);
1976
1980
  const [retryKey, setRetryKey] = useState(0);
@@ -2023,7 +2027,7 @@ function ImageModal({
2023
2027
  {
2024
2028
  onClick: onClose,
2025
2029
  className: "cursor-pointer flex items-center justify-center w-8 h-8 rounded-md bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
2026
- "aria-label": "Close modal",
2030
+ "aria-label": t("BiChat.Image.Close"),
2027
2031
  type: "button",
2028
2032
  children: /* @__PURE__ */ jsx(X, { size: 18, weight: "bold" })
2029
2033
  }
@@ -2039,11 +2043,11 @@ function ImageModal({
2039
2043
  children: [
2040
2044
  !isImageLoaded && !imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
2041
2045
  /* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-2 border-gray-300 dark:border-gray-700 border-t-gray-500 dark:border-t-gray-400 rounded-full animate-spin" }),
2042
- /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: "Loading" })
2046
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: t("BiChat.Loading") })
2043
2047
  ] }) }),
2044
2048
  imageError && /* @__PURE__ */ jsxs("div", { role: "alert", className: "flex flex-col items-center justify-center text-center max-w-xs", children: [
2045
2049
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-16 h-16 rounded-2xl bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 mb-5", children: /* @__PURE__ */ jsx(ImageBroken, { size: 28, className: "text-gray-400 dark:text-gray-500", weight: "duotone" }) }),
2046
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Failed to load image" }),
2050
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: t("BiChat.Image.FailedToLoad") }),
2047
2051
  /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 mb-5 truncate max-w-full", children: attachment.filename }),
2048
2052
  /* @__PURE__ */ jsxs(
2049
2053
  "button",
@@ -2051,10 +2055,10 @@ function ImageModal({
2051
2055
  type: "button",
2052
2056
  onClick: handleRetry,
2053
2057
  className: "cursor-pointer inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
2054
- "aria-label": "Retry loading image",
2058
+ "aria-label": t("BiChat.Image.Retry"),
2055
2059
  children: [
2056
2060
  /* @__PURE__ */ jsx(ArrowClockwise, { size: 16, weight: "bold" }),
2057
- "Retry"
2061
+ t("BiChat.Retry.Label")
2058
2062
  ]
2059
2063
  }
2060
2064
  )
@@ -2088,7 +2092,7 @@ function ImageModal({
2088
2092
  "transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
2089
2093
  canNavigatePrev && isImageLoaded && !imageError ? "cursor-pointer bg-white/90 hover:bg-white dark:bg-gray-800/90 dark:hover:bg-gray-700 text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white shadow-sm" : "bg-white/40 dark:bg-gray-800/40 text-gray-300 dark:text-gray-700 cursor-not-allowed"
2090
2094
  ].join(" "),
2091
- "aria-label": "Previous image",
2095
+ "aria-label": t("BiChat.Image.Previous"),
2092
2096
  type: "button",
2093
2097
  children: /* @__PURE__ */ jsx(CaretLeft, { size: 20, weight: "bold" })
2094
2098
  }
@@ -2104,7 +2108,7 @@ function ImageModal({
2104
2108
  "transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
2105
2109
  canNavigateNext && isImageLoaded && !imageError ? "cursor-pointer bg-white/90 hover:bg-white dark:bg-gray-800/90 dark:hover:bg-gray-700 text-gray-700 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white shadow-sm" : "bg-white/40 dark:bg-gray-800/40 text-gray-300 dark:text-gray-700 cursor-not-allowed"
2106
2110
  ].join(" "),
2107
- "aria-label": "Next image",
2111
+ "aria-label": t("BiChat.Image.Next"),
2108
2112
  type: "button",
2109
2113
  children: /* @__PURE__ */ jsx(CaretRight, { size: 20, weight: "bold" })
2110
2114
  }
@@ -2351,7 +2355,7 @@ function UserMessage({
2351
2355
  onClick: handleCopyClick,
2352
2356
  className: `cursor-pointer ${classes.actionButton} ${isCopied ? "text-green-600 dark:text-green-400" : ""}`,
2353
2357
  "aria-label": "Copy message",
2354
- title: isCopied ? t("Message.Copied") : t("Message.Copy"),
2358
+ title: isCopied ? t("BiChat.Message.Copied") : t("BiChat.Message.Copy"),
2355
2359
  children: isCopied ? /* @__PURE__ */ jsx(Check, { size: 14, weight: "bold" }) : /* @__PURE__ */ jsx(Copy, { size: 14, weight: "regular" })
2356
2360
  }
2357
2361
  ),
@@ -2593,8 +2597,10 @@ function DownloadCard({ artifact }) {
2593
2597
  }
2594
2598
  );
2595
2599
  }
2600
+ init_useTranslation();
2596
2601
  function InlineQuestionForm({ pendingQuestion }) {
2597
2602
  const { handleSubmitQuestionAnswers, handleRejectPendingQuestion, loading } = useChatMessaging();
2603
+ const { t } = useTranslation();
2598
2604
  const [currentStep, setCurrentStep] = useState(0);
2599
2605
  const [answers, setAnswers] = useState({});
2600
2606
  const [otherTexts, setOtherTexts] = useState({});
@@ -2697,11 +2703,11 @@ function InlineQuestionForm({ pendingQuestion }) {
2697
2703
  const options = currentQuestion.options || [];
2698
2704
  const isOtherSelected = currentAnswer?.customText !== void 0;
2699
2705
  const canProceed = isCurrentAnswerValid();
2700
- return /* @__PURE__ */ jsx("div", { className: "animate-slide-up rounded-2xl border border-primary-200 dark:border-primary-800/50 bg-gradient-to-b from-primary-50/80 to-white dark:from-primary-950/30 dark:to-gray-900/80 shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
2706
+ return /* @__PURE__ */ jsx("div", { className: "animate-slide-up rounded-2xl border border-gray-200 dark:border-gray-700/50 bg-gradient-to-b from-primary-50/80 to-white dark:from-primary-950/30 dark:to-gray-900/80 shadow-sm overflow-hidden", children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
2701
2707
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 pt-4 pb-3", children: [
2702
2708
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-7 h-7 rounded-lg bg-primary-100 dark:bg-primary-900/40", children: /* @__PURE__ */ jsx(ChatCircleDots, { className: "w-4 h-4 text-primary-600 dark:text-primary-400", weight: "fill" }) }),
2703
2709
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2704
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-primary-600 dark:text-primary-400", children: "Input needed" }),
2710
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-primary-600 dark:text-primary-400", children: t("BiChat.InlineQuestion.InputNeeded") }),
2705
2711
  totalSteps > 1 && /* @__PURE__ */ jsxs("span", { className: "text-[11px] tabular-nums text-gray-400 dark:text-gray-500", children: [
2706
2712
  currentStep + 1,
2707
2713
  "/",
@@ -2715,7 +2721,7 @@ function InlineQuestionForm({ pendingQuestion }) {
2715
2721
  onClick: handleRejectPendingQuestion,
2716
2722
  disabled: loading,
2717
2723
  className: "cursor-pointer p-1 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors disabled:opacity-40",
2718
- "aria-label": "Dismiss",
2724
+ "aria-label": t("BiChat.InlineQuestion.Dismiss"),
2719
2725
  children: /* @__PURE__ */ jsx(X, { size: 16, weight: "bold" })
2720
2726
  }
2721
2727
  )
@@ -2737,7 +2743,7 @@ function InlineQuestionForm({ pendingQuestion }) {
2737
2743
  }) }),
2738
2744
  /* @__PURE__ */ jsxs("div", { className: "px-4 pb-3", children: [
2739
2745
  /* @__PURE__ */ jsx("p", { className: "text-[15px] leading-relaxed text-gray-800 dark:text-gray-200", children: currentQuestion.text }),
2740
- isMultiSelect && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400 dark:text-gray-500", children: "Select all that apply" })
2746
+ isMultiSelect && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400 dark:text-gray-500", children: t("BiChat.InlineQuestion.SelectAllThatApply") })
2741
2747
  ] }),
2742
2748
  /* @__PURE__ */ jsxs("div", { className: "px-4 pb-2 space-y-1.5", children: [
2743
2749
  options.map((option) => {
@@ -2816,18 +2822,17 @@ function InlineQuestionForm({ pendingQuestion }) {
2816
2822
  /* @__PURE__ */ jsx("span", { className: [
2817
2823
  "text-sm transition-colors duration-150",
2818
2824
  isOtherSelected ? "text-gray-900 dark:text-gray-100 font-medium" : "text-gray-700 dark:text-gray-300"
2819
- ].join(" "), children: "Other" })
2825
+ ].join(" "), children: t("BiChat.InlineQuestion.OtherOption") })
2820
2826
  ]
2821
2827
  }
2822
2828
  ),
2823
- isOtherSelected && /* @__PURE__ */ jsx("div", { className: "pl-8 pr-1 pb-1 animate-slide-up", children: /* @__PURE__ */ jsx(
2829
+ /* @__PURE__ */ jsx("div", { className: "pl-8 pr-1 pb-1", children: /* @__PURE__ */ jsx(
2824
2830
  "input",
2825
2831
  {
2826
2832
  type: "text",
2827
2833
  value: currentOtherText,
2828
2834
  onChange: (e) => handleOtherTextChange(e.target.value),
2829
- placeholder: "Type your answer...",
2830
- autoFocus: true,
2835
+ placeholder: t("BiChat.InlineQuestion.TypeYourAnswer"),
2831
2836
  className: "w-full px-3 py-2 text-sm border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 dark:placeholder:text-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500/40 focus:border-primary-400 dark:focus:border-primary-600 transition-shadow"
2832
2837
  }
2833
2838
  ) })
@@ -2841,7 +2846,7 @@ function InlineQuestionForm({ pendingQuestion }) {
2841
2846
  className: "cursor-pointer flex items-center gap-1 px-2.5 py-1.5 text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors",
2842
2847
  children: [
2843
2848
  /* @__PURE__ */ jsx(ArrowLeft, { size: 14, weight: "bold" }),
2844
- "Back"
2849
+ t("BiChat.InlineQuestion.Back")
2845
2850
  ]
2846
2851
  }
2847
2852
  ) }),
@@ -2856,10 +2861,10 @@ function InlineQuestionForm({ pendingQuestion }) {
2856
2861
  canProceed ? "cursor-pointer bg-primary-600 hover:bg-primary-700 active:bg-primary-800 text-white shadow-sm hover:shadow" : "bg-gray-100 dark:bg-gray-800 text-gray-400 dark:text-gray-600 cursor-not-allowed"
2857
2862
  ].join(" "),
2858
2863
  children: isLastStep ? /* @__PURE__ */ jsxs(Fragment, { children: [
2859
- "Submit",
2864
+ t("BiChat.Submit"),
2860
2865
  /* @__PURE__ */ jsx(PaperPlaneTilt, { size: 14, weight: "fill" })
2861
2866
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2862
- "Next",
2867
+ t("BiChat.InlineQuestion.Next"),
2863
2868
  /* @__PURE__ */ jsx(ArrowRight, { size: 14, weight: "bold" })
2864
2869
  ] })
2865
2870
  }
@@ -3028,13 +3033,13 @@ function ToolCard({ tool }) {
3028
3033
  children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden min-h-0", children: /* @__PURE__ */ jsxs("div", { className: "px-3 pb-3 pt-1 space-y-2", children: [
3029
3034
  tool.arguments && /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-[#1a1b26] dark:bg-gray-950 overflow-hidden ring-1 ring-gray-800/10 dark:ring-white/5", children: [
3030
3035
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 bg-[#1e1f2e] dark:bg-gray-900/80 border-b border-white/5", children: [
3031
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("Slash.DebugArguments") }),
3036
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("BiChat.Slash.DebugArguments") }),
3032
3037
  /* @__PURE__ */ jsx(
3033
3038
  CopyPill,
3034
3039
  {
3035
3040
  text: tool.arguments,
3036
- label: t("Slash.DebugCopyTrace"),
3037
- copiedLabel: t("Slash.DebugCopied")
3041
+ label: t("BiChat.Slash.DebugCopyTrace"),
3042
+ copiedLabel: t("BiChat.Slash.DebugCopied")
3038
3043
  }
3039
3044
  )
3040
3045
  ] }),
@@ -3042,20 +3047,20 @@ function ToolCard({ tool }) {
3042
3047
  ] }),
3043
3048
  tool.result && /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-[#1a1b26] dark:bg-gray-950 overflow-hidden ring-1 ring-gray-800/10 dark:ring-white/5", children: [
3044
3049
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 bg-[#1e1f2e] dark:bg-gray-900/80 border-b border-white/5", children: [
3045
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("Slash.DebugResult") }),
3050
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("BiChat.Slash.DebugResult") }),
3046
3051
  /* @__PURE__ */ jsx(
3047
3052
  CopyPill,
3048
3053
  {
3049
3054
  text: tool.result,
3050
- label: t("Slash.DebugCopyTrace"),
3051
- copiedLabel: t("Slash.DebugCopied")
3055
+ label: t("BiChat.Slash.DebugCopyTrace"),
3056
+ copiedLabel: t("BiChat.Slash.DebugCopied")
3052
3057
  }
3053
3058
  )
3054
3059
  ] }),
3055
3060
  /* @__PURE__ */ jsx("pre", { className: "p-3 text-[11px] font-mono text-gray-300 overflow-x-auto max-h-60 overflow-y-auto whitespace-pre-wrap break-all leading-relaxed", children: tool.result })
3056
3061
  ] }),
3057
3062
  tool.error && /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-red-950/80 dark:bg-red-950/40 overflow-hidden ring-1 ring-red-800/20", children: [
3058
- /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 border-b border-red-800/20", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-red-400", children: t("Slash.DebugError") }) }),
3063
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 border-b border-red-800/20", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-red-400", children: t("BiChat.Slash.DebugError") }) }),
3059
3064
  /* @__PURE__ */ jsx("pre", { className: "p-3 text-[11px] font-mono text-red-300 overflow-x-auto whitespace-pre-wrap break-all leading-relaxed", children: tool.error })
3060
3065
  ] })
3061
3066
  ] }) })
@@ -3075,7 +3080,7 @@ function DebugPanel({ trace }) {
3075
3080
  metrics.push({
3076
3081
  icon: /* @__PURE__ */ jsx(Timer, { size: 14, weight: "duotone", className: "text-amber-600 dark:text-amber-400" }),
3077
3082
  value: formatGenerationDuration(trace.generationMs),
3078
- label: t("Slash.DebugGeneration"),
3083
+ label: t("BiChat.Slash.DebugGeneration"),
3079
3084
  accentBorder: "border-l-amber-400 dark:border-l-amber-500",
3080
3085
  accentBg: "bg-amber-50 dark:bg-amber-950/30"
3081
3086
  });
@@ -3084,7 +3089,7 @@ function DebugPanel({ trace }) {
3084
3089
  metrics.push({
3085
3090
  icon: /* @__PURE__ */ jsx(Lightning, { size: 14, weight: "fill", className: "text-orange-500 dark:text-orange-400" }),
3086
3091
  value: `${tokensPerSecond.toFixed(1)}/s`,
3087
- label: t("Slash.DebugTokensPerSecond"),
3092
+ label: t("BiChat.Slash.DebugTokensPerSecond"),
3088
3093
  accentBorder: "border-l-orange-400 dark:border-l-orange-500",
3089
3094
  accentBg: "bg-orange-50 dark:bg-orange-950/30"
3090
3095
  });
@@ -3094,21 +3099,21 @@ function DebugPanel({ trace }) {
3094
3099
  {
3095
3100
  icon: /* @__PURE__ */ jsx(Stack, { size: 14, weight: "duotone", className: "text-violet-600 dark:text-violet-400" }),
3096
3101
  value: trace.usage.totalTokens.toLocaleString(),
3097
- label: t("Slash.DebugTotalTokens"),
3102
+ label: t("BiChat.Slash.DebugTotalTokens"),
3098
3103
  accentBorder: "border-l-violet-400 dark:border-l-violet-500",
3099
3104
  accentBg: "bg-violet-50 dark:bg-violet-950/30"
3100
3105
  },
3101
3106
  {
3102
3107
  icon: /* @__PURE__ */ jsx(ArrowUp, { size: 14, weight: "bold", className: "text-blue-600 dark:text-blue-400" }),
3103
3108
  value: trace.usage.promptTokens.toLocaleString(),
3104
- label: t("Slash.DebugPromptTokens"),
3109
+ label: t("BiChat.Slash.DebugPromptTokens"),
3105
3110
  accentBorder: "border-l-blue-400 dark:border-l-blue-500",
3106
3111
  accentBg: "bg-blue-50 dark:bg-blue-950/30"
3107
3112
  },
3108
3113
  {
3109
3114
  icon: /* @__PURE__ */ jsx(ArrowDown, { size: 14, weight: "bold", className: "text-indigo-600 dark:text-indigo-400" }),
3110
3115
  value: trace.usage.completionTokens.toLocaleString(),
3111
- label: t("Slash.DebugCompletionTokens"),
3116
+ label: t("BiChat.Slash.DebugCompletionTokens"),
3112
3117
  accentBorder: "border-l-indigo-400 dark:border-l-indigo-500",
3113
3118
  accentBg: "bg-indigo-50 dark:bg-indigo-950/30"
3114
3119
  }
@@ -3117,7 +3122,7 @@ function DebugPanel({ trace }) {
3117
3122
  metrics.push({
3118
3123
  icon: /* @__PURE__ */ jsx(Database, { size: 14, weight: "duotone", className: "text-pink-600 dark:text-pink-400" }),
3119
3124
  value: trace.usage.cachedTokens.toLocaleString(),
3120
- label: t("Slash.DebugCachedTokens"),
3125
+ label: t("BiChat.Slash.DebugCachedTokens"),
3121
3126
  accentBorder: "border-l-pink-400 dark:border-l-pink-500",
3122
3127
  accentBg: "bg-pink-50 dark:bg-pink-950/30"
3123
3128
  });
@@ -3128,14 +3133,14 @@ function DebugPanel({ trace }) {
3128
3133
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
3129
3134
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
3130
3135
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-6 h-6 rounded-lg bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsx(Bug, { size: 14, weight: "duotone", className: "text-gray-500 dark:text-gray-400" }) }),
3131
- /* @__PURE__ */ jsx("h3", { className: "text-[11px] uppercase tracking-widest font-semibold text-gray-400 dark:text-gray-500", children: t("Slash.DebugPanelTitle") })
3136
+ /* @__PURE__ */ jsx("h3", { className: "text-[11px] uppercase tracking-widest font-semibold text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.DebugPanelTitle") })
3132
3137
  ] }),
3133
3138
  hasData && trace && /* @__PURE__ */ jsx(
3134
3139
  CopyPill,
3135
3140
  {
3136
3141
  text: JSON.stringify(trace, null, 2),
3137
- label: t("Slash.DebugCopyTrace"),
3138
- copiedLabel: t("Slash.DebugCopied")
3142
+ label: t("BiChat.Slash.DebugCopyTrace"),
3143
+ copiedLabel: t("BiChat.Slash.DebugCopied")
3139
3144
  }
3140
3145
  )
3141
3146
  ] }),
@@ -3144,12 +3149,12 @@ function DebugPanel({ trace }) {
3144
3149
  trace.tools.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
3145
3150
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2.5", children: [
3146
3151
  /* @__PURE__ */ jsx(Wrench, { size: 13, weight: "duotone", className: "text-gray-400 dark:text-gray-500" }),
3147
- /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-gray-500 dark:text-gray-400", children: t("Slash.DebugToolCalls") }),
3152
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-gray-500 dark:text-gray-400", children: t("BiChat.Slash.DebugToolCalls") }),
3148
3153
  /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 rounded-full bg-gray-100 dark:bg-gray-800 text-[10px] font-mono font-medium text-gray-500 dark:text-gray-400 tabular-nums", children: trace.tools.length })
3149
3154
  ] }),
3150
3155
  /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: trace.tools.map((tool, idx) => /* @__PURE__ */ jsx(ToolCard, { tool }, `${tool.callId || tool.name}-${idx}`)) })
3151
3156
  ] })
3152
- ] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: t("Slash.DebugUnavailable") })
3157
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: t("BiChat.Slash.DebugUnavailable") })
3153
3158
  ] });
3154
3159
  }
3155
3160
 
@@ -3355,7 +3360,7 @@ function AssistantMessage({
3355
3360
  )
3356
3361
  }
3357
3362
  ),
3358
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("Assistant.Explanation") })
3363
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("BiChat.Assistant.Explanation") })
3359
3364
  ]
3360
3365
  }
3361
3366
  ),
@@ -3381,7 +3386,7 @@ function AssistantMessage({
3381
3386
  onClick: handleCopyClick,
3382
3387
  className: `cursor-pointer ${classes.actionButton} ${isCopied ? "text-green-600 dark:text-green-400" : ""}`,
3383
3388
  "aria-label": "Copy message",
3384
- title: isCopied ? t("Message.Copied") : t("Message.Copy"),
3389
+ title: isCopied ? t("BiChat.Message.Copied") : t("BiChat.Message.Copy"),
3385
3390
  children: isCopied ? /* @__PURE__ */ jsx(Check, { size: 14, weight: "bold" }) : /* @__PURE__ */ jsx(Copy, { size: 14, weight: "regular" })
3386
3391
  }
3387
3392
  ),
@@ -3475,7 +3480,7 @@ function SystemMessage({
3475
3480
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 pt-3 pb-2", children: [
3476
3481
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-gray-400 dark:text-gray-500", children: [
3477
3482
  /* @__PURE__ */ jsx(ClockCounterClockwise, { size: 13, weight: "bold" }),
3478
- /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider", children: t("System.ConversationSummary") })
3483
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider", children: t("BiChat.System.ConversationSummary") })
3479
3484
  ] }),
3480
3485
  /* @__PURE__ */ jsx("div", { className: "flex-1" }),
3481
3486
  !hideActions && !hideTimestamp && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 tabular-nums", children: timestamp }),
@@ -3489,7 +3494,7 @@ function SystemMessage({
3489
3494
  ${isCopied ? "text-green-600 dark:text-green-400" : "text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-200/50 dark:hover:bg-gray-700/40"}
3490
3495
  `,
3491
3496
  "aria-label": "Copy message",
3492
- title: isCopied ? t("Message.Copied") : t("Message.Copy"),
3497
+ title: isCopied ? t("BiChat.Message.Copied") : t("BiChat.Message.Copy"),
3493
3498
  children: isCopied ? /* @__PURE__ */ jsx(Check, { size: 13, weight: "bold" }) : /* @__PURE__ */ jsx(Copy, { size: 13, weight: "regular" })
3494
3499
  }
3495
3500
  )
@@ -3507,7 +3512,7 @@ function SystemMessage({
3507
3512
  {
3508
3513
  fallback: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-400 dark:text-gray-500 py-2", children: [
3509
3514
  /* @__PURE__ */ jsx("div", { className: "w-3.5 h-3.5 border-[1.5px] border-gray-300 dark:border-gray-600 border-t-transparent rounded-full animate-spin" }),
3510
- /* @__PURE__ */ jsx("span", { className: "text-xs", children: t("System.LoadingSummary") })
3515
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: t("BiChat.System.LoadingSummary") })
3511
3516
  ] }),
3512
3517
  children: /* @__PURE__ */ jsx(MarkdownRenderer3, { content, sendDisabled: true })
3513
3518
  }
@@ -3524,7 +3529,7 @@ function SystemMessage({
3524
3529
  "aria-expanded": isExpanded,
3525
3530
  className: "cursor-pointer group/toggle inline-flex items-center gap-1 px-3 py-1 rounded-full text-[11px] font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-200/60 dark:hover:bg-gray-700/50 transition-colors duration-150",
3526
3531
  children: [
3527
- /* @__PURE__ */ jsx("span", { children: isExpanded ? t("System.ShowLess") : t("System.ShowMore") }),
3532
+ /* @__PURE__ */ jsx("span", { children: isExpanded ? t("BiChat.System.ShowLess") : t("BiChat.System.ShowMore") }),
3528
3533
  /* @__PURE__ */ jsx(
3529
3534
  CaretDown,
3530
3535
  {
@@ -3888,13 +3893,16 @@ var errorMessageVariants = {
3888
3893
  }
3889
3894
  }
3890
3895
  };
3891
- var DEFAULT_VERBS = [
3892
- "Thinking",
3893
- "Processing",
3894
- "Analyzing",
3895
- "Synthesizing",
3896
- "Computing",
3897
- "Working on it"
3896
+
3897
+ // ui/src/bichat/components/TypingIndicator.tsx
3898
+ init_useTranslation();
3899
+ var THINKING_KEYS = [
3900
+ "BiChat.Thinking.Thinking",
3901
+ "BiChat.Thinking.Processing",
3902
+ "BiChat.Thinking.Analyzing",
3903
+ "BiChat.Thinking.Synthesizing",
3904
+ "BiChat.Thinking.Computing",
3905
+ "BiChat.Thinking.WorkingOnIt"
3898
3906
  ];
3899
3907
  var prefersReducedMotion2 = () => {
3900
3908
  if (typeof window === "undefined") return false;
@@ -3908,10 +3916,15 @@ var getRandomVerb = (verbs, current) => {
3908
3916
  return available[Math.floor(Math.random() * available.length)];
3909
3917
  };
3910
3918
  function TypingIndicator({
3911
- verbs = DEFAULT_VERBS,
3919
+ verbs: verbsProp,
3912
3920
  rotationInterval = 3e3,
3913
3921
  className = ""
3914
3922
  }) {
3923
+ const { t } = useTranslation();
3924
+ const verbs = useMemo(() => {
3925
+ if (verbsProp) return verbsProp;
3926
+ return THINKING_KEYS.map((key2) => t(key2));
3927
+ }, [verbsProp, t]);
3915
3928
  const [verb, setVerb] = useState(() => verbs[Math.floor(Math.random() * verbs.length)]);
3916
3929
  useEffect(() => {
3917
3930
  if (prefersReducedMotion2()) return;
@@ -4096,8 +4109,8 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
4096
4109
  isCompacting && /* @__PURE__ */ jsx(
4097
4110
  CompactionDoodle_default,
4098
4111
  {
4099
- title: t("Slash.CompactingTitle"),
4100
- subtitle: t("Slash.CompactingSubtitle")
4112
+ title: t("BiChat.Slash.CompactingTitle"),
4113
+ subtitle: t("BiChat.Slash.CompactingSubtitle")
4101
4114
  }
4102
4115
  ),
4103
4116
  fetching && turns.length === 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-6", "aria-hidden": "true", children: [
@@ -4198,7 +4211,7 @@ var MessageInput = forwardRef(
4198
4211
  const [dropSuccess, setDropSuccess] = useState(false);
4199
4212
  const [pendingFileCount, setPendingFileCount] = useState(0);
4200
4213
  const [viewingImageIndex, setViewingImageIndex] = useState(null);
4201
- const placeholder = placeholderOverride || t("Input.Placeholder");
4214
+ const placeholder = placeholderOverride || t("BiChat.Input.Placeholder");
4202
4215
  const textareaRef = useRef(null);
4203
4216
  const fileInputRef = useRef(null);
4204
4217
  const containerRef = useRef(null);
@@ -4209,9 +4222,9 @@ var MessageInput = forwardRef(
4209
4222
  const commandQuery = message.trimStart().slice(1).split(/\s+/)[0]?.toLowerCase() || "";
4210
4223
  const slashCommands = useMemo(
4211
4224
  () => [
4212
- { name: "/clear", description: t("Slash.ClearDescription") },
4213
- { name: "/debug", description: t("Slash.DebugDescription") },
4214
- { name: "/compact", description: t("Slash.CompactDescription") }
4225
+ { name: "/clear", description: t("BiChat.Slash.ClearDescription") },
4226
+ { name: "/debug", description: t("BiChat.Slash.DebugDescription") },
4227
+ { name: "/compact", description: t("BiChat.Slash.CompactDescription") }
4215
4228
  ],
4216
4229
  [t]
4217
4230
  );
@@ -4501,12 +4514,12 @@ var MessageInput = forwardRef(
4501
4514
  onClearCommandError?.();
4502
4515
  },
4503
4516
  className: "cursor-pointer ml-2 p-1 hover:bg-red-100 dark:hover:bg-red-800 rounded transition-colors",
4504
- "aria-label": t("Input.DismissError"),
4517
+ "aria-label": t("BiChat.Input.DismissError"),
4505
4518
  children: /* @__PURE__ */ jsx(X, { size: 14 })
4506
4519
  }
4507
4520
  )
4508
4521
  ] }),
4509
- messageQueue.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 text-xs text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsx("span", { className: "px-2.5 py-1 bg-primary-50 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded font-medium", children: t("Input.MessagesQueued", { count: messageQueue.length }) }) }),
4522
+ messageQueue.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 text-xs text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsx("span", { className: "px-2.5 py-1 bg-primary-50 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded font-medium", children: t("BiChat.Input.MessagesQueued", { count: messageQueue.length }) }) }),
4510
4523
  debugMode && /* @__PURE__ */ jsxs("div", { className: "mb-3 space-y-2 text-xs", children: [
4511
4524
  /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-1 bg-amber-100 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300 rounded-full font-medium text-[11px]", children: [
4512
4525
  /* @__PURE__ */ jsxs("span", { className: "relative flex h-1.5 w-1.5", "aria-hidden": "true", children: [
@@ -4514,49 +4527,49 @@ var MessageInput = forwardRef(
4514
4527
  /* @__PURE__ */ jsx("span", { className: "relative inline-flex rounded-full h-1.5 w-1.5 bg-amber-500" })
4515
4528
  ] }),
4516
4529
  /* @__PURE__ */ jsx(Bug, { size: 12 }),
4517
- t("Slash.DebugBadge")
4530
+ t("BiChat.Slash.DebugBadge")
4518
4531
  ] }),
4519
4532
  /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/30 p-3 space-y-3", children: [
4520
4533
  hasUsage ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-1.5", children: [
4521
4534
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4522
4535
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4523
4536
  /* @__PURE__ */ jsx(ArrowUp, { size: 10, weight: "bold", className: "text-blue-500 dark:text-blue-400" }),
4524
- t("Slash.DebugPromptTokens")
4537
+ t("BiChat.Slash.DebugPromptTokens")
4525
4538
  ] }),
4526
4539
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionPromptTokens) })
4527
4540
  ] }),
4528
4541
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4529
4542
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4530
4543
  /* @__PURE__ */ jsx(ArrowDown, { size: 10, weight: "bold", className: "text-indigo-500 dark:text-indigo-400" }),
4531
- t("Slash.DebugCompletionTokens")
4544
+ t("BiChat.Slash.DebugCompletionTokens")
4532
4545
  ] }),
4533
4546
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionCompletionTokens) })
4534
4547
  ] }),
4535
4548
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4536
4549
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4537
4550
  /* @__PURE__ */ jsx(Stack, { size: 10, weight: "bold", className: "text-violet-500 dark:text-violet-400" }),
4538
- t("Slash.DebugTotalTokens")
4551
+ t("BiChat.Slash.DebugTotalTokens")
4539
4552
  ] }),
4540
4553
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionTotalTokens) })
4541
4554
  ] })
4542
- ] }) : /* @__PURE__ */ jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500 text-center py-1", children: t("Slash.DebugSessionUsageUnavailable") }),
4555
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500 text-center py-1", children: t("BiChat.Slash.DebugSessionUsageUnavailable") }),
4543
4556
  debugLimits && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-1.5", children: [
4544
4557
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4545
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugPolicyMaxContextWindow") }),
4558
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.DebugPolicyMaxContextWindow") }),
4546
4559
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(policyMaxTokens) })
4547
4560
  ] }),
4548
4561
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4549
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugModelMaxContextWindow") }),
4562
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.DebugModelMaxContextWindow") }),
4550
4563
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(modelMaxTokens) })
4551
4564
  ] }),
4552
4565
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4553
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugEffectiveContextWindow") }),
4566
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.DebugEffectiveContextWindow") }),
4554
4567
  /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(effectiveMaxTokens) })
4555
4568
  ] })
4556
4569
  ] }),
4557
4570
  effectiveMaxTokens > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
4558
4571
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4559
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugContextUsage") }),
4572
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.DebugContextUsage") }),
4560
4573
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4561
4574
  /* @__PURE__ */ jsxs("span", { className: "font-mono text-[10px] text-gray-400 dark:text-gray-500 tabular-nums", children: [
4562
4575
  formatTokens(latestPromptTokens),
@@ -4606,9 +4619,9 @@ var MessageInput = forwardRef(
4606
4619
  children: [
4607
4620
  isDragging && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10 bg-primary-50/95 dark:bg-primary-900/90 border-2 border-dashed border-primary-400 rounded-2xl flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
4608
4621
  /* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-800 flex items-center justify-center", children: /* @__PURE__ */ jsx(Paperclip, { size: 20, className: "text-primary-600 dark:text-primary-400" }) }),
4609
- /* @__PURE__ */ jsx("span", { className: "text-sm text-primary-700 dark:text-primary-300 font-medium", children: t("Input.DropFiles") })
4622
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-primary-700 dark:text-primary-300 font-medium", children: t("BiChat.Input.DropFiles") })
4610
4623
  ] }) }),
4611
- dropSuccess && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10 bg-green-50/95 dark:bg-green-900/90 border-2 border-green-400 rounded-2xl flex items-center justify-center animate-pulse pointer-events-none", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-green-700 dark:text-green-300 font-medium", children: t("Input.FilesAdded") }) }),
4624
+ dropSuccess && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10 bg-green-50/95 dark:bg-green-900/90 border-2 border-green-400 rounded-2xl flex items-center justify-center animate-pulse pointer-events-none", children: /* @__PURE__ */ jsx("span", { className: "text-sm text-green-700 dark:text-green-300 font-medium", children: t("BiChat.Input.FilesAdded") }) }),
4612
4625
  /* @__PURE__ */ jsxs(
4613
4626
  "div",
4614
4627
  {
@@ -4621,8 +4634,8 @@ var MessageInput = forwardRef(
4621
4634
  onClick: () => fileInputRef.current?.click(),
4622
4635
  disabled: loading || disabled || attachments.length >= maxFiles,
4623
4636
  className: "cursor-pointer flex-shrink-0 self-center p-2 text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
4624
- "aria-label": t("Input.AttachFiles"),
4625
- title: t("Input.AttachFiles"),
4637
+ "aria-label": t("BiChat.Input.AttachFiles"),
4638
+ title: t("BiChat.Input.AttachFiles"),
4626
4639
  children: /* @__PURE__ */ jsx(Paperclip, { size: 20 })
4627
4640
  }
4628
4641
  ),
@@ -4635,7 +4648,7 @@ var MessageInput = forwardRef(
4635
4648
  multiple: true,
4636
4649
  onChange: handleFileInputChange,
4637
4650
  className: "hidden",
4638
- "aria-label": t("Input.FileInput")
4651
+ "aria-label": t("BiChat.Input.FileInput")
4639
4652
  }
4640
4653
  ),
4641
4654
  /* @__PURE__ */ jsx("div", { className: "flex-1 self-stretch flex items-center", children: /* @__PURE__ */ jsx(
@@ -4665,7 +4678,7 @@ var MessageInput = forwardRef(
4665
4678
  rows: 1,
4666
4679
  disabled: loading || disabled,
4667
4680
  "aria-busy": loading,
4668
- "aria-label": t("Input.MessageInput")
4681
+ "aria-label": t("BiChat.Input.MessageInput")
4669
4682
  }
4670
4683
  ) }),
4671
4684
  /* @__PURE__ */ jsx(
@@ -4674,15 +4687,15 @@ var MessageInput = forwardRef(
4674
4687
  type: "submit",
4675
4688
  disabled: !canSubmit,
4676
4689
  className: "cursor-pointer flex-shrink-0 self-center p-2 rounded-lg bg-primary-600 hover:bg-primary-700 active:bg-primary-800 active:scale-95 text-white shadow-sm transition-all disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-primary-600",
4677
- "aria-label": loading ? t("Input.Processing") : t("Input.SendMessage"),
4690
+ "aria-label": loading ? t("BiChat.Input.Processing") : t("BiChat.Input.SendMessage"),
4678
4691
  children: loading ? /* @__PURE__ */ jsx("div", { className: "w-[18px] h-[18px] border-2 border-white/60 border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsx(PaperPlaneRight, { size: 18, weight: "fill" })
4679
4692
  }
4680
4693
  )
4681
4694
  ]
4682
4695
  }
4683
4696
  ),
4684
- isFocused && !message && !loading && /* @__PURE__ */ jsx("span", { className: "hidden sm:block absolute -bottom-5 left-14 text-[10px] text-gray-400 dark:text-gray-500 select-none animate-fade-in", children: t("Input.ShiftEnterHint") }),
4685
- isCommandListVisible && /* @__PURE__ */ jsx("div", { className: "absolute left-0 right-0 bottom-full mb-1.5 z-20 overflow-hidden rounded-lg border border-gray-200/70 bg-white/98 shadow-md backdrop-blur-xl dark:border-gray-700/70 dark:bg-gray-900/98 dark:shadow-black/20", children: filteredCommands.length > 0 ? /* @__PURE__ */ jsx("ul", { role: "listbox", "aria-label": t("Slash.CommandsList"), className: "py-1 px-1", children: filteredCommands.map((command, index) => {
4697
+ isFocused && !message && !loading && /* @__PURE__ */ jsx("span", { className: "hidden sm:block absolute -bottom-5 left-14 text-[10px] text-gray-400 dark:text-gray-500 select-none animate-fade-in", children: t("BiChat.Input.ShiftEnterHint") }),
4698
+ isCommandListVisible && /* @__PURE__ */ jsx("div", { className: "absolute left-0 right-0 bottom-full mb-1.5 z-20 overflow-hidden rounded-lg border border-gray-200/70 bg-white/98 shadow-md backdrop-blur-xl dark:border-gray-700/70 dark:bg-gray-900/98 dark:shadow-black/20", children: filteredCommands.length > 0 ? /* @__PURE__ */ jsx("ul", { role: "listbox", "aria-label": t("BiChat.Slash.CommandsList"), className: "py-1 px-1", children: filteredCommands.map((command, index) => {
4686
4699
  const isActive = index === activeCommandIndex;
4687
4700
  return /* @__PURE__ */ jsxs(
4688
4701
  "li",
@@ -4708,7 +4721,7 @@ var MessageInput = forwardRef(
4708
4721
  },
4709
4722
  command.name
4710
4723
  );
4711
- }) }) : /* @__PURE__ */ jsx("div", { className: "px-3 py-2.5 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500", children: t("Slash.NoMatches") }) }) })
4724
+ }) }) : /* @__PURE__ */ jsx("div", { className: "px-3 py-2.5 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500", children: t("BiChat.Slash.NoMatches") }) }) })
4712
4725
  ]
4713
4726
  }
4714
4727
  ),
@@ -4732,37 +4745,25 @@ MessageInput.displayName = "MessageInput";
4732
4745
 
4733
4746
  // ui/src/bichat/components/WelcomeContent.tsx
4734
4747
  init_useTranslation();
4735
- var EXAMPLE_PROMPTS = [
4736
- {
4737
- category: "Data Analysis",
4738
- icon: ChartBar,
4739
- text: "Show me sales trends for the last quarter"
4740
- },
4741
- {
4742
- category: "Reports",
4743
- icon: FileText,
4744
- text: "Generate a summary of customer feedback"
4745
- },
4746
- {
4747
- category: "Insights",
4748
- icon: Lightbulb,
4749
- text: "What are the top performing products?"
4750
- }
4748
+ var PROMPT_DEFS = [
4749
+ { categoryKey: "Welcome.Prompt1Category", textKey: "Welcome.Prompt1Text", icon: ChartBar, defaultCategory: "OSAGO Portfolio", defaultText: "What is the total amount of accrued OSAGO premiums for the reporting period?" },
4750
+ { categoryKey: "Welcome.Prompt2Category", textKey: "Welcome.Prompt2Text", icon: FileText, defaultCategory: "Regional Analysis", defaultText: "Show me the top 5 regions by collected insurance premiums" },
4751
+ { categoryKey: "Welcome.Prompt3Category", textKey: "Welcome.Prompt3Text", icon: Lightbulb, defaultCategory: "Loss Analysis", defaultText: "Calculate the loss ratio across the entire OSAGO portfolio" }
4751
4752
  ];
4752
- var CATEGORY_STYLES = {
4753
- "Data Analysis": {
4753
+ var PROMPT_STYLES = [
4754
+ {
4754
4755
  badge: "bg-sky-50 text-sky-600 ring-sky-600/10 dark:bg-sky-400/10 dark:text-sky-400 dark:ring-sky-400/20",
4755
4756
  icon: "text-sky-500 dark:text-sky-400"
4756
4757
  },
4757
- Reports: {
4758
+ {
4758
4759
  badge: "bg-teal-50 text-teal-600 ring-teal-600/10 dark:bg-teal-400/10 dark:text-teal-400 dark:ring-teal-400/20",
4759
4760
  icon: "text-teal-500 dark:text-teal-400"
4760
4761
  },
4761
- Insights: {
4762
+ {
4762
4763
  badge: "bg-amber-50 text-amber-600 ring-amber-600/10 dark:bg-amber-400/10 dark:text-amber-400 dark:ring-amber-400/20",
4763
4764
  icon: "text-amber-500 dark:text-amber-400"
4764
4765
  }
4765
- };
4766
+ ];
4766
4767
  var containerVariants = {
4767
4768
  hidden: { opacity: 0 },
4768
4769
  visible: {
@@ -4804,6 +4805,10 @@ var reducedItemVariants = {
4804
4805
  }
4805
4806
  }
4806
4807
  };
4808
+ function tOr(t, key2, defaultValue) {
4809
+ const v = t(key2);
4810
+ return v !== key2 ? v : defaultValue;
4811
+ }
4807
4812
  function WelcomeContent({
4808
4813
  onPromptSelect,
4809
4814
  title,
@@ -4812,8 +4817,13 @@ function WelcomeContent({
4812
4817
  }) {
4813
4818
  const { t } = useTranslation();
4814
4819
  const shouldReduceMotion = useReducedMotion();
4815
- const resolvedTitle = title || t("Welcome.Title");
4816
- const resolvedDescription = description || t("Welcome.Description");
4820
+ const resolvedTitle = title || "";
4821
+ const resolvedDescription = description || "";
4822
+ const prompts = PROMPT_DEFS.map((def) => ({
4823
+ category: tOr(t, def.categoryKey, def.defaultCategory),
4824
+ text: tOr(t, def.textKey, def.defaultText),
4825
+ icon: def.icon
4826
+ }));
4817
4827
  const handlePromptClick = (prompt) => {
4818
4828
  if (onPromptSelect && !disabled) {
4819
4829
  onPromptSelect(prompt);
@@ -4829,15 +4839,7 @@ function WelcomeContent({
4829
4839
  initial: "hidden",
4830
4840
  animate: "visible",
4831
4841
  children: [
4832
- /* @__PURE__ */ jsx(
4833
- "div",
4834
- {
4835
- className: "pointer-events-none absolute inset-x-0 -top-8 flex justify-center overflow-hidden h-56",
4836
- "aria-hidden": true,
4837
- children: /* @__PURE__ */ jsx("div", { className: "w-[420px] h-[260px] -mt-16 rounded-full bg-primary-300/[0.08] blur-[80px] dark:bg-primary-400/[0.05]" })
4838
- }
4839
- ),
4840
- /* @__PURE__ */ jsx(
4842
+ resolvedTitle && /* @__PURE__ */ jsx(
4841
4843
  motion.h1,
4842
4844
  {
4843
4845
  className: "relative text-2xl sm:text-3xl font-semibold text-gray-900 dark:text-white mb-4",
@@ -4845,7 +4847,7 @@ function WelcomeContent({
4845
4847
  children: resolvedTitle
4846
4848
  }
4847
4849
  ),
4848
- /* @__PURE__ */ jsx(
4850
+ resolvedDescription && /* @__PURE__ */ jsx(
4849
4851
  motion.p,
4850
4852
  {
4851
4853
  className: "text-base text-gray-500 dark:text-gray-400 mb-10 max-w-2xl mx-auto leading-relaxed",
@@ -4856,11 +4858,11 @@ function WelcomeContent({
4856
4858
  /* @__PURE__ */ jsxs(motion.div, { variants: activeItemVariants, children: [
4857
4859
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 mb-5", children: [
4858
4860
  /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent to-gray-200 dark:to-gray-700/70" }),
4859
- /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-gray-400 dark:text-gray-500 select-none", children: t("Welcome.QuickStart") }),
4861
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-gray-400 dark:text-gray-500 select-none", children: t("BiChat.Welcome.QuickStart") }),
4860
4862
  /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-gradient-to-l from-transparent to-gray-200 dark:to-gray-700/70" })
4861
4863
  ] }),
4862
- /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: EXAMPLE_PROMPTS.map((prompt, index) => {
4863
- const style = CATEGORY_STYLES[prompt.category];
4864
+ /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: prompts.map((prompt, index) => {
4865
+ const style = PROMPT_STYLES[index];
4864
4866
  return /* @__PURE__ */ jsxs(
4865
4867
  motion.button,
4866
4868
  {
@@ -4990,8 +4992,8 @@ function SessionArtifactList({
4990
4992
  return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 px-4 py-12 text-center", children: [
4991
4993
  /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-xl bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsx(Package, { className: "h-6 w-6 text-gray-400 dark:text-gray-500", weight: "duotone" }) }),
4992
4994
  /* @__PURE__ */ jsxs("div", { children: [
4993
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: t("Artifacts.Empty") }),
4994
- /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-gray-400 dark:text-gray-500", children: t("Artifacts.EmptySubtitle") })
4995
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: t("BiChat.Artifacts.Empty") }),
4996
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-gray-400 dark:text-gray-500", children: t("BiChat.Artifacts.EmptySubtitle") })
4995
4997
  ] })
4996
4998
  ] });
4997
4999
  }
@@ -5103,7 +5105,7 @@ function ArtifactActions({ url }) {
5103
5105
  className: "inline-flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5104
5106
  children: [
5105
5107
  /* @__PURE__ */ jsx(ArrowSquareOut, { className: "h-3.5 w-3.5", weight: "bold" }),
5106
- t("Artifacts.OpenInNewTab")
5108
+ t("BiChat.Artifacts.OpenInNewTab")
5107
5109
  ]
5108
5110
  }
5109
5111
  ),
@@ -5117,7 +5119,7 @@ function ArtifactActions({ url }) {
5117
5119
  className: "inline-flex items-center gap-2 rounded-lg bg-primary-600 px-3 py-1.5 text-xs font-medium text-white shadow-sm transition-colors hover:bg-primary-700",
5118
5120
  children: [
5119
5121
  /* @__PURE__ */ jsx(DownloadSimple, { className: "h-3.5 w-3.5", weight: "bold" }),
5120
- t("Artifacts.Download")
5122
+ t("BiChat.Artifacts.Download")
5121
5123
  ]
5122
5124
  }
5123
5125
  )
@@ -5132,7 +5134,7 @@ function TextArtifactPreview({ artifact }) {
5132
5134
  useEffect(() => {
5133
5135
  if (!artifact.url) {
5134
5136
  setLoading(false);
5135
- setError(t("Artifacts.TextPreviewFailed"));
5137
+ setError(t("BiChat.Artifacts.TextPreviewFailed"));
5136
5138
  return;
5137
5139
  }
5138
5140
  const controller = new AbortController();
@@ -5155,7 +5157,7 @@ function TextArtifactPreview({ artifact }) {
5155
5157
  if (err instanceof Error && err.name === "AbortError") {
5156
5158
  return;
5157
5159
  }
5158
- setError(t("Artifacts.TextPreviewFailed"));
5160
+ setError(t("BiChat.Artifacts.TextPreviewFailed"));
5159
5161
  }).finally(() => {
5160
5162
  setLoading(false);
5161
5163
  });
@@ -5166,15 +5168,15 @@ function TextArtifactPreview({ artifact }) {
5166
5168
  if (loading) {
5167
5169
  return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[320px] items-center justify-center rounded-xl border border-gray-200 bg-gray-50 text-sm text-gray-500 dark:border-gray-700/60 dark:bg-gray-800/30 dark:text-gray-400", children: [
5168
5170
  /* @__PURE__ */ jsx(SpinnerGap, { className: "mr-2 h-4 w-4 animate-spin" }),
5169
- t("Artifacts.PreviewLoading")
5171
+ t("BiChat.Artifacts.PreviewLoading")
5170
5172
  ] });
5171
5173
  }
5172
5174
  if (error) {
5173
5175
  return /* @__PURE__ */ jsx(WarningBox, { message: error });
5174
5176
  }
5175
5177
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
5176
- /* @__PURE__ */ jsx("pre", { className: "max-h-[70vh] overflow-auto rounded-xl border border-gray-200 bg-gray-50 p-3 text-xs leading-relaxed text-gray-800 dark:border-gray-700/60 dark:bg-gray-900 dark:text-gray-100", children: content || t("Artifacts.PreviewUnavailable") }),
5177
- truncated && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("Artifacts.TextPreviewTruncated") })
5178
+ /* @__PURE__ */ jsx("pre", { className: "max-h-[70vh] overflow-auto rounded-xl border border-gray-200 bg-gray-50 p-3 text-xs leading-relaxed text-gray-800 dark:border-gray-700/60 dark:bg-gray-900 dark:text-gray-100", children: content || t("BiChat.Artifacts.PreviewUnavailable") }),
5179
+ truncated && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Artifacts.TextPreviewTruncated") })
5178
5180
  ] });
5179
5181
  }
5180
5182
  function SessionArtifactPreview({ artifact }) {
@@ -5190,11 +5192,11 @@ function SessionArtifactPreview({ artifact }) {
5190
5192
  if (chartData) {
5191
5193
  return /* @__PURE__ */ jsx(ChartCard, { chartData });
5192
5194
  }
5193
- return /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.ChartUnavailable") });
5195
+ return /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.ChartUnavailable") });
5194
5196
  }
5195
5197
  if (isImageArtifact2(artifact)) {
5196
5198
  if (!artifact.url) {
5197
- return /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.ImageUnavailable") });
5199
+ return /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.ImageUnavailable") });
5198
5200
  }
5199
5201
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5200
5202
  /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50/50 dark:border-gray-700/60 dark:bg-gray-800/30", children: /* @__PURE__ */ jsx(
@@ -5211,7 +5213,7 @@ function SessionArtifactPreview({ artifact }) {
5211
5213
  }
5212
5214
  if (isPDFArtifact(artifact)) {
5213
5215
  if (!artifact.url) {
5214
- return /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5216
+ return /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.DownloadUnavailable") });
5215
5217
  }
5216
5218
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5217
5219
  /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50 dark:border-gray-700/60 dark:bg-gray-900", children: /* @__PURE__ */ jsx(
@@ -5227,7 +5229,7 @@ function SessionArtifactPreview({ artifact }) {
5227
5229
  }
5228
5230
  if (isOfficeDocumentArtifact(artifact)) {
5229
5231
  if (!artifact.url) {
5230
- return /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5232
+ return /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.DownloadUnavailable") });
5231
5233
  }
5232
5234
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5233
5235
  officeViewerURL ? /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50 dark:border-gray-700/60 dark:bg-gray-900", children: /* @__PURE__ */ jsx(
@@ -5237,7 +5239,7 @@ function SessionArtifactPreview({ artifact }) {
5237
5239
  title: artifact.name,
5238
5240
  className: "h-[72vh] w-full"
5239
5241
  }
5240
- ) }) : /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.OfficePreviewUnavailable") }),
5242
+ ) }) : /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.OfficePreviewUnavailable") }),
5241
5243
  /* @__PURE__ */ jsx(ArtifactActions, { url: artifact.url })
5242
5244
  ] });
5243
5245
  }
@@ -5251,13 +5253,13 @@ function SessionArtifactPreview({ artifact }) {
5251
5253
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5252
5254
  /* @__PURE__ */ jsxs("div", { className: "flex min-h-[240px] flex-col items-center justify-center rounded-xl border border-gray-200/80 bg-gray-50/60 p-6 text-center dark:border-gray-700/60 dark:bg-gray-900", children: [
5253
5255
  /* @__PURE__ */ jsx(FileText, { className: "h-8 w-8 text-gray-400 dark:text-gray-500", weight: "duotone" }),
5254
- /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm font-medium text-gray-800 dark:text-gray-100", children: t("Artifacts.PreviewUnavailable") }),
5255
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: t("Artifacts.PreviewNotSupported") })
5256
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm font-medium text-gray-800 dark:text-gray-100", children: t("BiChat.Artifacts.PreviewUnavailable") }),
5257
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Artifacts.PreviewNotSupported") })
5256
5258
  ] }),
5257
5259
  /* @__PURE__ */ jsx(ArtifactActions, { url: artifact.url })
5258
5260
  ] });
5259
5261
  }
5260
- return /* @__PURE__ */ jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5262
+ return /* @__PURE__ */ jsx(WarningBox, { message: t("BiChat.Artifacts.DownloadUnavailable") });
5261
5263
  }
5262
5264
  function SessionArtifactPreviewModal({
5263
5265
  isOpen,
@@ -5303,7 +5305,7 @@ function SessionArtifactPreviewModal({
5303
5305
  await onRename(artifact, nextName);
5304
5306
  setIsEditingName(false);
5305
5307
  } catch (err) {
5306
- setError(err instanceof Error ? err.message : t("Artifacts.RenameFailed"));
5308
+ setError(err instanceof Error ? err.message : t("BiChat.Artifacts.RenameFailed"));
5307
5309
  } finally {
5308
5310
  setSubmittingRename(false);
5309
5311
  }
@@ -5312,7 +5314,7 @@ function SessionArtifactPreviewModal({
5312
5314
  if (!artifact || !onDelete) {
5313
5315
  return;
5314
5316
  }
5315
- if (!window.confirm(t("Artifacts.DeleteConfirm"))) {
5317
+ if (!window.confirm(t("BiChat.Artifacts.DeleteConfirm"))) {
5316
5318
  return;
5317
5319
  }
5318
5320
  setSubmittingDelete(true);
@@ -5321,7 +5323,7 @@ function SessionArtifactPreviewModal({
5321
5323
  await onDelete(artifact);
5322
5324
  onClose();
5323
5325
  } catch (err) {
5324
- setError(err instanceof Error ? err.message : t("Artifacts.DeleteFailed"));
5326
+ setError(err instanceof Error ? err.message : t("BiChat.Artifacts.DeleteFailed"));
5325
5327
  } finally {
5326
5328
  setSubmittingDelete(false);
5327
5329
  }
@@ -5352,7 +5354,7 @@ function SessionArtifactPreviewModal({
5352
5354
  }
5353
5355
  },
5354
5356
  className: "w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100",
5355
- "aria-label": t("Artifacts.Rename"),
5357
+ "aria-label": t("BiChat.Artifacts.Rename"),
5356
5358
  autoFocus: true
5357
5359
  }
5358
5360
  ),
@@ -5367,7 +5369,7 @@ function SessionArtifactPreviewModal({
5367
5369
  className: "cursor-pointer inline-flex items-center gap-1 rounded-lg bg-primary-600 px-2.5 py-1.5 text-xs font-medium text-white transition-colors hover:bg-primary-700 disabled:cursor-not-allowed disabled:opacity-60",
5368
5370
  children: [
5369
5371
  /* @__PURE__ */ jsx(FloppyDisk, { className: "h-3.5 w-3.5", weight: "bold" }),
5370
- t("Message.Save")
5372
+ t("BiChat.Message.Save")
5371
5373
  ]
5372
5374
  }
5373
5375
  ),
@@ -5381,7 +5383,7 @@ function SessionArtifactPreviewModal({
5381
5383
  },
5382
5384
  disabled: submittingRename,
5383
5385
  className: "cursor-pointer rounded-lg border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-60 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5384
- children: t("Message.Cancel")
5386
+ children: t("BiChat.Message.Cancel")
5385
5387
  }
5386
5388
  )
5387
5389
  ] }) : /* @__PURE__ */ jsx("h2", { className: "truncate text-base font-semibold text-gray-900 dark:text-gray-100", children: artifact.name }),
@@ -5397,8 +5399,8 @@ function SessionArtifactPreviewModal({
5397
5399
  setIsEditingName(true);
5398
5400
  },
5399
5401
  className: "cursor-pointer rounded-lg border border-gray-200 p-2 text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100",
5400
- "aria-label": t("Artifacts.Rename"),
5401
- title: t("Artifacts.Rename"),
5402
+ "aria-label": t("BiChat.Artifacts.Rename"),
5403
+ title: t("BiChat.Artifacts.Rename"),
5402
5404
  children: /* @__PURE__ */ jsx(PencilSimple, { className: "h-4 w-4", weight: "regular" })
5403
5405
  }
5404
5406
  ),
@@ -5411,8 +5413,8 @@ function SessionArtifactPreviewModal({
5411
5413
  },
5412
5414
  disabled: submittingDelete,
5413
5415
  className: "cursor-pointer rounded-lg border border-red-200 p-2 text-red-600 transition-colors hover:bg-red-50 hover:text-red-700 disabled:cursor-not-allowed disabled:opacity-60 dark:border-red-900/60 dark:text-red-400 dark:hover:bg-red-950/30 dark:hover:text-red-300",
5414
- "aria-label": t("Artifacts.Delete"),
5415
- title: t("Artifacts.Delete"),
5416
+ "aria-label": t("BiChat.Artifacts.Delete"),
5417
+ title: t("BiChat.Artifacts.Delete"),
5416
5418
  children: /* @__PURE__ */ jsx(Trash, { className: "h-4 w-4", weight: "regular" })
5417
5419
  }
5418
5420
  ),
@@ -5422,8 +5424,8 @@ function SessionArtifactPreviewModal({
5422
5424
  type: "button",
5423
5425
  onClick: handleClose,
5424
5426
  className: "cursor-pointer rounded-lg border border-gray-200 p-2 text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100",
5425
- "aria-label": t("Common.Close"),
5426
- title: t("Common.Close"),
5427
+ "aria-label": t("BiChat.Common.Close"),
5428
+ title: t("BiChat.Common.Close"),
5427
5429
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4", weight: "bold" })
5428
5430
  }
5429
5431
  )
@@ -5527,7 +5529,7 @@ function SessionArtifactsPanel({
5527
5529
  if (requestID !== requestSeq.current) {
5528
5530
  return;
5529
5531
  }
5530
- setError(err instanceof Error ? err.message : tRef.current("Artifacts.FailedToLoad"));
5532
+ setError(err instanceof Error ? err.message : tRef.current("BiChat.Artifacts.FailedToLoad"));
5531
5533
  } finally {
5532
5534
  if (requestID === requestSeq.current) {
5533
5535
  setFetching(false);
@@ -5642,7 +5644,7 @@ function SessionArtifactsPanel({
5642
5644
  }
5643
5645
  setError(null);
5644
5646
  } catch (err) {
5645
- setError(err instanceof Error ? err.message : tRef.current("Artifacts.FailedToLoad"));
5647
+ setError(err instanceof Error ? err.message : tRef.current("BiChat.Artifacts.FailedToLoad"));
5646
5648
  }
5647
5649
  }, [canDropFiles, dataSource, fetchArtifacts, hasDragFiles, sessionId, setDropSuccessState]);
5648
5650
  const canRenameArtifacts = typeof dataSource.renameSessionArtifact === "function";
@@ -5691,7 +5693,7 @@ function SessionArtifactsPanel({
5691
5693
  isDragging ? "bg-primary-50/40 dark:bg-primary-950/20" : "",
5692
5694
  className
5693
5695
  ].join(" "),
5694
- "aria-label": t("Artifacts.Title"),
5696
+ "aria-label": t("BiChat.Artifacts.Title"),
5695
5697
  onDragEnter: handleDragEnter,
5696
5698
  onDragOver: handleDragOver,
5697
5699
  onDragLeave: handleDragLeave,
@@ -5706,18 +5708,18 @@ function SessionArtifactsPanel({
5706
5708
  ].join(" "),
5707
5709
  children: [
5708
5710
  /* @__PURE__ */ jsx(Paperclip, { className: "h-5 w-5", weight: "bold" }),
5709
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: dropSuccess ? t("Input.FilesAdded") : t("Input.DropFiles") })
5711
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: dropSuccess ? t("BiChat.Input.FilesAdded") : t("BiChat.Input.DropFiles") })
5710
5712
  ]
5711
5713
  }
5712
5714
  ) }),
5713
5715
  /* @__PURE__ */ jsx("header", { className: "flex items-center justify-between border-b border-gray-200 px-3 py-2 dark:border-gray-700/80", children: /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxs("h2", { className: "truncate text-sm font-semibold text-gray-900 dark:text-gray-100", children: [
5714
- t("Artifacts.Title"),
5716
+ t("BiChat.Artifacts.Title"),
5715
5717
  " (",
5716
5718
  artifacts.length,
5717
5719
  ")"
5718
5720
  ] }) }) }),
5719
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 py-3", children: fetching ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-sm text-gray-500 dark:text-gray-400", children: t("Artifacts.Loading") }) : error ? /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-900/70 dark:bg-red-950/30", children: [
5720
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-300", children: t("Artifacts.FailedToLoad") }),
5721
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 py-3", children: fetching ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-sm text-gray-500 dark:text-gray-400", children: t("BiChat.Artifacts.Loading") }) : error ? /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-900/70 dark:bg-red-950/30", children: [
5722
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-300", children: t("BiChat.Artifacts.FailedToLoad") }),
5721
5723
  /* @__PURE__ */ jsx("p", { className: "text-xs text-red-700 dark:text-red-400", children: error }),
5722
5724
  /* @__PURE__ */ jsx(
5723
5725
  "button",
@@ -5727,10 +5729,10 @@ function SessionArtifactsPanel({
5727
5729
  void fetchArtifacts({ reset: true, manual: true });
5728
5730
  },
5729
5731
  className: "cursor-pointer rounded-md border border-red-300 px-2 py-1 text-xs font-medium text-red-700 hover:bg-red-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-400/50 dark:border-red-800 dark:text-red-300 dark:hover:bg-red-900/40",
5730
- children: t("Alert.Retry")
5732
+ children: t("BiChat.Alert.Retry")
5731
5733
  }
5732
5734
  )
5733
- ] }) : !canFetchArtifacts ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-800 dark:border-amber-900/70 dark:bg-amber-950/30 dark:text-amber-200", children: t("Artifacts.Unsupported") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5735
+ ] }) : !canFetchArtifacts ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-800 dark:border-amber-900/70 dark:bg-amber-950/30 dark:text-amber-200", children: t("BiChat.Artifacts.Unsupported") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5734
5736
  /* @__PURE__ */ jsx(
5735
5737
  SessionArtifactList,
5736
5738
  {
@@ -5748,7 +5750,7 @@ function SessionArtifactsPanel({
5748
5750
  },
5749
5751
  disabled: loadingMore || refreshing || fetching,
5750
5752
  className: "cursor-pointer rounded-md border border-gray-200 px-3 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5751
- children: loadingMore ? t("Artifacts.LoadingMore") : t("Artifacts.LoadMore")
5753
+ children: loadingMore ? t("BiChat.Artifacts.LoadingMore") : t("BiChat.Artifacts.LoadMore")
5752
5754
  }
5753
5755
  ) })
5754
5756
  ] }) }),
@@ -5873,11 +5875,11 @@ function ChatSessionCore({
5873
5875
  };
5874
5876
  }, [isResizingArtifactsPanel, artifactsPanelStorageKey]);
5875
5877
  if (fetching) {
5876
- return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 dark:text-gray-400", children: t("Input.Processing") }) });
5878
+ return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "text-gray-500 dark:text-gray-400", children: t("BiChat.Input.Processing") }) });
5877
5879
  }
5878
5880
  if (error) {
5879
5881
  return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-red-500 dark:text-red-400", children: [
5880
- t("Error.Generic"),
5882
+ t("BiChat.Error.Generic"),
5881
5883
  ": ",
5882
5884
  error
5883
5885
  ] }) });
@@ -5913,11 +5915,11 @@ function ChatSessionCore({
5913
5915
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
5914
5916
  artifactsPanelExpanded ? "bg-primary-50 text-primary-700 hover:bg-primary-100 dark:bg-primary-950/30 dark:text-primary-300 dark:hover:bg-primary-900/40" : "text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200"
5915
5917
  ].join(" "),
5916
- "aria-label": artifactsPanelExpanded ? t("Artifacts.ToggleHide") : t("Artifacts.ToggleShow"),
5917
- title: artifactsPanelExpanded ? t("Artifacts.ToggleHide") : t("Artifacts.ToggleShow"),
5918
+ "aria-label": artifactsPanelExpanded ? t("BiChat.Artifacts.ToggleHide") : t("BiChat.Artifacts.ToggleShow"),
5919
+ title: artifactsPanelExpanded ? t("BiChat.Artifacts.ToggleHide") : t("BiChat.Artifacts.ToggleShow"),
5918
5920
  children: [
5919
5921
  /* @__PURE__ */ jsx(Sidebar, { className: "h-4 w-4", weight: artifactsPanelExpanded ? "duotone" : "regular" }),
5920
- t("Artifacts.Title")
5922
+ t("BiChat.Artifacts.Title")
5921
5923
  ]
5922
5924
  }
5923
5925
  ),
@@ -5965,7 +5967,7 @@ function ChatSessionCore({
5965
5967
  formClassName: "mx-auto"
5966
5968
  }
5967
5969
  ),
5968
- /* @__PURE__ */ jsx("p", { className: "mt-4 pb-1 text-center text-xs text-gray-500 dark:text-gray-400", children: t("Welcome.Disclaimer") })
5970
+ /* @__PURE__ */ jsx("p", { className: "mt-4 pb-1 text-center text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Welcome.Disclaimer") })
5969
5971
  ] }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5970
5972
  /* @__PURE__ */ jsx(
5971
5973
  MessageList,
@@ -6015,7 +6017,7 @@ function ChatSessionCore({
6015
6017
  "div",
6016
6018
  {
6017
6019
  role: "separator",
6018
- "aria-label": t("Artifacts.Resize"),
6020
+ "aria-label": t("BiChat.Artifacts.Resize"),
6019
6021
  onMouseDown: handleArtifactsResizeStart,
6020
6022
  className: "relative flex shrink-0 cursor-col-resize touch-none items-center justify-center w-2 transition-colors lg:flex group/resize after:absolute after:inset-y-0 after:left-0 after:w-0.5 after:bg-gray-300 dark:after:bg-gray-600 after:transition-colors group-hover/resize:after:bg-primary-400 dark:group-hover/resize:after:bg-primary-500",
6021
6023
  children: /* @__PURE__ */ jsx("span", { className: "absolute h-10 w-1.5 cursor-col-resize rounded-full bg-gray-400 transition-colors group-hover/resize:bg-primary-400 dark:bg-gray-500 dark:group-hover/resize:bg-primary-500" })
@@ -6056,7 +6058,7 @@ function ChatSessionCore({
6056
6058
  animate: { opacity: 1 },
6057
6059
  exit: { opacity: 0 },
6058
6060
  onClick: handleToggleArtifactsPanel,
6059
- "aria-label": t("Common.Close")
6061
+ "aria-label": t("BiChat.Common.Close")
6060
6062
  }
6061
6063
  ),
6062
6064
  /* @__PURE__ */ jsx(
@@ -6170,6 +6172,9 @@ function EmptyState({
6170
6172
  }
6171
6173
  var MemoizedEmptyState = memo(EmptyState);
6172
6174
  MemoizedEmptyState.displayName = "EmptyState";
6175
+
6176
+ // ui/src/bichat/components/EditableText.tsx
6177
+ init_useTranslation();
6173
6178
  var sizeClasses2 = {
6174
6179
  sm: "text-sm",
6175
6180
  md: "text-base",
@@ -6186,6 +6191,7 @@ var EditableText = forwardRef(
6186
6191
  inputClassName = "",
6187
6192
  size = "sm"
6188
6193
  }, ref) => {
6194
+ const { t } = useTranslation();
6189
6195
  const [isEditing, setIsEditing] = useState(false);
6190
6196
  const [editValue, setEditValue] = useState(value);
6191
6197
  const inputRef = useRef(null);
@@ -6261,7 +6267,7 @@ var EditableText = forwardRef(
6261
6267
  maxLength,
6262
6268
  placeholder,
6263
6269
  className: `flex-1 px-2 py-1 ${sizeClass} bg-white dark:bg-gray-700 border border-primary-500 dark:border-primary-600 rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 dark:focus-visible:ring-primary-600/30 text-gray-900 dark:text-white ${inputClassName}`,
6264
- "aria-label": "Edit text. Press Enter to save, Escape to cancel"
6270
+ "aria-label": t("BiChat.EditableText.AriaLabel")
6265
6271
  }
6266
6272
  )
6267
6273
  }
@@ -6273,7 +6279,7 @@ var EditableText = forwardRef(
6273
6279
  {
6274
6280
  onDoubleClick: handleDoubleClick,
6275
6281
  className: `${sizeClass} font-medium truncate flex-1 cursor-pointer select-none hover:text-primary-600 dark:hover:text-primary-400 transition-colors ${className}`,
6276
- title: "Double-click to edit",
6282
+ title: t("BiChat.EditableText.DoubleClickToEdit"),
6277
6283
  role: "button",
6278
6284
  tabIndex: 0,
6279
6285
  onKeyDown: (e) => {
@@ -6292,6 +6298,9 @@ var EditableText = forwardRef(
6292
6298
  );
6293
6299
  EditableText.displayName = "EditableText";
6294
6300
  var MemoizedEditableText = memo(EditableText);
6301
+
6302
+ // ui/src/bichat/components/SearchInput.tsx
6303
+ init_useTranslation();
6295
6304
  var sizeClasses3 = {
6296
6305
  sm: {
6297
6306
  container: "py-1.5 pl-8 pr-8 text-xs",
@@ -6321,6 +6330,7 @@ function SearchInput({
6321
6330
  disabled = false,
6322
6331
  ariaLabel = "Search"
6323
6332
  }) {
6333
+ const { t } = useTranslation();
6324
6334
  const inputRef = useRef(null);
6325
6335
  const sizes = sizeClasses3[size];
6326
6336
  useEffect(() => {
@@ -6375,8 +6385,8 @@ function SearchInput({
6375
6385
  type: "button",
6376
6386
  onClick: handleClear,
6377
6387
  className: `cursor-pointer absolute inset-y-0 right-2 flex items-center ${sizes.clearBtn} rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-all duration-200 text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300`,
6378
- "aria-label": "Clear search",
6379
- title: "Clear search",
6388
+ "aria-label": t("BiChat.Search.Clear"),
6389
+ title: t("BiChat.Search.Clear"),
6380
6390
  children: /* @__PURE__ */ jsx(X, { size: sizes.icon - 2, weight: "bold" })
6381
6391
  }
6382
6392
  )
@@ -6911,12 +6921,16 @@ function useLongPress(options) {
6911
6921
  isPressed
6912
6922
  };
6913
6923
  }
6924
+
6925
+ // ui/src/bichat/components/TouchContextMenu.tsx
6926
+ init_useTranslation();
6914
6927
  var TouchContextMenu = ({
6915
6928
  items,
6916
6929
  isOpen,
6917
6930
  onClose,
6918
6931
  anchorRect
6919
6932
  }) => {
6933
+ const { t } = useTranslation();
6920
6934
  const [focusedIndex, setFocusedIndex] = useState(-1);
6921
6935
  const menuRef = useRef(null);
6922
6936
  const itemRefs = useRef([]);
@@ -7000,7 +7014,7 @@ var TouchContextMenu = ({
7000
7014
  {
7001
7015
  ref: menuRef,
7002
7016
  role: "menu",
7003
- "aria-label": "Context menu",
7017
+ "aria-label": t("BiChat.ContextMenu"),
7004
7018
  initial: { opacity: 0, scale: 0.95 },
7005
7019
  animate: { opacity: 1, scale: 1 },
7006
7020
  exit: { opacity: 0, scale: 0.95 },
@@ -7065,11 +7079,24 @@ var SessionItem = memo(
7065
7079
  const [menuAnchor, setMenuAnchor] = useState(null);
7066
7080
  const [isTouch, setIsTouch] = useState(false);
7067
7081
  const { t } = useTranslation();
7082
+ const isDraggingRef = useRef(false);
7083
+ const dragX = useMotionValue(0);
7084
+ const archiveOpacity = useTransform(dragX, [-80, -40, 0], [1, 0.5, 0]);
7085
+ const archiveScale = useTransform(dragX, [-80, -40, 0], [1, 0.8, 0.6]);
7086
+ const canDragArchive = !!onArchive;
7087
+ const handleDragEnd = (_, info) => {
7088
+ if (info.offset.x < -80 && onArchive) {
7089
+ onArchive();
7090
+ }
7091
+ requestAnimationFrame(() => {
7092
+ isDraggingRef.current = false;
7093
+ });
7094
+ };
7068
7095
  useEffect(() => {
7069
7096
  setIsTouch("ontouchend" in document);
7070
7097
  }, []);
7071
- const isTitleGenerating = !session.title || session.title === t("Chat.NewChat");
7072
- const displayTitle = isTitleGenerating ? t("Common.Generating") : session.title ?? t("Common.Untitled");
7098
+ const isTitleGenerating = !session.title || session.title === t("BiChat.Chat.NewChat");
7099
+ const displayTitle = isTitleGenerating ? t("BiChat.Common.Generating") : session.title ?? t("BiChat.Common.Untitled");
7073
7100
  const { handlers: longPressHandlers } = useLongPress({
7074
7101
  delay: 500,
7075
7102
  onLongPress: (e) => {
@@ -7083,60 +7110,58 @@ var SessionItem = memo(
7083
7110
  const element = itemRef.current;
7084
7111
  if (!element) return;
7085
7112
  const isIPad = /iPad|Macintosh/i.test(navigator.userAgent) && "ontouchend" in document;
7086
- if (isIPad) {
7087
- const handleContextMenu = (e) => {
7088
- e.preventDefault();
7089
- const target = e.currentTarget;
7090
- setMenuAnchor(target.getBoundingClientRect());
7091
- setMenuOpen(true);
7092
- };
7093
- element.addEventListener("contextmenu", handleContextMenu);
7094
- return () => element.removeEventListener("contextmenu", handleContextMenu);
7095
- }
7096
- return void 0;
7113
+ if (!isIPad) return;
7114
+ const handleContextMenu = (e) => {
7115
+ e.preventDefault();
7116
+ const target = e.currentTarget;
7117
+ setMenuAnchor(target.getBoundingClientRect());
7118
+ setMenuOpen(true);
7119
+ };
7120
+ element.addEventListener("contextmenu", handleContextMenu);
7121
+ return () => element.removeEventListener("contextmenu", handleContextMenu);
7097
7122
  }, [itemRef]);
7098
7123
  const contextMenuItems = mode === "archived" ? [
7099
7124
  ...onRestore ? [{
7100
7125
  id: "restore",
7101
- label: t("Archived.RestoreButton"),
7126
+ label: t("BiChat.Archived.RestoreButton"),
7102
7127
  icon: /* @__PURE__ */ jsx(ArrowUUpLeft, { size: 20 }),
7103
7128
  onClick: () => onRestore()
7104
7129
  }] : [],
7105
7130
  ...onRename ? [{
7106
7131
  id: "rename",
7107
- label: t("Sidebar.RenameChat"),
7132
+ label: t("BiChat.Sidebar.RenameChat"),
7108
7133
  icon: /* @__PURE__ */ jsx(PencilSimple, { size: 20 }),
7109
7134
  onClick: () => editableTitleRef.current?.startEditing()
7110
7135
  }] : []
7111
7136
  ] : [
7112
7137
  ...onPin ? [{
7113
7138
  id: "pin",
7114
- label: session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat"),
7139
+ label: session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat"),
7115
7140
  icon: session.pinned ? /* @__PURE__ */ jsx(Check, { size: 20 }) : /* @__PURE__ */ jsx(Bookmark, { size: 20 }),
7116
7141
  onClick: () => onPin()
7117
7142
  }] : [],
7118
7143
  ...onRename ? [{
7119
7144
  id: "rename",
7120
- label: t("Sidebar.RenameChat"),
7145
+ label: t("BiChat.Sidebar.RenameChat"),
7121
7146
  icon: /* @__PURE__ */ jsx(PencilSimple, { size: 20 }),
7122
7147
  onClick: () => editableTitleRef.current?.startEditing()
7123
7148
  }] : [],
7124
7149
  ...onRegenerateTitle ? [{
7125
7150
  id: "regenerate",
7126
- label: t("Sidebar.RegenerateTitle"),
7151
+ label: t("BiChat.Sidebar.RegenerateTitle"),
7127
7152
  icon: /* @__PURE__ */ jsx(ArrowsClockwise, { size: 20 }),
7128
7153
  onClick: () => onRegenerateTitle()
7129
7154
  }] : [],
7130
7155
  ...onArchive ? [{
7131
7156
  id: "archive",
7132
- label: t("Sidebar.ArchiveChat"),
7157
+ label: t("BiChat.Sidebar.ArchiveChat"),
7133
7158
  icon: /* @__PURE__ */ jsx(Archive, { size: 20 }),
7134
7159
  onClick: () => onArchive(),
7135
7160
  variant: "danger"
7136
7161
  }] : [],
7137
7162
  ...onDelete ? [{
7138
7163
  id: "delete",
7139
- label: t("Sidebar.DeleteChat"),
7164
+ label: t("BiChat.Sidebar.DeleteChat"),
7140
7165
  icon: /* @__PURE__ */ jsx(Trash, { size: 20 }),
7141
7166
  onClick: () => onDelete(),
7142
7167
  variant: "danger"
@@ -7144,7 +7169,7 @@ var SessionItem = memo(
7144
7169
  ];
7145
7170
  const hasContextMenu = contextMenuItems.length > 0;
7146
7171
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7147
- /* @__PURE__ */ jsx(
7172
+ /* @__PURE__ */ jsxs(
7148
7173
  motion.div,
7149
7174
  {
7150
7175
  variants: sessionItemVariants,
@@ -7152,158 +7177,196 @@ var SessionItem = memo(
7152
7177
  animate: "animate",
7153
7178
  whileHover: "hover",
7154
7179
  exit: "exit",
7155
- children: /* @__PURE__ */ jsx(
7156
- "button",
7157
- {
7158
- type: "button",
7159
- ref: itemRef,
7160
- onClick: () => onSelect(session.id),
7161
- 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}`,
7162
- "aria-current": isActive ? "page" : void 0,
7163
- "data-session-item": true,
7164
- "data-testid": `${testIdPrefix}-session-${session.id}`,
7165
- ...longPressHandlers,
7166
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
7167
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: /* @__PURE__ */ jsx(
7168
- MemoizedEditableText,
7180
+ className: "relative overflow-hidden rounded-lg",
7181
+ children: [
7182
+ canDragArchive && /* @__PURE__ */ jsx(
7183
+ motion.div,
7184
+ {
7185
+ className: "absolute inset-y-0 right-0 w-20 flex items-center justify-center bg-gray-500 dark:bg-gray-600 rounded-r-lg",
7186
+ style: { opacity: archiveOpacity, scale: archiveScale },
7187
+ "aria-hidden": "true",
7188
+ children: /* @__PURE__ */ jsx(Archive, { size: 20, className: "text-white" })
7189
+ }
7190
+ ),
7191
+ /* @__PURE__ */ jsx(
7192
+ motion.div,
7193
+ {
7194
+ drag: canDragArchive ? "x" : false,
7195
+ dragDirectionLock: true,
7196
+ dragConstraints: { left: -100, right: 0 },
7197
+ dragElastic: { left: 0.2, right: 0.5 },
7198
+ dragSnapToOrigin: true,
7199
+ style: { x: canDragArchive ? dragX : void 0 },
7200
+ onDragStart: () => {
7201
+ isDraggingRef.current = true;
7202
+ },
7203
+ onDragEnd: canDragArchive ? handleDragEnd : void 0,
7204
+ className: "relative",
7205
+ children: /* @__PURE__ */ jsx(
7206
+ "div",
7169
7207
  {
7170
- ref: editableTitleRef,
7171
- value: displayTitle,
7172
- onSave: (newTitle) => onRename?.(newTitle),
7173
- isLoading: isTitleGenerating
7174
- }
7175
- ) }),
7176
- !isTouch && hasContextMenu && /* @__PURE__ */ jsxs(Menu, { children: [
7177
- /* @__PURE__ */ jsx(
7178
- MenuButton,
7179
- {
7180
- onClick: (e) => {
7208
+ role: "button",
7209
+ tabIndex: 0,
7210
+ ref: itemRef,
7211
+ onClick: () => {
7212
+ if (isDraggingRef.current) return;
7213
+ onSelect(session.id);
7214
+ },
7215
+ onKeyDown: (e) => {
7216
+ if (e.key === "Enter" || e.key === " ") {
7181
7217
  e.preventDefault();
7182
- e.stopPropagation();
7183
- },
7184
- 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",
7185
- "aria-label": t("Sidebar.ChatOptions"),
7186
- "data-testid": `${testIdPrefix}-session-options-${session.id}`,
7187
- children: /* @__PURE__ */ jsx(DotsThree, { size: 16, className: "w-4 h-4", weight: "bold" })
7188
- }
7189
- ),
7190
- /* @__PURE__ */ jsxs(
7191
- MenuItems,
7192
- {
7193
- anchor: "bottom start",
7194
- 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",
7195
- children: [
7196
- mode !== "archived" && onPin && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7197
- "button",
7198
- {
7199
- onClick: (e) => {
7200
- e.preventDefault();
7201
- e.stopPropagation();
7202
- onPin();
7203
- },
7204
- 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"}`,
7205
- "aria-label": session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat"),
7206
- "data-testid": `${testIdPrefix}-session-pin-${session.id}`,
7207
- children: [
7208
- session.pinned ? /* @__PURE__ */ jsx(Check, { size: 16, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Bookmark, { size: 16, className: "w-4 h-4" }),
7209
- session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat")
7210
- ]
7211
- }
7212
- ) }),
7213
- onRename && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxs(
7214
- "button",
7215
- {
7216
- onClick: (e) => {
7217
- e.preventDefault();
7218
- e.stopPropagation();
7219
- editableTitleRef.current?.startEditing();
7220
- close();
7221
- },
7222
- 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"}`,
7223
- "aria-label": t("Sidebar.RenameChat"),
7224
- "data-testid": `${testIdPrefix}-session-rename-${session.id}`,
7225
- children: [
7226
- /* @__PURE__ */ jsx(PencilSimple, { size: 16, className: "w-4 h-4" }),
7227
- t("Sidebar.RenameChat")
7228
- ]
7229
- }
7230
- ) }),
7231
- mode !== "archived" && onRegenerateTitle && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxs(
7232
- "button",
7233
- {
7234
- onClick: (e) => {
7235
- e.preventDefault();
7236
- e.stopPropagation();
7237
- onRegenerateTitle();
7238
- close();
7239
- },
7240
- 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"}`,
7241
- "aria-label": t("Sidebar.RegenerateTitle"),
7242
- "data-testid": `${testIdPrefix}-session-regenerate-${session.id}`,
7243
- children: [
7244
- /* @__PURE__ */ jsx(ArrowsClockwise, { size: 16, className: "w-4 h-4" }),
7245
- t("Sidebar.RegenerateTitle")
7246
- ]
7247
- }
7248
- ) }),
7249
- mode === "archived" && onRestore && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7250
- "button",
7251
- {
7252
- onClick: (e) => {
7253
- e.preventDefault();
7254
- e.stopPropagation();
7255
- onRestore();
7256
- },
7257
- 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"}`,
7258
- "aria-label": t("Archived.RestoreButton"),
7259
- "data-testid": `${testIdPrefix}-session-restore-${session.id}`,
7260
- children: [
7261
- /* @__PURE__ */ jsx(ArrowUUpLeft, { size: 16, className: "w-4 h-4" }),
7262
- t("Archived.RestoreButton")
7263
- ]
7264
- }
7265
- ) }),
7266
- mode !== "archived" && onArchive && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7267
- "button",
7218
+ onSelect(session.id);
7219
+ }
7220
+ },
7221
+ 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}`,
7222
+ "aria-current": isActive ? "page" : void 0,
7223
+ "data-session-item": true,
7224
+ "data-testid": `${testIdPrefix}-session-${session.id}`,
7225
+ ...longPressHandlers,
7226
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
7227
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: /* @__PURE__ */ jsx(
7228
+ MemoizedEditableText,
7229
+ {
7230
+ ref: editableTitleRef,
7231
+ value: displayTitle,
7232
+ onSave: (newTitle) => onRename?.(newTitle),
7233
+ isLoading: isTitleGenerating
7234
+ }
7235
+ ) }),
7236
+ !isTouch && hasContextMenu && /* @__PURE__ */ jsxs(Menu, { children: [
7237
+ /* @__PURE__ */ jsx(
7238
+ MenuButton,
7268
7239
  {
7269
7240
  onClick: (e) => {
7270
7241
  e.preventDefault();
7271
7242
  e.stopPropagation();
7272
- onArchive();
7273
7243
  },
7274
- 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"}`,
7275
- "aria-label": t("Sidebar.ArchiveChat"),
7276
- "data-testid": `${testIdPrefix}-session-archive-${session.id}`,
7277
- children: [
7278
- /* @__PURE__ */ jsx(Archive, { size: 16, className: "w-4 h-4" }),
7279
- t("Sidebar.ArchiveChat")
7280
- ]
7244
+ 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",
7245
+ "aria-label": t("BiChat.Sidebar.ChatOptions"),
7246
+ "data-testid": `${testIdPrefix}-session-options-${session.id}`,
7247
+ children: /* @__PURE__ */ jsx(DotsThree, { size: 16, className: "w-4 h-4", weight: "bold" })
7281
7248
  }
7282
- ) }),
7283
- onDelete && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7284
- "button",
7249
+ ),
7250
+ /* @__PURE__ */ jsxs(
7251
+ MenuItems,
7285
7252
  {
7286
- onClick: (e) => {
7287
- e.preventDefault();
7288
- e.stopPropagation();
7289
- onDelete();
7290
- },
7291
- 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"}`,
7292
- "aria-label": t("Sidebar.DeleteChat"),
7293
- "data-testid": `${testIdPrefix}-session-delete-${session.id}`,
7253
+ anchor: "bottom start",
7254
+ 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",
7294
7255
  children: [
7295
- /* @__PURE__ */ jsx(Trash, { size: 16, className: "w-4 h-4" }),
7296
- t("Sidebar.DeleteChat")
7256
+ mode !== "archived" && onPin && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7257
+ "button",
7258
+ {
7259
+ onClick: (e) => {
7260
+ e.preventDefault();
7261
+ e.stopPropagation();
7262
+ onPin();
7263
+ },
7264
+ 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"}`,
7265
+ "aria-label": session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat"),
7266
+ "data-testid": `${testIdPrefix}-session-pin-${session.id}`,
7267
+ children: [
7268
+ session.pinned ? /* @__PURE__ */ jsx(Check, { size: 16, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Bookmark, { size: 16, className: "w-4 h-4" }),
7269
+ session.pinned ? t("BiChat.Sidebar.UnpinChat") : t("BiChat.Sidebar.PinChat")
7270
+ ]
7271
+ }
7272
+ ) }),
7273
+ onRename && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxs(
7274
+ "button",
7275
+ {
7276
+ onClick: (e) => {
7277
+ e.preventDefault();
7278
+ e.stopPropagation();
7279
+ editableTitleRef.current?.startEditing();
7280
+ close();
7281
+ },
7282
+ 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"}`,
7283
+ "aria-label": t("BiChat.Sidebar.RenameChat"),
7284
+ "data-testid": `${testIdPrefix}-session-rename-${session.id}`,
7285
+ children: [
7286
+ /* @__PURE__ */ jsx(PencilSimple, { size: 16, className: "w-4 h-4" }),
7287
+ t("BiChat.Sidebar.RenameChat")
7288
+ ]
7289
+ }
7290
+ ) }),
7291
+ mode !== "archived" && onRegenerateTitle && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus, close }) => /* @__PURE__ */ jsxs(
7292
+ "button",
7293
+ {
7294
+ onClick: (e) => {
7295
+ e.preventDefault();
7296
+ e.stopPropagation();
7297
+ onRegenerateTitle();
7298
+ close();
7299
+ },
7300
+ 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"}`,
7301
+ "aria-label": t("BiChat.Sidebar.RegenerateTitle"),
7302
+ "data-testid": `${testIdPrefix}-session-regenerate-${session.id}`,
7303
+ children: [
7304
+ /* @__PURE__ */ jsx(ArrowsClockwise, { size: 16, className: "w-4 h-4" }),
7305
+ t("BiChat.Sidebar.RegenerateTitle")
7306
+ ]
7307
+ }
7308
+ ) }),
7309
+ mode === "archived" && onRestore && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7310
+ "button",
7311
+ {
7312
+ onClick: (e) => {
7313
+ e.preventDefault();
7314
+ e.stopPropagation();
7315
+ onRestore();
7316
+ },
7317
+ 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"}`,
7318
+ "aria-label": t("BiChat.Archived.RestoreButton"),
7319
+ "data-testid": `${testIdPrefix}-session-restore-${session.id}`,
7320
+ children: [
7321
+ /* @__PURE__ */ jsx(ArrowUUpLeft, { size: 16, className: "w-4 h-4" }),
7322
+ t("BiChat.Archived.RestoreButton")
7323
+ ]
7324
+ }
7325
+ ) }),
7326
+ mode !== "archived" && onArchive && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7327
+ "button",
7328
+ {
7329
+ onClick: (e) => {
7330
+ e.preventDefault();
7331
+ e.stopPropagation();
7332
+ onArchive();
7333
+ },
7334
+ 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"}`,
7335
+ "aria-label": t("BiChat.Sidebar.ArchiveChat"),
7336
+ "data-testid": `${testIdPrefix}-session-archive-${session.id}`,
7337
+ children: [
7338
+ /* @__PURE__ */ jsx(Archive, { size: 16, className: "w-4 h-4" }),
7339
+ t("BiChat.Sidebar.ArchiveChat")
7340
+ ]
7341
+ }
7342
+ ) }),
7343
+ onDelete && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
7344
+ "button",
7345
+ {
7346
+ onClick: (e) => {
7347
+ e.preventDefault();
7348
+ e.stopPropagation();
7349
+ onDelete();
7350
+ },
7351
+ 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"}`,
7352
+ "aria-label": t("BiChat.Sidebar.DeleteChat"),
7353
+ "data-testid": `${testIdPrefix}-session-delete-${session.id}`,
7354
+ children: [
7355
+ /* @__PURE__ */ jsx(Trash, { size: 16, className: "w-4 h-4" }),
7356
+ t("BiChat.Sidebar.DeleteChat")
7357
+ ]
7358
+ }
7359
+ ) })
7297
7360
  ]
7298
7361
  }
7299
- ) })
7300
- ]
7301
- }
7302
- )
7303
- ] })
7304
- ] })
7305
- }
7306
- )
7362
+ )
7363
+ ] })
7364
+ ] })
7365
+ }
7366
+ )
7367
+ }
7368
+ )
7369
+ ]
7307
7370
  }
7308
7371
  ),
7309
7372
  /* @__PURE__ */ jsx(
@@ -7369,7 +7432,7 @@ function TabBar({ tabs, activeTab, onTabChange }) {
7369
7432
  "div",
7370
7433
  {
7371
7434
  ref: tablistRef,
7372
- className: "flex gap-1 px-4 pt-4 pb-2 border-b border-gray-200 dark:border-gray-700",
7435
+ className: "flex justify-center gap-1 px-4 pt-4 pb-2 border-b border-gray-200 dark:border-gray-700",
7373
7436
  role: "tablist",
7374
7437
  onKeyDown: handleKeyDown,
7375
7438
  children: tabs.map((tab) => /* @__PURE__ */ jsx(
@@ -7434,7 +7497,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7434
7497
  disabled:opacity-50 disabled:cursor-not-allowed
7435
7498
  flex items-center justify-between gap-2
7436
7499
  `,
7437
- "aria-label": t("allChats.allUsers"),
7500
+ "aria-label": t("BiChat.AllChats.AllUsers"),
7438
7501
  children: [
7439
7502
  selectedUser ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
7440
7503
  /* @__PURE__ */ jsx(
@@ -7451,7 +7514,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7451
7514
  " ",
7452
7515
  selectedUser.lastName
7453
7516
  ] })
7454
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400", children: loading ? t("allChats.loadingUsers") : t("allChats.allUsers") }),
7517
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400", children: loading ? t("BiChat.AllChats.LoadingUsers") : t("BiChat.AllChats.AllUsers") }),
7455
7518
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
7456
7519
  selectedUser && /* @__PURE__ */ jsx(
7457
7520
  "button",
@@ -7462,7 +7525,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7462
7525
  onUserChange(null);
7463
7526
  },
7464
7527
  className: "cursor-pointer p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-smooth",
7465
- "aria-label": t("Common.Clear"),
7528
+ "aria-label": t("BiChat.Common.Clear"),
7466
7529
  children: /* @__PURE__ */ jsx(X, { size: 14, className: "w-3.5 h-3.5 text-gray-600 dark:text-gray-400" })
7467
7530
  }
7468
7531
  ),
@@ -7493,7 +7556,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7493
7556
  ${focus ? "bg-gray-100 dark:bg-gray-700" : "hover:bg-gray-50 dark:hover:bg-gray-750"}
7494
7557
  ${!selectedUser ? "text-primary-700 dark:text-primary-400 font-medium" : "text-gray-900 dark:text-gray-100"}
7495
7558
  `,
7496
- children: t("allChats.allUsers")
7559
+ children: t("BiChat.AllChats.AllUsers")
7497
7560
  }
7498
7561
  ) }),
7499
7562
  users.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 my-1" }),
@@ -7526,7 +7589,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7526
7589
  ]
7527
7590
  }
7528
7591
  ) }, user.id)),
7529
- users.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: t("allChats.noUsersFound") }) })
7592
+ users.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("BiChat.AllChats.NoUsersFound") }) })
7530
7593
  ]
7531
7594
  }
7532
7595
  )
@@ -7591,7 +7654,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7591
7654
  }
7592
7655
  }).catch(() => {
7593
7656
  if (!cancelled) {
7594
- setError(t("allChats.failedToLoad"));
7657
+ setError(t("BiChat.AllChats.FailedToLoad"));
7595
7658
  setFetching(false);
7596
7659
  }
7597
7660
  });
@@ -7657,12 +7720,12 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7657
7720
  ),
7658
7721
  /* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-700 dark:text-gray-300 flex items-center gap-1.5", children: [
7659
7722
  /* @__PURE__ */ jsx(Archive, { size: 16, className: "w-4 h-4" }),
7660
- t("allChats.includeArchived")
7723
+ t("BiChat.AllChats.IncludeArchived")
7661
7724
  ] })
7662
7725
  ] }),
7663
- totalCount > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: totalCount === 1 ? t("allChats.chatFound", { count: totalCount }) : t("allChats.chatsFound", { count: totalCount }) })
7726
+ totalCount > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: totalCount === 1 ? t("BiChat.AllChats.ChatFound", { count: totalCount }) : t("BiChat.AllChats.ChatsFound", { count: totalCount }) })
7664
7727
  ] }),
7665
- /* @__PURE__ */ jsxs("nav", { className: "flex-1 overflow-y-auto px-2 pb-4 hide-scrollbar", "aria-label": t("allChats.organizationChats"), children: [
7728
+ /* @__PURE__ */ jsxs("nav", { className: "flex-1 overflow-y-auto px-2 pb-4 hide-scrollbar", "aria-label": t("BiChat.AllChats.OrganizationChats"), children: [
7666
7729
  fetching && chats.length === 0 ? /* @__PURE__ */ jsx(SessionSkeleton, { count: 5 }) : /* @__PURE__ */ jsx(Fragment, { children: chats.length > 0 ? /* @__PURE__ */ jsxs(
7667
7730
  motion.div,
7668
7731
  {
@@ -7671,7 +7734,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7671
7734
  initial: "hidden",
7672
7735
  animate: "visible",
7673
7736
  role: "list",
7674
- "aria-label": t("allChats.organizationChatSessions"),
7737
+ "aria-label": t("BiChat.AllChats.OrganizationChatSessions"),
7675
7738
  children: [
7676
7739
  chats.map((chat) => /* @__PURE__ */ jsx(
7677
7740
  motion.div,
@@ -7707,7 +7770,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7707
7770
  }
7708
7771
  ),
7709
7772
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
7710
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("Common.Untitled") }),
7773
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("BiChat.Common.Untitled") }),
7711
7774
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: [
7712
7775
  chat.owner.firstName,
7713
7776
  " ",
@@ -7715,7 +7778,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7715
7778
  ] }),
7716
7779
  chat.status === "archived" && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
7717
7780
  /* @__PURE__ */ jsx(Archive, { size: 12, className: "w-3 h-3" }),
7718
- t("Chat.Archived")
7781
+ t("BiChat.Chat.Archived")
7719
7782
  ] })
7720
7783
  ] })
7721
7784
  ] })
@@ -7729,7 +7792,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7729
7792
  {
7730
7793
  onClick: handleLoadMore,
7731
7794
  className: "text-sm text-primary-600 dark:text-primary-400 hover:underline",
7732
- children: t("allChats.loadMore")
7795
+ children: t("BiChat.AllChats.LoadMore")
7733
7796
  }
7734
7797
  ) })
7735
7798
  ]
@@ -7737,8 +7800,8 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7737
7800
  ) : /* @__PURE__ */ jsx(
7738
7801
  MemoizedEmptyState,
7739
7802
  {
7740
- title: t("allChats.noChatsFound"),
7741
- description: selectedUser ? t("allChats.noChatsFromUser", { firstName: selectedUser.firstName, lastName: selectedUser.lastName }) : includeArchived ? t("allChats.noChatsInOrg") : t("allChats.noActiveChatsInOrg")
7803
+ title: t("BiChat.AllChats.NoChatsFound"),
7804
+ description: selectedUser ? t("BiChat.AllChats.NoChatsFromUser", { firstName: selectedUser.firstName, lastName: selectedUser.lastName }) : includeArchived ? t("BiChat.AllChats.NoChatsInOrg") : t("BiChat.AllChats.NoActiveChatsInOrg")
7742
7805
  }
7743
7806
  ) }),
7744
7807
  error && /* @__PURE__ */ jsx("div", { className: "mx-2 mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600 dark:text-red-400", children: error }) })
@@ -7782,11 +7845,11 @@ function groupSessionsByDate(sessions, t) {
7782
7845
  const today = startOfDay(now);
7783
7846
  const translate = t || ((key2) => key2);
7784
7847
  const dateLabels = {
7785
- "Today": translate("DateGroup.Today"),
7786
- "Yesterday": translate("DateGroup.Yesterday"),
7787
- "Last 7 Days": translate("DateGroup.Last7Days"),
7788
- "Last 30 Days": translate("DateGroup.Last30Days"),
7789
- "Older": translate("DateGroup.Older")
7848
+ "Today": translate("BiChat.DateGroup.Today"),
7849
+ "Yesterday": translate("BiChat.DateGroup.Yesterday"),
7850
+ "Last 7 Days": translate("BiChat.DateGroup.Last7Days"),
7851
+ "Last 30 Days": translate("BiChat.DateGroup.Last30Days"),
7852
+ "Older": translate("BiChat.DateGroup.Older")
7790
7853
  };
7791
7854
  const groupMap = /* @__PURE__ */ new Map([
7792
7855
  ["Today", []],
@@ -7823,6 +7886,113 @@ function groupSessionsByDate(sessions, t) {
7823
7886
  });
7824
7887
  return groups;
7825
7888
  }
7889
+
7890
+ // ui/src/bichat/utils/errorDisplay.ts
7891
+ function isPermissionDeniedError(error) {
7892
+ if (!error) return false;
7893
+ if (error instanceof Error) {
7894
+ const msg = error.message.toLowerCase();
7895
+ if (msg.includes("forbidden") || msg.includes("permission denied")) return true;
7896
+ }
7897
+ if (typeof error === "object" && error !== null) {
7898
+ const obj = error;
7899
+ if (obj.code === "forbidden" || obj.code === 403) return true;
7900
+ if (obj.status === 403) return true;
7901
+ if (obj.statusCode === 403) return true;
7902
+ if (typeof obj.response === "object" && obj.response !== null) {
7903
+ const resp = obj.response;
7904
+ if (resp.status === 403) return true;
7905
+ }
7906
+ }
7907
+ if (typeof error === "string") {
7908
+ const lower = error.toLowerCase();
7909
+ if (lower.includes("forbidden") || lower.includes("permission denied")) return true;
7910
+ }
7911
+ return false;
7912
+ }
7913
+ function toErrorDisplay(error, fallbackTitle) {
7914
+ const permDenied = isPermissionDeniedError(error);
7915
+ let title = fallbackTitle;
7916
+ let description = "";
7917
+ if (error instanceof Error) {
7918
+ description = error.message;
7919
+ } else if (typeof error === "object" && error !== null) {
7920
+ const obj = error;
7921
+ if (typeof obj.message === "string" && obj.message) description = obj.message;
7922
+ if (typeof obj.title === "string" && obj.title) title = obj.title;
7923
+ if (typeof obj.detail === "string" && obj.detail) description = obj.detail;
7924
+ } else if (typeof error === "string") {
7925
+ description = error;
7926
+ }
7927
+ if (permDenied && !description) {
7928
+ description = "Your account does not have permission for this action.";
7929
+ }
7930
+ return { title, description, isPermissionDenied: permDenied };
7931
+ }
7932
+ function ErrorAlert({ error }) {
7933
+ const amber = error.isPermissionDenied;
7934
+ return /* @__PURE__ */ jsxs(
7935
+ "div",
7936
+ {
7937
+ 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"}`,
7938
+ children: [
7939
+ /* @__PURE__ */ jsx(
7940
+ "p",
7941
+ {
7942
+ className: `text-xs font-medium ${amber ? "text-amber-700 dark:text-amber-300" : "text-red-600 dark:text-red-400"}`,
7943
+ children: error.title
7944
+ }
7945
+ ),
7946
+ error.description && /* @__PURE__ */ jsx(
7947
+ "p",
7948
+ {
7949
+ className: `mt-1 text-xs ${amber ? "text-amber-600 dark:text-amber-400" : "text-red-500 dark:text-red-300"}`,
7950
+ children: error.description
7951
+ }
7952
+ )
7953
+ ]
7954
+ }
7955
+ );
7956
+ }
7957
+ var COLLAPSE_STORAGE_KEY = "bichat-sidebar-collapsed";
7958
+ function useSidebarCollapse() {
7959
+ const [isCollapsed, setIsCollapsed] = useState(() => {
7960
+ try {
7961
+ return localStorage.getItem(COLLAPSE_STORAGE_KEY) === "true";
7962
+ } catch {
7963
+ return false;
7964
+ }
7965
+ });
7966
+ const isCollapsedRef = useRef(isCollapsed);
7967
+ useEffect(() => {
7968
+ isCollapsedRef.current = isCollapsed;
7969
+ }, [isCollapsed]);
7970
+ const toggle = useCallback(() => {
7971
+ setIsCollapsed((prev) => {
7972
+ const next = !prev;
7973
+ try {
7974
+ localStorage.setItem(COLLAPSE_STORAGE_KEY, String(next));
7975
+ } catch {
7976
+ }
7977
+ return next;
7978
+ });
7979
+ }, []);
7980
+ const expand = useCallback(() => {
7981
+ setIsCollapsed(false);
7982
+ try {
7983
+ localStorage.setItem(COLLAPSE_STORAGE_KEY, "false");
7984
+ } catch {
7985
+ }
7986
+ }, []);
7987
+ const collapse = useCallback(() => {
7988
+ setIsCollapsed(true);
7989
+ try {
7990
+ localStorage.setItem(COLLAPSE_STORAGE_KEY, "true");
7991
+ } catch {
7992
+ }
7993
+ }, []);
7994
+ return { isCollapsed, isCollapsedRef, toggle, expand, collapse };
7995
+ }
7826
7996
  function Sidebar2({
7827
7997
  dataSource,
7828
7998
  onSessionSelect,
@@ -7841,30 +8011,84 @@ function Sidebar2({
7841
8011
  const toast = useToast();
7842
8012
  const shouldReduceMotion = useReducedMotion();
7843
8013
  const sessionListRef = useRef(null);
8014
+ const searchContainerRef = useRef(null);
8015
+ const { isCollapsed, isCollapsedRef, toggle, expand, collapse } = useSidebarCollapse();
8016
+ const collapsible = !onClose;
8017
+ const handleSidebarClick = useCallback(
8018
+ (e) => {
8019
+ if (!collapsible) return;
8020
+ const interactive = 'a, button, input, summary, [role="button"]';
8021
+ if (e.target.closest(interactive)) return;
8022
+ toggle();
8023
+ },
8024
+ [collapsible, toggle]
8025
+ );
8026
+ const focusSearch = useCallback(() => {
8027
+ if (!collapsible) return;
8028
+ if (isCollapsedRef.current) {
8029
+ expand();
8030
+ setTimeout(() => {
8031
+ searchContainerRef.current?.querySelector("input")?.focus();
8032
+ }, 250);
8033
+ } else {
8034
+ searchContainerRef.current?.querySelector("input")?.focus();
8035
+ }
8036
+ }, [collapsible, expand, isCollapsedRef]);
8037
+ useEffect(() => {
8038
+ if (!collapsible) return;
8039
+ const handleKeyDown = (e) => {
8040
+ const isMod = e.metaKey || e.ctrlKey;
8041
+ if (isMod && e.key === "b") {
8042
+ e.preventDefault();
8043
+ toggle();
8044
+ }
8045
+ if (isMod && e.key === "k") {
8046
+ e.preventDefault();
8047
+ focusSearch();
8048
+ }
8049
+ };
8050
+ document.addEventListener("keydown", handleKeyDown);
8051
+ return () => document.removeEventListener("keydown", handleKeyDown);
8052
+ }, [collapsible, toggle, focusSearch]);
8053
+ useEffect(() => {
8054
+ if (!collapsible) return;
8055
+ const handler = (e) => {
8056
+ const detail = e.detail;
8057
+ if (detail?.expanded) {
8058
+ collapse();
8059
+ }
8060
+ };
8061
+ window.addEventListener("bichat:artifacts-panel-expanded", handler);
8062
+ return () => window.removeEventListener("bichat:artifacts-panel-expanded", handler);
8063
+ }, [collapsible, collapse]);
8064
+ const showCollapsed = collapsible && isCollapsed;
7844
8065
  const [activeTab, setActiveTab] = useState("my-chats");
7845
8066
  const [searchQuery, setSearchQuery] = useState("");
7846
8067
  const [sessions, setSessions] = useState([]);
7847
8068
  const [loading, setLoading] = useState(true);
7848
- const [error, setError] = useState(null);
8069
+ const [loadError, setLoadError] = useState(null);
8070
+ const [actionError, setActionError] = useState(null);
8071
+ const accessDenied = loadError?.isPermissionDenied === true;
7849
8072
  const [refreshKey, setRefreshKey] = useState(0);
7850
8073
  const [showConfirm, setShowConfirm] = useState(false);
7851
8074
  const [sessionToArchive, setSessionToArchive] = useState(null);
7852
8075
  const tabs = useMemo(() => {
7853
- const items = [{ id: "my-chats", label: t("Sidebar.MyChats") }];
8076
+ const items = [{ id: "my-chats", label: t("BiChat.Sidebar.MyChats") }];
7854
8077
  if (showAllChatsTab) {
7855
- items.push({ id: "all-chats", label: t("Sidebar.AllChats") });
8078
+ items.push({ id: "all-chats", label: t("BiChat.Sidebar.AllChats") });
7856
8079
  }
7857
8080
  return items;
7858
8081
  }, [showAllChatsTab, t]);
7859
8082
  const fetchSessions = useCallback(async () => {
7860
8083
  try {
7861
8084
  setLoading(true);
7862
- setError(null);
8085
+ setLoadError(null);
8086
+ setActionError(null);
7863
8087
  const result = await dataSource.listSessions({ limit: 50 });
7864
8088
  setSessions(result.sessions);
7865
8089
  } catch (err) {
7866
8090
  console.error("Failed to load sessions:", err);
7867
- setError(t("Sidebar.FailedToLoadSessions"));
8091
+ setLoadError(toErrorDisplay(err, t("BiChat.Sidebar.FailedToLoadSessions")));
7868
8092
  } finally {
7869
8093
  setLoading(false);
7870
8094
  }
@@ -7873,7 +8097,7 @@ function Sidebar2({
7873
8097
  fetchSessions();
7874
8098
  }, [fetchSessions, refreshKey]);
7875
8099
  const hasPlaceholderTitles = useMemo(() => {
7876
- const newChatLabel = t("Chat.NewChat");
8100
+ const newChatLabel = t("BiChat.Chat.NewChat");
7877
8101
  return Array.isArray(sessions) && sessions.some((s) => s && (!s.title || s.title === newChatLabel));
7878
8102
  }, [sessions, t]);
7879
8103
  useEffect(() => {
@@ -7909,7 +8133,9 @@ function Sidebar2({
7909
8133
  }
7910
8134
  } catch (err) {
7911
8135
  console.error("Failed to archive session:", err);
7912
- toast.error(t("Sidebar.FailedToArchiveChat"));
8136
+ const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToArchiveChat"));
8137
+ setActionError(display);
8138
+ toast.error(display.title);
7913
8139
  } finally {
7914
8140
  setShowConfirm(false);
7915
8141
  setSessionToArchive(null);
@@ -7925,27 +8151,33 @@ function Sidebar2({
7925
8151
  setRefreshKey((k) => k + 1);
7926
8152
  } catch (err) {
7927
8153
  console.error("Failed to toggle pin:", err);
7928
- toast.error(t("Sidebar.FailedToTogglePin"));
8154
+ const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToTogglePin"));
8155
+ setActionError(display);
8156
+ toast.error(display.title);
7929
8157
  }
7930
8158
  };
7931
8159
  const handleRenameSession = async (sessionId, newTitle) => {
7932
8160
  try {
7933
8161
  await dataSource.renameSession(sessionId, newTitle);
7934
- toast.success(t("Sidebar.ChatRenamedSuccessfully"));
8162
+ toast.success(t("BiChat.Sidebar.ChatRenamedSuccessfully"));
7935
8163
  setRefreshKey((k) => k + 1);
7936
8164
  } catch (err) {
7937
8165
  console.error("Failed to update session title:", err);
7938
- toast.error(t("Sidebar.FailedToRenameChat"));
8166
+ const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToRenameChat"));
8167
+ setActionError(display);
8168
+ toast.error(display.title);
7939
8169
  }
7940
8170
  };
7941
8171
  const handleRegenerateTitle = async (sessionId) => {
7942
8172
  try {
7943
8173
  await dataSource.regenerateSessionTitle(sessionId);
7944
- toast.success(t("Sidebar.TitleRegenerated"));
8174
+ toast.success(t("BiChat.Sidebar.TitleRegenerated"));
7945
8175
  setRefreshKey((k) => k + 1);
7946
8176
  } catch (err) {
7947
8177
  console.error("Failed to regenerate title:", err);
7948
- toast.error(t("Sidebar.FailedToRegenerateTitle"));
8178
+ const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToRegenerateTitle"));
8179
+ setActionError(display);
8180
+ toast.error(display.title);
7949
8181
  }
7950
8182
  };
7951
8183
  const filteredSessions = useMemo(() => {
@@ -8008,176 +8240,311 @@ function Sidebar2({
8008
8240
  /* @__PURE__ */ jsxs(
8009
8241
  "aside",
8010
8242
  {
8011
- className: `w-64 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 ${className}`,
8243
+ onClick: collapsible ? handleSidebarClick : void 0,
8244
+ 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}`,
8245
+ style: { willChange: "width" },
8012
8246
  role: "navigation",
8013
- "aria-label": t("Sidebar.ChatSessions"),
8247
+ "aria-label": t("BiChat.Sidebar.ChatSessions"),
8014
8248
  children: [
8015
- /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
8016
- headerSlot,
8017
- onClose && /* @__PURE__ */ jsx(
8018
- motion.button,
8019
- {
8020
- onClick: onClose,
8021
- 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",
8022
- title: t("Sidebar.CloseSidebar"),
8023
- "aria-label": t("Sidebar.CloseSidebar"),
8024
- whileHover: "hover",
8025
- whileTap: "tap",
8026
- variants: buttonVariants,
8027
- children: /* @__PURE__ */ jsx(X, { size: 20, className: "w-5 h-5" })
8028
- }
8029
- )
8030
- ] }),
8031
- showAllChatsTab && /* @__PURE__ */ jsx(
8032
- TabBar_default,
8249
+ collapsible && /* @__PURE__ */ jsx(
8250
+ "div",
8033
8251
  {
8034
- tabs,
8035
- activeTab,
8036
- onTabChange: (id) => setActiveTab(id)
8252
+ 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"}`,
8253
+ children: /* @__PURE__ */ jsxs("div", { className: "group/tooltip relative", children: [
8254
+ /* @__PURE__ */ jsx(
8255
+ motion.button,
8256
+ {
8257
+ onClick: (e) => {
8258
+ e.stopPropagation();
8259
+ onNewChat();
8260
+ },
8261
+ disabled: creating || loading || accessDenied,
8262
+ 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",
8263
+ title: t("BiChat.Chat.NewChat"),
8264
+ "aria-label": t("BiChat.Sidebar.CreateNewChat"),
8265
+ whileTap: { scale: 0.95 },
8266
+ children: creating ? /* @__PURE__ */ jsx("div", { className: "w-4 h-4 border-2 border-white/50 border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsx(Plus, { size: 18, weight: "bold" })
8267
+ }
8268
+ ),
8269
+ /* @__PURE__ */ 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") })
8270
+ ] })
8037
8271
  }
8038
8272
  ),
8039
- activeTab === "all-chats" && showAllChatsTab ? /* @__PURE__ */ jsx(
8040
- AllChatsList,
8273
+ /* @__PURE__ */ jsxs(
8274
+ "div",
8041
8275
  {
8042
- dataSource,
8043
- onSessionSelect,
8044
- activeSessionId
8045
- }
8046
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
8047
- /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(
8048
- SearchInput_default,
8049
- {
8050
- value: searchQuery,
8051
- onChange: setSearchQuery,
8052
- placeholder: t("Sidebar.SearchChats")
8053
- }
8054
- ) }),
8055
- /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
8056
- motion.button,
8057
- {
8058
- onClick: onNewChat,
8059
- disabled: creating || loading,
8060
- className: "cursor-pointer w-full px-4 py-3 bg-primary-600 dark:bg-primary-700 text-white rounded-lg hover:bg-primary-700 dark:hover:bg-primary-800 transition-smooth font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
8061
- title: t("Chat.NewChat"),
8062
- "aria-label": t("Sidebar.CreateNewChat"),
8063
- whileHover: shouldReduceMotion ? {} : { scale: 1.02 },
8064
- whileTap: shouldReduceMotion ? {} : { scale: 0.95 },
8065
- children: creating ? /* @__PURE__ */ jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8066
- /* @__PURE__ */ jsx(Plus, { size: 20, className: "w-5 h-5" }),
8067
- /* @__PURE__ */ jsx("span", { className: "ml-2", children: t("Chat.NewChat") })
8068
- ] })
8069
- }
8070
- ) }),
8071
- onArchivedView && /* @__PURE__ */ jsx("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsxs(
8072
- "button",
8073
- {
8074
- onClick: onArchivedView,
8075
- className: "cursor-pointer flex items-center gap-2 px-3 py-2 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-smooth text-sm font-medium w-full",
8076
- title: t("Sidebar.ArchivedChats"),
8077
- children: [
8078
- /* @__PURE__ */ jsx(Archive, { size: 18, className: "w-4.5 h-4.5" }),
8079
- /* @__PURE__ */ jsx("span", { children: t("Sidebar.ArchivedChats") })
8080
- ]
8081
- }
8082
- ) }),
8083
- /* @__PURE__ */ jsxs(
8084
- "nav",
8085
- {
8086
- ref: sessionListRef,
8087
- className: "flex-1 overflow-y-auto px-2 pb-4 hide-scrollbar",
8088
- "aria-label": "Chat history",
8089
- onKeyDown: handleSessionListKeyDown,
8090
- children: [
8091
- loading && sessions.length === 0 ? /* @__PURE__ */ jsx(SessionSkeleton, { count: 5 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8092
- pinnedSessions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
8093
- /* @__PURE__ */ jsx(
8094
- DateGroupHeader,
8095
- {
8096
- groupName: t("Common.Pinned"),
8097
- count: pinnedSessions.length
8098
- }
8099
- ),
8100
- /* @__PURE__ */ jsx(
8101
- motion.div,
8102
- {
8103
- className: "space-y-1 mt-2",
8104
- variants: staggerContainerVariants,
8105
- initial: "hidden",
8106
- animate: "visible",
8107
- role: "list",
8108
- "aria-label": t("Sidebar.PinnedChats"),
8109
- children: pinnedSessions.map((session) => /* @__PURE__ */ jsx(
8110
- SessionItem_default,
8111
- {
8112
- session,
8113
- isActive: session.id === activeSessionId,
8114
- onSelect: () => onSessionSelect(session.id),
8115
- onArchive: () => handleArchiveRequest(session.id),
8116
- onPin: () => handleTogglePin(session.id, session.pinned),
8117
- onRename: (newTitle) => handleRenameSession(session.id, newTitle),
8118
- onRegenerateTitle: () => handleRegenerateTitle(session.id)
8119
- },
8120
- session.id
8121
- ))
8122
- }
8123
- ),
8124
- /* @__PURE__ */ jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
8125
- ] }),
8126
- sessionGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
8127
- /* @__PURE__ */ jsx(
8128
- DateGroupHeader,
8129
- {
8130
- groupName: group.name,
8131
- count: group.sessions.length
8132
- }
8133
- ),
8134
- /* @__PURE__ */ jsx(
8135
- motion.div,
8136
- {
8137
- className: "space-y-1 mt-2",
8138
- variants: staggerContainerVariants,
8139
- initial: "hidden",
8140
- animate: "visible",
8141
- role: "list",
8142
- "aria-label": `${group.name} chats`,
8143
- children: group.sessions.map((session) => /* @__PURE__ */ jsx(
8144
- SessionItem_default,
8276
+ 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]" : ""}`,
8277
+ children: [
8278
+ (headerSlot || onClose) && /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
8279
+ headerSlot,
8280
+ onClose && /* @__PURE__ */ jsx(
8281
+ motion.button,
8282
+ {
8283
+ onClick: onClose,
8284
+ 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",
8285
+ title: t("BiChat.Sidebar.CloseSidebar"),
8286
+ "aria-label": t("BiChat.Sidebar.CloseSidebar"),
8287
+ whileHover: "hover",
8288
+ whileTap: "tap",
8289
+ variants: buttonVariants,
8290
+ children: /* @__PURE__ */ jsx(X, { size: 20, className: "w-5 h-5" })
8291
+ }
8292
+ )
8293
+ ] }),
8294
+ showAllChatsTab && /* @__PURE__ */ jsx(
8295
+ TabBar_default,
8296
+ {
8297
+ tabs,
8298
+ activeTab,
8299
+ onTabChange: (id) => setActiveTab(id)
8300
+ }
8301
+ ),
8302
+ activeTab === "all-chats" && showAllChatsTab ? /* @__PURE__ */ jsx(
8303
+ AllChatsList,
8304
+ {
8305
+ dataSource,
8306
+ onSessionSelect,
8307
+ activeSessionId
8308
+ }
8309
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
8310
+ /* @__PURE__ */ jsx("div", { ref: searchContainerRef, className: "mt-3 px-4", children: /* @__PURE__ */ jsx(
8311
+ SearchInput_default,
8312
+ {
8313
+ value: searchQuery,
8314
+ onChange: setSearchQuery,
8315
+ placeholder: t("BiChat.Sidebar.SearchChats")
8316
+ }
8317
+ ) }),
8318
+ /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
8319
+ motion.button,
8320
+ {
8321
+ onClick: (e) => {
8322
+ e.stopPropagation();
8323
+ onNewChat();
8324
+ },
8325
+ disabled: creating || loading || accessDenied,
8326
+ 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",
8327
+ title: accessDenied ? t("BiChat.Sidebar.MissingPermission") : t("BiChat.Chat.NewChat"),
8328
+ "aria-label": t("BiChat.Sidebar.CreateNewChat"),
8329
+ whileHover: shouldReduceMotion ? {} : { y: -1 },
8330
+ whileTap: shouldReduceMotion ? {} : { scale: 0.98 },
8331
+ children: creating ? /* @__PURE__ */ jsxs(Fragment, { children: [
8332
+ /* @__PURE__ */ jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }),
8333
+ /* @__PURE__ */ jsx("span", { children: t("BiChat.Common.Creating") })
8334
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8335
+ /* @__PURE__ */ jsx(Plus, { size: 16, weight: "bold" }),
8336
+ /* @__PURE__ */ jsx("span", { children: t("BiChat.Chat.NewChat") })
8337
+ ] })
8338
+ }
8339
+ ) }),
8340
+ /* @__PURE__ */ jsxs(
8341
+ "nav",
8342
+ {
8343
+ ref: sessionListRef,
8344
+ className: "flex-1 overflow-y-auto px-2 pb-4 hide-scrollbar",
8345
+ "aria-label": t("BiChat.Sidebar.ChatHistory"),
8346
+ onKeyDown: handleSessionListKeyDown,
8347
+ children: [
8348
+ loading && sessions.length === 0 ? /* @__PURE__ */ jsx(SessionSkeleton, { count: 5 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8349
+ pinnedSessions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
8350
+ /* @__PURE__ */ jsx(
8351
+ DateGroupHeader,
8352
+ {
8353
+ groupName: t("BiChat.Common.Pinned"),
8354
+ count: pinnedSessions.length
8355
+ }
8356
+ ),
8357
+ /* @__PURE__ */ jsx(
8358
+ motion.div,
8359
+ {
8360
+ className: "space-y-1 mt-2",
8361
+ variants: staggerContainerVariants,
8362
+ initial: "hidden",
8363
+ animate: "visible",
8364
+ role: "list",
8365
+ "aria-label": t("BiChat.Sidebar.PinnedChats"),
8366
+ children: pinnedSessions.map((session) => /* @__PURE__ */ jsx(
8367
+ SessionItem_default,
8368
+ {
8369
+ session,
8370
+ isActive: session.id === activeSessionId,
8371
+ onSelect: () => onSessionSelect(session.id),
8372
+ onArchive: () => handleArchiveRequest(session.id),
8373
+ onPin: () => handleTogglePin(session.id, session.pinned),
8374
+ onRename: (newTitle) => handleRenameSession(session.id, newTitle),
8375
+ onRegenerateTitle: () => handleRegenerateTitle(session.id)
8376
+ },
8377
+ session.id
8378
+ ))
8379
+ }
8380
+ ),
8381
+ /* @__PURE__ */ jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
8382
+ ] }),
8383
+ sessionGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
8384
+ /* @__PURE__ */ jsx(
8385
+ DateGroupHeader,
8386
+ {
8387
+ groupName: group.name,
8388
+ count: group.sessions.length
8389
+ }
8390
+ ),
8391
+ /* @__PURE__ */ jsx(
8392
+ motion.div,
8393
+ {
8394
+ className: "space-y-1 mt-2",
8395
+ variants: staggerContainerVariants,
8396
+ initial: "hidden",
8397
+ animate: "visible",
8398
+ role: "list",
8399
+ "aria-label": `${group.name} chats`,
8400
+ children: group.sessions.map((session) => /* @__PURE__ */ jsx(
8401
+ SessionItem_default,
8402
+ {
8403
+ session,
8404
+ isActive: session.id === activeSessionId,
8405
+ onSelect: () => onSessionSelect(session.id),
8406
+ onArchive: () => handleArchiveRequest(session.id),
8407
+ onPin: () => handleTogglePin(session.id, session.pinned),
8408
+ onRename: (newTitle) => handleRenameSession(session.id, newTitle),
8409
+ onRegenerateTitle: () => handleRegenerateTitle(session.id)
8410
+ },
8411
+ session.id
8412
+ ))
8413
+ }
8414
+ )
8415
+ ] }, group.name)),
8416
+ filteredSessions.length === 0 && !loading && /* @__PURE__ */ jsx(
8417
+ MemoizedEmptyState,
8145
8418
  {
8146
- session,
8147
- isActive: session.id === activeSessionId,
8148
- onSelect: () => onSessionSelect(session.id),
8149
- onArchive: () => handleArchiveRequest(session.id),
8150
- onPin: () => handleTogglePin(session.id, session.pinned),
8151
- onRename: (newTitle) => handleRenameSession(session.id, newTitle),
8152
- onRegenerateTitle: () => handleRegenerateTitle(session.id)
8153
- },
8154
- session.id
8155
- ))
8156
- }
8157
- )
8158
- ] }, group.name)),
8159
- filteredSessions.length === 0 && !loading && /* @__PURE__ */ jsx(
8160
- MemoizedEmptyState,
8419
+ title: searchQuery ? t("BiChat.Sidebar.NoChatsFound", { query: searchQuery }) : t("BiChat.Sidebar.NoChatsYet"),
8420
+ description: searchQuery ? void 0 : t("BiChat.Sidebar.CreateOneToGetStarted"),
8421
+ action: searchQuery ? /* @__PURE__ */ jsx(
8422
+ "button",
8423
+ {
8424
+ onClick: () => setSearchQuery(""),
8425
+ className: "cursor-pointer text-sm text-primary-600 dark:text-primary-400 hover:underline",
8426
+ children: t("BiChat.Common.Clear")
8427
+ }
8428
+ ) : void 0
8429
+ }
8430
+ )
8431
+ ] }),
8432
+ loadError && /* @__PURE__ */ jsx(ErrorAlert, { error: loadError }),
8433
+ actionError && !loadError && /* @__PURE__ */ jsx(ErrorAlert, { error: actionError })
8434
+ ]
8435
+ }
8436
+ ),
8437
+ footerSlot
8438
+ ] }),
8439
+ collapsible && /* @__PURE__ */ 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: [
8440
+ onArchivedView || showAllChatsTab ? /* @__PURE__ */ jsxs(Menu, { children: [
8441
+ /* @__PURE__ */ jsx(
8442
+ MenuButton,
8161
8443
  {
8162
- title: searchQuery ? t("Sidebar.NoChatsFound", { query: searchQuery }) : t("Sidebar.NoChatsYet"),
8163
- description: searchQuery ? void 0 : t("Sidebar.CreateOneToGetStarted"),
8164
- action: searchQuery ? /* @__PURE__ */ jsx(
8165
- "button",
8166
- {
8167
- onClick: () => setSearchQuery(""),
8168
- className: "cursor-pointer text-sm text-primary-600 dark:text-primary-400 hover:underline",
8169
- children: t("Common.Clear")
8170
- }
8171
- ) : void 0
8444
+ onClick: (e) => {
8445
+ e.stopPropagation();
8446
+ },
8447
+ disabled: loading || accessDenied,
8448
+ 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",
8449
+ "aria-label": t("BiChat.Sidebar.Settings"),
8450
+ title: t("BiChat.Sidebar.Settings"),
8451
+ children: /* @__PURE__ */ jsx(Gear, { size: 20 })
8452
+ }
8453
+ ),
8454
+ /* @__PURE__ */ jsxs(
8455
+ MenuItems,
8456
+ {
8457
+ anchor: "top start",
8458
+ 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",
8459
+ children: [
8460
+ onArchivedView && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
8461
+ "button",
8462
+ {
8463
+ onClick: (e) => {
8464
+ e.preventDefault();
8465
+ e.stopPropagation();
8466
+ onArchivedView();
8467
+ },
8468
+ 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" : ""}`,
8469
+ "aria-label": t("BiChat.Sidebar.ArchivedChats"),
8470
+ children: [
8471
+ /* @__PURE__ */ jsx(Archive, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
8472
+ t("BiChat.Sidebar.ArchivedChats")
8473
+ ]
8474
+ }
8475
+ ) }),
8476
+ showAllChatsTab && activeTab !== "all-chats" && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
8477
+ "button",
8478
+ {
8479
+ onClick: (e) => {
8480
+ e.preventDefault();
8481
+ e.stopPropagation();
8482
+ setActiveTab("all-chats");
8483
+ },
8484
+ 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" : ""}`,
8485
+ "aria-label": t("BiChat.Sidebar.AllChats"),
8486
+ children: [
8487
+ /* @__PURE__ */ jsx(Users, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
8488
+ t("BiChat.Sidebar.AllChats")
8489
+ ]
8490
+ }
8491
+ ) }),
8492
+ showAllChatsTab && activeTab === "all-chats" && /* @__PURE__ */ jsx(MenuItem, { children: ({ focus }) => /* @__PURE__ */ jsxs(
8493
+ "button",
8494
+ {
8495
+ onClick: (e) => {
8496
+ e.preventDefault();
8497
+ e.stopPropagation();
8498
+ setActiveTab("my-chats");
8499
+ },
8500
+ 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" : ""}`,
8501
+ "aria-label": t("BiChat.Sidebar.MyChats"),
8502
+ children: [
8503
+ /* @__PURE__ */ jsx(List, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
8504
+ t("BiChat.Sidebar.MyChats")
8505
+ ]
8506
+ }
8507
+ ) })
8508
+ ]
8172
8509
  }
8173
8510
  )
8174
- ] }),
8175
- error && /* @__PURE__ */ jsx("div", { className: "mx-2 mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600 dark:text-red-400", children: error }) })
8176
- ]
8511
+ ] }) : /* @__PURE__ */ jsx("div", {}),
8512
+ /* @__PURE__ */ jsxs(
8513
+ "button",
8514
+ {
8515
+ onClick: (e) => {
8516
+ e.stopPropagation();
8517
+ toggle();
8518
+ },
8519
+ 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",
8520
+ title: t("BiChat.Sidebar.CollapseSidebar"),
8521
+ "aria-label": t("BiChat.Sidebar.CollapseSidebar"),
8522
+ children: [
8523
+ /* @__PURE__ */ jsx(CaretLineLeft, { size: 16 }),
8524
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("BiChat.Sidebar.Collapse") })
8525
+ ]
8526
+ }
8527
+ )
8528
+ ] })
8529
+ ]
8530
+ }
8531
+ ),
8532
+ collapsible && showCollapsed && /* @__PURE__ */ 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__ */ jsxs("div", { className: "group/tooltip relative", children: [
8533
+ /* @__PURE__ */ jsx(
8534
+ "button",
8535
+ {
8536
+ onClick: (e) => {
8537
+ e.stopPropagation();
8538
+ toggle();
8539
+ },
8540
+ 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",
8541
+ title: t("BiChat.Sidebar.ExpandSidebar"),
8542
+ "aria-label": t("BiChat.Sidebar.ExpandSidebar"),
8543
+ children: /* @__PURE__ */ jsx(CaretLineRight, { size: 16 })
8177
8544
  }
8178
8545
  ),
8179
- footerSlot
8180
- ] })
8546
+ /* @__PURE__ */ 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") })
8547
+ ] }) })
8181
8548
  ]
8182
8549
  }
8183
8550
  ),
@@ -8185,11 +8552,11 @@ function Sidebar2({
8185
8552
  ConfirmModal_default,
8186
8553
  {
8187
8554
  isOpen: showConfirm,
8188
- title: t("Sidebar.ArchiveChatSession"),
8189
- message: t("Sidebar.ArchiveChatMessage"),
8190
- confirmText: t("Sidebar.ArchiveButton"),
8191
- cancelText: t("Common.Cancel"),
8192
- isDanger: false,
8555
+ title: t("BiChat.Sidebar.ArchiveChatSession"),
8556
+ message: t("BiChat.Sidebar.ArchiveChatMessage"),
8557
+ confirmText: t("BiChat.Sidebar.ArchiveButton"),
8558
+ cancelText: t("BiChat.Common.Cancel"),
8559
+ isDanger: true,
8193
8560
  onConfirm: confirmArchive,
8194
8561
  onCancel: () => {
8195
8562
  setShowConfirm(false);
@@ -8245,10 +8612,10 @@ function ArchivedChatList({
8245
8612
  try {
8246
8613
  await dataSource.unarchiveSession(sessionToRestore);
8247
8614
  setRefreshKey((k) => k + 1);
8248
- toast.success(t("Archived.ChatRestoredSuccessfully"));
8615
+ toast.success(t("BiChat.Archived.ChatRestoredSuccessfully"));
8249
8616
  } catch (err) {
8250
8617
  console.error("Failed to restore session:", err);
8251
- toast.error(t("Archived.FailedToRestoreChat"));
8618
+ toast.error(t("BiChat.Archived.FailedToRestoreChat"));
8252
8619
  } finally {
8253
8620
  setShowConfirm(false);
8254
8621
  setSessionToRestore(null);
@@ -8257,11 +8624,11 @@ function ArchivedChatList({
8257
8624
  const handleRenameSession = async (sessionId, newTitle) => {
8258
8625
  try {
8259
8626
  await dataSource.renameSession(sessionId, newTitle);
8260
- toast.success(t("Sidebar.ChatRenamedSuccessfully"));
8627
+ toast.success(t("BiChat.Sidebar.ChatRenamedSuccessfully"));
8261
8628
  setRefreshKey((k) => k + 1);
8262
8629
  } catch (err) {
8263
8630
  console.error("Failed to update session title:", err);
8264
- toast.error(t("Sidebar.FailedToRenameChat"));
8631
+ toast.error(t("BiChat.Sidebar.FailedToRenameChat"));
8265
8632
  }
8266
8633
  };
8267
8634
  const filteredSessions = useMemo(() => {
@@ -8289,10 +8656,10 @@ function ArchivedChatList({
8289
8656
  {
8290
8657
  onClick: onBack,
8291
8658
  className: "inline-flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-600 dark:text-gray-400",
8292
- "aria-label": t("Archived.BackToChats"),
8659
+ "aria-label": t("BiChat.Archived.BackToChats"),
8293
8660
  children: [
8294
8661
  /* @__PURE__ */ jsx(ArrowLeft, { size: 20, className: "w-5 h-5" }),
8295
- t("Common.Back")
8662
+ t("BiChat.Common.Back")
8296
8663
  ]
8297
8664
  }
8298
8665
  ) }),
@@ -8304,14 +8671,14 @@ function ArchivedChatList({
8304
8671
  className: "w-6 h-6 text-gray-600 dark:text-gray-400"
8305
8672
  }
8306
8673
  ),
8307
- /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("Archived.Title") })
8674
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("BiChat.Archived.Title") })
8308
8675
  ] }),
8309
8676
  /* @__PURE__ */ jsx(
8310
8677
  SearchInput_default,
8311
8678
  {
8312
8679
  value: searchQuery,
8313
8680
  onChange: setSearchQuery,
8314
- placeholder: t("Archived.SearchArchivedChats")
8681
+ placeholder: t("BiChat.Archived.SearchArchivedChats")
8315
8682
  }
8316
8683
  )
8317
8684
  ] }),
@@ -8325,8 +8692,8 @@ function ArchivedChatList({
8325
8692
  className: "text-gray-400 dark:text-gray-500"
8326
8693
  }
8327
8694
  ),
8328
- title: t("Archived.NoArchivedChats"),
8329
- description: t("Archived.NoArchivedChatsDescription")
8695
+ title: t("BiChat.Archived.NoArchivedChats"),
8696
+ description: t("BiChat.Archived.NoArchivedChatsDescription")
8330
8697
  }
8331
8698
  ) }) : isEmptyAfterSearch ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full px-6", children: /* @__PURE__ */ jsx(
8332
8699
  MemoizedEmptyState,
@@ -8338,8 +8705,8 @@ function ArchivedChatList({
8338
8705
  className: "text-gray-400 dark:text-gray-500"
8339
8706
  }
8340
8707
  ),
8341
- title: t("Archived.NoResults"),
8342
- description: t("Archived.NoResultsDescription", {
8708
+ title: t("BiChat.Archived.NoResults"),
8709
+ description: t("BiChat.Archived.NoResultsDescription", {
8343
8710
  query: searchQuery
8344
8711
  })
8345
8712
  }
@@ -8377,10 +8744,10 @@ function ArchivedChatList({
8377
8744
  ConfirmModal_default,
8378
8745
  {
8379
8746
  isOpen: showConfirm,
8380
- title: t("Archived.RestoreChat"),
8381
- message: t("Archived.RestoreChatMessage"),
8382
- confirmText: t("Archived.RestoreButton"),
8383
- cancelText: t("Common.Cancel"),
8747
+ title: t("BiChat.Archived.RestoreChat"),
8748
+ message: t("BiChat.Archived.RestoreChatMessage"),
8749
+ confirmText: t("BiChat.Archived.RestoreButton"),
8750
+ cancelText: t("BiChat.Common.Cancel"),
8384
8751
  isDanger: false,
8385
8752
  onConfirm: confirmRestore,
8386
8753
  onCancel: () => {
@@ -8394,6 +8761,231 @@ function ArchivedChatList({
8394
8761
  }
8395
8762
  );
8396
8763
  }
8764
+
8765
+ // ui/src/bichat/components/SkipLink.tsx
8766
+ init_useTranslation();
8767
+ function SkipLink() {
8768
+ const { t } = useTranslation();
8769
+ return /* @__PURE__ */ jsx(
8770
+ "a",
8771
+ {
8772
+ href: "#main-content",
8773
+ 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",
8774
+ children: t("BiChat.SkipLink.Label")
8775
+ }
8776
+ );
8777
+ }
8778
+ var MOBILE_QUERY = "(max-width: 767px)";
8779
+ function getIsMobile() {
8780
+ if (typeof window === "undefined") return false;
8781
+ return window.matchMedia(MOBILE_QUERY).matches;
8782
+ }
8783
+ function useSidebarState() {
8784
+ const [isMobile, setIsMobile] = useState(getIsMobile);
8785
+ const [isMobileOpen, setIsMobileOpen] = useState(false);
8786
+ useEffect(() => {
8787
+ if (typeof window === "undefined") return;
8788
+ const mql = window.matchMedia(MOBILE_QUERY);
8789
+ const handler = (e) => {
8790
+ setIsMobile(e.matches);
8791
+ if (!e.matches) setIsMobileOpen(false);
8792
+ };
8793
+ if (mql.addEventListener) {
8794
+ mql.addEventListener("change", handler);
8795
+ } else if (mql.addListener) {
8796
+ mql.addListener(handler);
8797
+ }
8798
+ return () => {
8799
+ if (mql.removeEventListener) {
8800
+ mql.removeEventListener("change", handler);
8801
+ } else if (mql.removeListener) {
8802
+ mql.removeListener(handler);
8803
+ }
8804
+ };
8805
+ }, []);
8806
+ const openMobile = useCallback(() => setIsMobileOpen(true), []);
8807
+ const closeMobile = useCallback(() => setIsMobileOpen(false), []);
8808
+ const toggleMobile = useCallback(() => setIsMobileOpen((v) => !v), []);
8809
+ return { isMobile, isMobileOpen, openMobile, closeMobile, toggleMobile };
8810
+ }
8811
+ function useFocusTrap(containerRef, isActive, restoreFocusOnDeactivate) {
8812
+ useEffect(() => {
8813
+ if (!isActive || !containerRef.current) return;
8814
+ const container = containerRef.current;
8815
+ const previouslyFocused = document.activeElement;
8816
+ const getFocusableElements = () => {
8817
+ const selector = [
8818
+ "button:not([disabled])",
8819
+ "[href]",
8820
+ "input:not([disabled])",
8821
+ "select:not([disabled])",
8822
+ "textarea:not([disabled])",
8823
+ '[tabindex]:not([tabindex="-1"])'
8824
+ ].join(", ");
8825
+ return Array.from(container.querySelectorAll(selector));
8826
+ };
8827
+ const focusableElements = getFocusableElements();
8828
+ if (focusableElements.length > 0) {
8829
+ focusableElements[0].focus();
8830
+ }
8831
+ const handleTabKey = (e) => {
8832
+ if (e.key !== "Tab") return;
8833
+ const focusableElements2 = getFocusableElements();
8834
+ if (focusableElements2.length === 0) return;
8835
+ const firstElement = focusableElements2[0];
8836
+ const lastElement = focusableElements2[focusableElements2.length - 1];
8837
+ if (e.shiftKey) {
8838
+ if (document.activeElement === firstElement) {
8839
+ e.preventDefault();
8840
+ lastElement.focus();
8841
+ }
8842
+ } else {
8843
+ if (document.activeElement === lastElement) {
8844
+ e.preventDefault();
8845
+ firstElement.focus();
8846
+ }
8847
+ }
8848
+ };
8849
+ container.addEventListener("keydown", handleTabKey);
8850
+ return () => {
8851
+ container.removeEventListener("keydown", handleTabKey);
8852
+ if (restoreFocusOnDeactivate) {
8853
+ restoreFocusOnDeactivate.focus();
8854
+ } else if (previouslyFocused instanceof HTMLElement) {
8855
+ previouslyFocused.focus();
8856
+ }
8857
+ };
8858
+ }, [containerRef, isActive, restoreFocusOnDeactivate]);
8859
+ }
8860
+ function useKeyboardShortcuts(shortcuts) {
8861
+ useEffect(() => {
8862
+ const handleKeyDown = (e) => {
8863
+ const target = e.target;
8864
+ if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target.isContentEditable) {
8865
+ const allowInInput = shortcuts.find(
8866
+ (s) => s.key.toLowerCase() === e.key.toLowerCase() && s.key.toLowerCase() === "escape"
8867
+ );
8868
+ if (!allowInInput) {
8869
+ return;
8870
+ }
8871
+ }
8872
+ const matchingShortcut = shortcuts.find((s) => {
8873
+ const keyMatches = e.key.toLowerCase() === s.key.toLowerCase();
8874
+ const modMatches = s.meta ? e.metaKey && !e.ctrlKey : s.ctrl ? e.ctrlKey || e.metaKey : !e.ctrlKey && !e.metaKey;
8875
+ const shiftMatches = s.shift ? e.shiftKey : !e.shiftKey;
8876
+ const altMatches = s.alt ? e.altKey : !e.altKey;
8877
+ return keyMatches && modMatches && shiftMatches && altMatches;
8878
+ });
8879
+ if (matchingShortcut) {
8880
+ if (matchingShortcut.preventDefault !== false) {
8881
+ e.preventDefault();
8882
+ }
8883
+ matchingShortcut.callback();
8884
+ }
8885
+ };
8886
+ document.addEventListener("keydown", handleKeyDown);
8887
+ return () => document.removeEventListener("keydown", handleKeyDown);
8888
+ }, [shortcuts]);
8889
+ }
8890
+
8891
+ // ui/src/bichat/components/BiChatLayout.tsx
8892
+ init_useTranslation();
8893
+ function BiChatLayout({
8894
+ renderSidebar,
8895
+ children,
8896
+ onNewChat,
8897
+ routeKey,
8898
+ className = ""
8899
+ }) {
8900
+ const { t } = useTranslation();
8901
+ const { isMobile, isMobileOpen, openMobile, closeMobile } = useSidebarState();
8902
+ const drawerRef = useRef(null);
8903
+ const menuButtonRef = useRef(null);
8904
+ useFocusTrap(drawerRef, isMobile && isMobileOpen, menuButtonRef.current);
8905
+ const shortcuts = useMemo(() => {
8906
+ if (!onNewChat) return [];
8907
+ return [{ key: "n", ctrl: true, callback: onNewChat, description: "New chat" }];
8908
+ }, [onNewChat]);
8909
+ useKeyboardShortcuts(shortcuts);
8910
+ useEffect(() => {
8911
+ if (!isMobile || !isMobileOpen) return;
8912
+ const onKeyDown = (e) => {
8913
+ if (e.key === "Escape") {
8914
+ e.preventDefault();
8915
+ closeMobile();
8916
+ }
8917
+ };
8918
+ document.addEventListener("keydown", onKeyDown);
8919
+ return () => document.removeEventListener("keydown", onKeyDown);
8920
+ }, [closeMobile, isMobile, isMobileOpen]);
8921
+ const handleDrawerDragEnd = (_, info) => {
8922
+ if (info.offset.x < -80) {
8923
+ closeMobile();
8924
+ }
8925
+ };
8926
+ const content = routeKey ? /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: /* @__PURE__ */ jsx(
8927
+ motion.div,
8928
+ {
8929
+ className: "flex flex-1 min-h-0",
8930
+ initial: { opacity: 0, y: 4 },
8931
+ animate: { opacity: 1, y: 0 },
8932
+ exit: { opacity: 0, y: -4 },
8933
+ transition: { duration: 0.15, ease: "easeOut" },
8934
+ children
8935
+ },
8936
+ routeKey
8937
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 min-h-0", children });
8938
+ return /* @__PURE__ */ jsxs("div", { className: `relative flex flex-1 w-full h-full min-h-0 overflow-hidden ${className}`, children: [
8939
+ /* @__PURE__ */ jsx(SkipLink, {}),
8940
+ /* @__PURE__ */ jsx("div", { className: "hidden md:block", children: renderSidebar({}) }),
8941
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isMobile && isMobileOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
8942
+ /* @__PURE__ */ jsx(
8943
+ motion.div,
8944
+ {
8945
+ className: "fixed inset-0 z-40 bg-black/40",
8946
+ initial: { opacity: 0 },
8947
+ animate: { opacity: 1 },
8948
+ exit: { opacity: 0 },
8949
+ onClick: closeMobile,
8950
+ "aria-hidden": "true"
8951
+ },
8952
+ "sidebar-backdrop"
8953
+ ),
8954
+ /* @__PURE__ */ jsx(
8955
+ motion.div,
8956
+ {
8957
+ className: "fixed inset-y-0 left-0 z-50 w-[18rem] max-w-[85vw] shadow-2xl",
8958
+ initial: { x: "-100%" },
8959
+ animate: { x: 0 },
8960
+ exit: { x: "-100%" },
8961
+ transition: { type: "spring", stiffness: 320, damping: 32 },
8962
+ drag: "x",
8963
+ dragDirectionLock: true,
8964
+ dragConstraints: { left: -120, right: 0 },
8965
+ dragElastic: { left: 0.2, right: 0 },
8966
+ onDragEnd: handleDrawerDragEnd,
8967
+ onClick: (e) => e.stopPropagation(),
8968
+ children: /* @__PURE__ */ jsx("div", { ref: drawerRef, className: "h-full bg-white dark:bg-gray-900", children: renderSidebar({ onClose: closeMobile }) })
8969
+ },
8970
+ "sidebar-drawer"
8971
+ )
8972
+ ] }) }),
8973
+ /* @__PURE__ */ jsxs("main", { id: "main-content", className: "relative flex-1 flex flex-col min-h-0 overflow-hidden", children: [
8974
+ isMobile && !isMobileOpen && /* @__PURE__ */ jsx(
8975
+ "button",
8976
+ {
8977
+ ref: menuButtonRef,
8978
+ onClick: openMobile,
8979
+ 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",
8980
+ "aria-label": t("BiChat.Layout.OpenSidebar"),
8981
+ title: t("BiChat.Layout.OpenSidebar"),
8982
+ children: /* @__PURE__ */ jsx(List, { size: 20, weight: "bold" })
8983
+ }
8984
+ ),
8985
+ content
8986
+ ] })
8987
+ ] });
8988
+ }
8397
8989
  init_useTranslation();
8398
8990
  var variantStyles = {
8399
8991
  error: {
@@ -8466,7 +9058,7 @@ function Alert({
8466
9058
  {
8467
9059
  onClick: onRetry,
8468
9060
  className: `mt-2 text-xs px-3 py-1.5 rounded ${styles.retryButton} transition-colors font-medium`,
8469
- children: t("Chat.Retry")
9061
+ children: t("BiChat.Chat.Retry")
8470
9062
  }
8471
9063
  )
8472
9064
  ] })
@@ -8476,7 +9068,7 @@ function Alert({
8476
9068
  {
8477
9069
  onClick: onDismiss,
8478
9070
  className: `${styles.button} transition-colors flex-shrink-0`,
8479
- "aria-label": t("Chat.DismissNotification"),
9071
+ "aria-label": t("BiChat.Chat.DismissNotification"),
8480
9072
  children: /* @__PURE__ */ jsx(X, { size: 20, className: "w-5 h-5" })
8481
9073
  }
8482
9074
  )
@@ -8485,12 +9077,14 @@ function Alert({
8485
9077
  ) });
8486
9078
  }
8487
9079
  var Alert_default = memo(Alert);
9080
+ init_useTranslation();
8488
9081
  function ArchiveBanner({
8489
9082
  show = true,
8490
9083
  onRestore,
8491
9084
  restoring = false,
8492
9085
  onRestoreComplete
8493
9086
  }) {
9087
+ const { t } = useTranslation();
8494
9088
  const [error, setError] = useState(null);
8495
9089
  const handleRestore = async () => {
8496
9090
  try {
@@ -8502,7 +9096,7 @@ function ArchiveBanner({
8502
9096
  onRestoreComplete();
8503
9097
  }
8504
9098
  } catch (err) {
8505
- const message = err instanceof Error ? err.message : "Failed to restore session";
9099
+ const message = err instanceof Error ? err.message : t("BiChat.Archive.RestoreFailed");
8506
9100
  setError(message);
8507
9101
  }
8508
9102
  };
@@ -8516,11 +9110,11 @@ function ArchiveBanner({
8516
9110
  exit: "exit",
8517
9111
  className: "border-t border border-blue-200 bg-blue-50 dark:bg-blue-900/20 px-4 py-3",
8518
9112
  role: "region",
8519
- "aria-label": "Archive banner",
9113
+ "aria-label": t("BiChat.Archive.Banner"),
8520
9114
  children: /* @__PURE__ */ jsxs("div", { className: "w-full flex items-start justify-between px-4", children: [
8521
9115
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 flex-1", children: [
8522
9116
  /* @__PURE__ */ jsx(Archive, { size: 20, className: "w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" }),
8523
- /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-blue-700 dark:text-blue-400", children: "This chat session has been archived" }) })
9117
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-blue-700 dark:text-blue-400", children: t("BiChat.Archive.Archived") }) })
8524
9118
  ] }),
8525
9119
  /* @__PURE__ */ jsx(
8526
9120
  "button",
@@ -8528,11 +9122,11 @@ function ArchiveBanner({
8528
9122
  onClick: handleRestore,
8529
9123
  disabled: restoring,
8530
9124
  className: "ml-2 flex-shrink-0 px-3 py-1.5 text-xs font-medium bg-blue-600 dark:bg-blue-700 hover:bg-blue-700 dark:hover:bg-blue-800 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-1.5",
8531
- "aria-label": "Restore session",
9125
+ "aria-label": t("BiChat.Archive.Restore"),
8532
9126
  children: restoring ? /* @__PURE__ */ jsxs(Fragment, { children: [
8533
9127
  /* @__PURE__ */ jsx(Spinner, { size: 16, className: "w-4 h-4 animate-spin" }),
8534
- "Restoring..."
8535
- ] }) : "Restore"
9128
+ t("BiChat.Archive.Restoring")
9129
+ ] }) : t("BiChat.Archive.Restore")
8536
9130
  }
8537
9131
  )
8538
9132
  ] })
@@ -8543,7 +9137,7 @@ function ArchiveBanner({
8543
9137
  {
8544
9138
  variant: "error",
8545
9139
  message: error,
8546
- title: "Restore Failed",
9140
+ title: t("BiChat.Archive.RestoreFailed"),
8547
9141
  onDismiss: () => setError(null),
8548
9142
  dismissible: true
8549
9143
  }
@@ -8583,17 +9177,17 @@ var RetryActionArea = memo(function RetryActionArea2({
8583
9177
  weight: "fill"
8584
9178
  }
8585
9179
  ),
8586
- /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("Retry.Description") })
9180
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("BiChat.Retry.Subtitle") })
8587
9181
  ] }),
8588
9182
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs(
8589
9183
  "button",
8590
9184
  {
8591
9185
  onClick: onRetry,
8592
9186
  className: "cursor-pointer inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 dark:bg-primary-700 dark:hover:bg-primary-600 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
8593
- "aria-label": t("Retry.Title"),
9187
+ "aria-label": t("BiChat.Retry.Title"),
8594
9188
  children: [
8595
9189
  /* @__PURE__ */ jsx(ArrowClockwise, { size: 16, className: "w-4 h-4" }),
8596
- t("Retry.Button")
9190
+ t("BiChat.Retry.Button")
8597
9191
  ]
8598
9192
  }
8599
9193
  ) })
@@ -8631,7 +9225,7 @@ function StreamError({
8631
9225
  }
8632
9226
  ),
8633
9227
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
8634
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200", children: t("Error.Generic") }),
9228
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200", children: t("BiChat.Error.Generic") }),
8635
9229
  /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600 dark:text-red-300 break-words", children: error })
8636
9230
  ] }),
8637
9231
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
@@ -8643,7 +9237,7 @@ function StreamError({
8643
9237
  type: "button",
8644
9238
  children: [
8645
9239
  /* @__PURE__ */ jsx(ArrowClockwise, { className: "w-4 h-4" }),
8646
- t("streamError.retry")
9240
+ t("BiChat.StreamError.Retry")
8647
9241
  ]
8648
9242
  }
8649
9243
  ),
@@ -8655,7 +9249,7 @@ function StreamError({
8655
9249
  type: "button",
8656
9250
  children: [
8657
9251
  /* @__PURE__ */ jsx(ArrowsCounterClockwise, { className: "w-4 h-4" }),
8658
- t("streamError.regenerate")
9252
+ t("BiChat.StreamError.Regenerate")
8659
9253
  ]
8660
9254
  }
8661
9255
  )
@@ -8664,6 +9258,7 @@ function StreamError({
8664
9258
  }
8665
9259
  );
8666
9260
  }
9261
+ init_useTranslation();
8667
9262
  function MessageActions({
8668
9263
  message,
8669
9264
  onCopy,
@@ -8673,14 +9268,15 @@ function MessageActions({
8673
9268
  const [copying, setCopying] = useState(false);
8674
9269
  const [regenerating, setRegenerating] = useState(false);
8675
9270
  const toast = useToast();
9271
+ const { t } = useTranslation();
8676
9272
  const isUser = message.role === "user" /* User */;
8677
9273
  const handleCopy = async () => {
8678
9274
  setCopying(true);
8679
9275
  try {
8680
9276
  await onCopy(message.content);
8681
- toast.success("Copied to clipboard");
9277
+ toast.success(t("BiChat.Message.CopiedToClipboard"));
8682
9278
  } catch {
8683
- toast.error("Failed to copy message");
9279
+ toast.error(t("BiChat.Message.FailedToCopy"));
8684
9280
  } finally {
8685
9281
  setCopying(false);
8686
9282
  }
@@ -8700,9 +9296,9 @@ function MessageActions({
8700
9296
  {
8701
9297
  onClick: handleCopy,
8702
9298
  disabled: copying,
8703
- title: copying ? "Copying..." : "Copy message (Cmd/Ctrl+C on selection)",
9299
+ title: copying ? t("BiChat.Message.Copying") : t("BiChat.Message.CopyMessage"),
8704
9300
  className: "cursor-pointer text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-300 rounded-md transition-colors disabled:opacity-50 p-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
8705
- "aria-label": copying ? "Copying message" : "Copy message",
9301
+ "aria-label": copying ? t("BiChat.Message.Copying") : t("BiChat.Message.CopyMessage"),
8706
9302
  children: copying ? /* @__PURE__ */ jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }) : /* @__PURE__ */ jsx(Copy, { size: 16, className: "w-4 h-4" })
8707
9303
  }
8708
9304
  ),
@@ -8711,9 +9307,9 @@ function MessageActions({
8711
9307
  {
8712
9308
  onClick: handleRegenerate,
8713
9309
  disabled: regenerating,
8714
- title: regenerating ? "Regenerating..." : "Regenerate response",
9310
+ title: regenerating ? t("BiChat.Message.Regenerating") : t("BiChat.Message.Regenerate"),
8715
9311
  className: "cursor-pointer text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-300 rounded-md transition-colors disabled:opacity-50 p-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
8716
- "aria-label": regenerating ? "Regenerating response" : "Regenerate response",
9312
+ "aria-label": regenerating ? t("BiChat.Message.Regenerating") : t("BiChat.Message.Regenerate"),
8717
9313
  children: regenerating ? /* @__PURE__ */ jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }) : /* @__PURE__ */ jsx(ArrowClockwise, { size: 16, className: "w-4 h-4" })
8718
9314
  }
8719
9315
  ),
@@ -8721,16 +9317,18 @@ function MessageActions({
8721
9317
  "button",
8722
9318
  {
8723
9319
  onClick: () => onEdit(message),
8724
- title: "Edit message",
9320
+ title: t("BiChat.Message.EditMessage"),
8725
9321
  className: "cursor-pointer text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-300 rounded-md transition-colors p-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
8726
- "aria-label": "Edit message",
9322
+ "aria-label": t("BiChat.Message.EditMessage"),
8727
9323
  children: /* @__PURE__ */ jsx(PencilSimple, { size: 16, className: "w-4 h-4" })
8728
9324
  }
8729
9325
  )
8730
9326
  ] });
8731
9327
  }
8732
9328
  memo(MessageActions);
9329
+ init_useTranslation();
8733
9330
  var AttachmentPreview = memo(({ attachment, onRemove, onClick, readonly = false }) => {
9331
+ const { t } = useTranslation();
8734
9332
  const [isImageLoaded, setIsImageLoaded] = useState(false);
8735
9333
  const [imageError, setImageError] = useState(false);
8736
9334
  const previewUrl = attachment.preview || createDataUrl(attachment.base64Data, attachment.mimeType);
@@ -8762,7 +9360,7 @@ var AttachmentPreview = memo(({ attachment, onRemove, onClick, readonly = false
8762
9360
  children: [
8763
9361
  /* @__PURE__ */ jsxs("div", { className: "relative mb-2 overflow-hidden rounded-md bg-gray-100 dark:bg-gray-700 aspect-square", children: [
8764
9362
  !isImageLoaded && !imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 animate-pulse bg-gray-200 dark:bg-gray-600" }),
8765
- imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-gray-100 dark:bg-gray-700", children: /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Preview unavailable" }) }),
9363
+ imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-gray-100 dark:bg-gray-700", children: /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Attachment.PreviewUnavailable") }) }),
8766
9364
  /* @__PURE__ */ jsx(
8767
9365
  "img",
8768
9366
  {
@@ -8798,7 +9396,7 @@ var AttachmentPreview = memo(({ attachment, onRemove, onClick, readonly = false
8798
9396
  },
8799
9397
  className: "absolute top-1 right-1 flex items-center justify-center bg-red-500 hover:bg-red-600 dark:bg-red-600 dark:hover:bg-red-700 text-white rounded-full transition-all duration-200 shadow-sm hover:shadow-md active:scale-90 w-6 h-6",
8800
9398
  "aria-label": `Remove ${attachment.filename}`,
8801
- title: "Remove attachment",
9399
+ title: t("BiChat.Attachment.Remove"),
8802
9400
  children: /* @__PURE__ */ jsx(X, { size: 14, className: "w-3.5 h-3.5", weight: "bold" })
8803
9401
  }
8804
9402
  )
@@ -8827,7 +9425,7 @@ var AttachmentUpload = memo(
8827
9425
  setIsLoading(true);
8828
9426
  try {
8829
9427
  if (files.length > maxAttachments) {
8830
- toast.error(t("Error.MaxFiles", { max: maxAttachments, selected: files.length }));
9428
+ toast.error(t("BiChat.Error.MaxFiles", { max: maxAttachments, selected: files.length }));
8831
9429
  setIsLoading(false);
8832
9430
  return;
8833
9431
  }
@@ -8867,10 +9465,10 @@ var AttachmentUpload = memo(
8867
9465
  }
8868
9466
  if (attachments.length > 0) {
8869
9467
  onAttachmentsSelected(attachments);
8870
- const message = attachments.length === 1 ? t("Attachment.FileAdded", { size: formatFileSize(attachments[0].sizeBytes) }) : t("Attachment.FileAdded", { size: `${attachments.length} files` });
9468
+ const message = attachments.length === 1 ? t("BiChat.Attachment.FileAdded", { size: formatFileSize(attachments[0].sizeBytes) }) : t("BiChat.Attachment.FileAdded", { size: `${attachments.length} files` });
8871
9469
  toast.success(message);
8872
9470
  } else if (errors.length > 0) {
8873
- toast.error(t("Attachment.InvalidFile"));
9471
+ toast.error(t("BiChat.Attachment.InvalidFile"));
8874
9472
  }
8875
9473
  } finally {
8876
9474
  setIsLoading(false);
@@ -8893,7 +9491,7 @@ var AttachmentUpload = memo(
8893
9491
  onChange: handleFileSelect,
8894
9492
  disabled: isDisabled,
8895
9493
  className: "sr-only",
8896
- "aria-label": t("Attachment.SelectFiles")
9494
+ "aria-label": t("BiChat.Attachment.SelectFiles")
8897
9495
  }
8898
9496
  ),
8899
9497
  /* @__PURE__ */ jsx(
@@ -8903,7 +9501,7 @@ var AttachmentUpload = memo(
8903
9501
  onClick: handleClick,
8904
9502
  disabled: isDisabled,
8905
9503
  className: "\n flex items-center justify-center\n w-8 h-8\n text-gray-600 dark:text-gray-400\n hover:text-gray-800 dark:hover:text-gray-200\n hover:bg-gray-100 dark:hover:bg-gray-700\n disabled:text-gray-400 dark:disabled:text-gray-600\n disabled:opacity-50 disabled:cursor-not-allowed\n rounded-lg\n transition-all\n duration-200\n active:scale-95\n focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50\n ",
8906
- "aria-label": t("Attachment.SelectFiles"),
9504
+ "aria-label": t("BiChat.Attachment.SelectFiles"),
8907
9505
  "aria-busy": isLoading,
8908
9506
  children: isLoading ? /* @__PURE__ */ jsx(CircleNotch, { size: 20, className: "w-5 h-5 animate-spin", weight: "fill" }) : /* @__PURE__ */ jsx(Paperclip, { size: 20, className: "w-5 h-5", weight: "fill" })
8909
9507
  }
@@ -8941,20 +9539,6 @@ function ScreenReaderAnnouncer({
8941
9539
  );
8942
9540
  }
8943
9541
 
8944
- // ui/src/bichat/components/SkipLink.tsx
8945
- init_useTranslation();
8946
- function SkipLink() {
8947
- const { t } = useTranslation();
8948
- return /* @__PURE__ */ jsx(
8949
- "a",
8950
- {
8951
- href: "#main-content",
8952
- 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",
8953
- children: t("skipLink.label")
8954
- }
8955
- );
8956
- }
8957
-
8958
9542
  // ui/src/bichat/components/QuestionForm.tsx
8959
9543
  init_useTranslation();
8960
9544
 
@@ -8991,7 +9575,7 @@ function QuestionStep({
8991
9575
  };
8992
9576
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
8993
9577
  /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white mb-2", children: question.text }) }),
8994
- isMultiSelect && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 italic", children: t("Question.SelectMulti") }),
9578
+ isMultiSelect && /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 italic", children: t("BiChat.Question.SelectMulti") }),
8995
9579
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: (question.options || []).map((option) => {
8996
9580
  const isSelected = selectedOptions.includes(option.label);
8997
9581
  return /* @__PURE__ */ jsx(
@@ -9031,7 +9615,7 @@ function QuestionStep({
9031
9615
  }) }),
9032
9616
  /* @__PURE__ */ jsxs("div", { children: [
9033
9617
  /* @__PURE__ */ jsxs("label", { htmlFor: "other-input", className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: [
9034
- t("Question.SpecifyOther"),
9618
+ t("BiChat.Question.SpecifyOther"),
9035
9619
  ":"
9036
9620
  ] }),
9037
9621
  /* @__PURE__ */ jsx(
@@ -9040,7 +9624,7 @@ function QuestionStep({
9040
9624
  id: "other-input",
9041
9625
  value: otherText,
9042
9626
  onChange: (e) => handleOtherTextChange(e.target.value),
9043
- placeholder: t("Question.Other"),
9627
+ placeholder: t("BiChat.Question.OtherOption"),
9044
9628
  rows: 3,
9045
9629
  className: "w-full px-4 py-3 border-2 border-gray-200 dark:border-gray-700 rounded-lg\n bg-white dark:bg-gray-800 text-gray-900 dark:text-white\n placeholder-gray-400 dark:placeholder-gray-500\n focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500\n resize-none"
9046
9630
  }
@@ -9058,8 +9642,8 @@ function ConfirmationStep({
9058
9642
  const { t } = useTranslation();
9059
9643
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
9060
9644
  /* @__PURE__ */ jsxs("div", { children: [
9061
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t("questionForm.reviewTitle") }),
9062
- /* @__PURE__ */ jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-1", children: t("questionForm.reviewDescription") })
9645
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t("BiChat.QuestionForm.ReviewTitle") }),
9646
+ /* @__PURE__ */ jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-1", children: t("BiChat.QuestionForm.ReviewDescription") })
9063
9647
  ] }),
9064
9648
  /* @__PURE__ */ jsx("div", { className: "space-y-4", children: questions.map((question) => {
9065
9649
  const answerData = answers[question.id] || { options: [] };
@@ -9083,12 +9667,12 @@ function ConfirmationStep({
9083
9667
  )),
9084
9668
  customText && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center px-3 py-1 rounded-lg text-sm font-medium border border-amber-500 bg-amber-500/10 text-amber-600 dark:border-amber-400 dark:bg-amber-400/10 dark:text-amber-400", children: [
9085
9669
  /* @__PURE__ */ jsxs("span", { className: "font-semibold mr-1", children: [
9086
- t("Question.Other"),
9670
+ t("BiChat.Question.OtherOption"),
9087
9671
  ":"
9088
9672
  ] }),
9089
9673
  /* @__PURE__ */ jsx("span", { className: "italic", children: customText })
9090
9674
  ] })
9091
- ] }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-400 dark:text-gray-500 italic", children: t("questionForm.skip") })
9675
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-400 dark:text-gray-500 italic", children: t("BiChat.QuestionForm.Skip") })
9092
9676
  ]
9093
9677
  },
9094
9678
  question.id
@@ -9105,12 +9689,12 @@ function isQuestionAnswered(data) {
9105
9689
  function validateAnswers(questions, answers, t) {
9106
9690
  const allAnswered = questions.every((q) => isQuestionAnswered(answers[q.id]));
9107
9691
  if (!allAnswered) {
9108
- return t ? t("Error.AllQuestionsRequired") : "Please answer all questions before submitting";
9692
+ return t ? t("BiChat.Error.AllQuestionsRequired") : "Please answer all questions before submitting";
9109
9693
  }
9110
9694
  for (const q of questions) {
9111
9695
  const data = answers[q.id];
9112
9696
  if (data && (data.options?.length ?? 0) === 0 && data.customText === "") {
9113
- return t ? t("Error.CustomTextRequired", { question: q.text }) : `Please enter custom text for question: ${q.text}`;
9697
+ return t ? t("BiChat.Error.CustomTextRequired", { question: q.text }) : `Please enter custom text for question: ${q.text}`;
9114
9698
  }
9115
9699
  }
9116
9700
  return null;
@@ -9163,24 +9747,24 @@ function QuestionForm({
9163
9747
  try {
9164
9748
  await onSubmit(answers);
9165
9749
  } catch (err) {
9166
- const errorMessage = err instanceof Error ? err.message : t("Error.Generic");
9750
+ const errorMessage = err instanceof Error ? err.message : t("BiChat.Error.Generic");
9167
9751
  setError(errorMessage);
9168
9752
  setIsSubmitting(false);
9169
9753
  }
9170
9754
  };
9171
9755
  const totalSteps = questions.length + 1;
9172
- const progressText = isConfirmationStep ? t("questionForm.step", { current: totalSteps, total: totalSteps }) : t("questionForm.step", { current: currentStep + 1, total: totalSteps });
9756
+ const progressText = isConfirmationStep ? t("BiChat.QuestionForm.Step", { current: totalSteps, total: totalSteps }) : t("BiChat.QuestionForm.Step", { current: currentStep + 1, total: totalSteps });
9173
9757
  return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4", children: /* @__PURE__ */ jsxs("div", { className: "bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto", children: [
9174
9758
  /* @__PURE__ */ jsxs("div", { className: "border-b border-gray-200 dark:border-gray-700 p-6", children: [
9175
9759
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
9176
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("questionForm.title") }),
9760
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("BiChat.QuestionForm.Title") }),
9177
9761
  /* @__PURE__ */ jsx(
9178
9762
  "button",
9179
9763
  {
9180
9764
  onClick: onCancel,
9181
9765
  disabled: isSubmitting,
9182
9766
  className: "cursor-pointer text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 disabled:opacity-50",
9183
- "aria-label": t("Common.Close"),
9767
+ "aria-label": t("BiChat.Common.Close"),
9184
9768
  children: /* @__PURE__ */ jsx(X, { className: "w-6 h-6" })
9185
9769
  }
9186
9770
  )
@@ -9214,7 +9798,7 @@ function QuestionForm({
9214
9798
  onClick: handleBack,
9215
9799
  disabled: isSubmitting,
9216
9800
  className: "cursor-pointer px-6 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 font-medium transition-colors",
9217
- children: t("questionForm.back")
9801
+ children: t("BiChat.QuestionForm.Back")
9218
9802
  }
9219
9803
  ),
9220
9804
  /* @__PURE__ */ jsx("div", { className: "flex-1" }),
@@ -9225,7 +9809,7 @@ function QuestionForm({
9225
9809
  onClick: onCancel,
9226
9810
  disabled: isSubmitting,
9227
9811
  className: "cursor-pointer px-6 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 font-medium transition-colors",
9228
- children: t("Message.Cancel")
9812
+ children: t("BiChat.Message.Cancel")
9229
9813
  }
9230
9814
  ),
9231
9815
  /* @__PURE__ */ jsxs(
@@ -9236,7 +9820,7 @@ function QuestionForm({
9236
9820
  className: "cursor-pointer px-6 py-2 bg-primary-600 hover:bg-primary-700 disabled:opacity-50 text-white rounded-lg font-medium transition-colors flex items-center gap-2",
9237
9821
  children: [
9238
9822
  isSubmitting && /* @__PURE__ */ jsx(MemoizedLoadingSpinner, { size: "sm" }),
9239
- isSubmitting ? t("questionForm.submitting") : t("questionForm.confirm")
9823
+ isSubmitting ? t("BiChat.QuestionForm.Submitting") : t("BiChat.QuestionForm.Confirm")
9240
9824
  ]
9241
9825
  }
9242
9826
  )
@@ -9248,7 +9832,7 @@ function QuestionForm({
9248
9832
  onClick: handleNext,
9249
9833
  disabled: !currentQuestionAnswered || isSubmitting,
9250
9834
  className: "cursor-pointer px-6 py-2 bg-primary-600 hover:bg-primary-700 disabled:opacity-50 text-white rounded-lg font-medium transition-colors",
9251
- children: t("questionForm.next")
9835
+ children: t("BiChat.QuestionForm.Next")
9252
9836
  }
9253
9837
  )
9254
9838
  )
@@ -9653,55 +10237,6 @@ function useModalLock(isOpen) {
9653
10237
  };
9654
10238
  }, [isOpen]);
9655
10239
  }
9656
- function useFocusTrap(containerRef, isActive, restoreFocusOnDeactivate) {
9657
- useEffect(() => {
9658
- if (!isActive || !containerRef.current) return;
9659
- const container = containerRef.current;
9660
- const previouslyFocused = document.activeElement;
9661
- const getFocusableElements = () => {
9662
- const selector = [
9663
- "button:not([disabled])",
9664
- "[href]",
9665
- "input:not([disabled])",
9666
- "select:not([disabled])",
9667
- "textarea:not([disabled])",
9668
- '[tabindex]:not([tabindex="-1"])'
9669
- ].join(", ");
9670
- return Array.from(container.querySelectorAll(selector));
9671
- };
9672
- const focusableElements = getFocusableElements();
9673
- if (focusableElements.length > 0) {
9674
- focusableElements[0].focus();
9675
- }
9676
- const handleTabKey = (e) => {
9677
- if (e.key !== "Tab") return;
9678
- const focusableElements2 = getFocusableElements();
9679
- if (focusableElements2.length === 0) return;
9680
- const firstElement = focusableElements2[0];
9681
- const lastElement = focusableElements2[focusableElements2.length - 1];
9682
- if (e.shiftKey) {
9683
- if (document.activeElement === firstElement) {
9684
- e.preventDefault();
9685
- lastElement.focus();
9686
- }
9687
- } else {
9688
- if (document.activeElement === lastElement) {
9689
- e.preventDefault();
9690
- firstElement.focus();
9691
- }
9692
- }
9693
- };
9694
- container.addEventListener("keydown", handleTabKey);
9695
- return () => {
9696
- container.removeEventListener("keydown", handleTabKey);
9697
- if (restoreFocusOnDeactivate) {
9698
- restoreFocusOnDeactivate.focus();
9699
- } else if (previouslyFocused instanceof HTMLElement) {
9700
- previouslyFocused.focus();
9701
- }
9702
- };
9703
- }, [containerRef, isActive, restoreFocusOnDeactivate]);
9704
- }
9705
10240
  function useImageGallery(options = {}) {
9706
10241
  const { images: initialImages = [], wrap = false, onOpen, onClose, onNavigate } = options;
9707
10242
  const [isOpen, setIsOpen] = useState(false);
@@ -10237,36 +10772,6 @@ function useScrollToBottom(items) {
10237
10772
  scrollToBottom
10238
10773
  };
10239
10774
  }
10240
- function useKeyboardShortcuts(shortcuts) {
10241
- useEffect(() => {
10242
- const handleKeyDown = (e) => {
10243
- const target = e.target;
10244
- if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target.isContentEditable) {
10245
- const allowInInput = shortcuts.find(
10246
- (s) => s.key.toLowerCase() === e.key.toLowerCase() && s.key.toLowerCase() === "escape"
10247
- );
10248
- if (!allowInInput) {
10249
- return;
10250
- }
10251
- }
10252
- const matchingShortcut = shortcuts.find((s) => {
10253
- const keyMatches = e.key.toLowerCase() === s.key.toLowerCase();
10254
- const modMatches = s.meta ? e.metaKey && !e.ctrlKey : s.ctrl ? e.ctrlKey || e.metaKey : !e.ctrlKey && !e.metaKey;
10255
- const shiftMatches = s.shift ? e.shiftKey : !e.shiftKey;
10256
- const altMatches = s.alt ? e.altKey : !e.altKey;
10257
- return keyMatches && modMatches && shiftMatches && altMatches;
10258
- });
10259
- if (matchingShortcut) {
10260
- if (matchingShortcut.preventDefault !== false) {
10261
- e.preventDefault();
10262
- }
10263
- matchingShortcut.callback();
10264
- }
10265
- };
10266
- document.addEventListener("keydown", handleKeyDown);
10267
- return () => document.removeEventListener("keydown", handleKeyDown);
10268
- }, [shortcuts]);
10269
- }
10270
10775
 
10271
10776
  // ui/src/bichat/index.ts
10272
10777
  init_IotaContext();
@@ -10721,12 +11226,63 @@ function toDownloadArtifact(artifact) {
10721
11226
  description: artifact.description
10722
11227
  };
10723
11228
  }
11229
+ function extractChartDataFromToolCalls(toolCalls) {
11230
+ if (!toolCalls) return void 0;
11231
+ for (const tc of toolCalls) {
11232
+ if (tc.name === "draw_chart" && tc.result) {
11233
+ const parsed = parseChartDataFromJsonString(tc.result);
11234
+ if (parsed) return parsed;
11235
+ }
11236
+ }
11237
+ return void 0;
11238
+ }
11239
+ var EXPORT_TOOL_NAMES = {
11240
+ export_query_to_excel: "excel",
11241
+ export_data_to_excel: "excel",
11242
+ export_to_pdf: "pdf"
11243
+ };
11244
+ function extractDownloadArtifactsFromToolCalls(toolCalls) {
11245
+ if (!toolCalls) return [];
11246
+ const artifacts = [];
11247
+ for (const tc of toolCalls) {
11248
+ const type = EXPORT_TOOL_NAMES[tc.name];
11249
+ if (!type || !tc.result) continue;
11250
+ let parsed;
11251
+ try {
11252
+ parsed = JSON.parse(tc.result);
11253
+ } catch {
11254
+ continue;
11255
+ }
11256
+ if (!isRecord(parsed) || typeof parsed.url !== "string" || !parsed.url) continue;
11257
+ const filename = typeof parsed.filename === "string" && parsed.filename ? parsed.filename : parsed.url.split("/").pop() || "download";
11258
+ const sizeKB = typeof parsed.file_size_kb === "number" ? parsed.file_size_kb : void 0;
11259
+ const sizeBytes = typeof parsed.size === "number" ? parsed.size : sizeKB != null ? sizeKB * 1024 : void 0;
11260
+ artifacts.push({
11261
+ type,
11262
+ filename,
11263
+ url: parsed.url,
11264
+ sizeReadable: sizeBytes != null ? formatSizeReadable(sizeBytes) : void 0,
11265
+ rowCount: parseRowCount(parsed),
11266
+ description: typeof parsed.description === "string" ? parsed.description : void 0
11267
+ });
11268
+ }
11269
+ return artifacts;
11270
+ }
10724
11271
  function normalizeAssistantTurn(turn) {
11272
+ const existingArtifacts = turn.artifacts || [];
11273
+ const fromToolCalls = extractDownloadArtifactsFromToolCalls(turn.toolCalls);
11274
+ const merged = [...existingArtifacts];
11275
+ for (const a of fromToolCalls) {
11276
+ if (!merged.some((e) => e.url === a.url && e.filename === a.filename)) {
11277
+ merged.push(a);
11278
+ }
11279
+ }
10725
11280
  return {
10726
11281
  ...turn,
10727
11282
  role: turn.role || "assistant" /* Assistant */,
11283
+ chartData: turn.chartData || extractChartDataFromToolCalls(turn.toolCalls),
10728
11284
  citations: turn.citations || [],
10729
- artifacts: turn.artifacts || [],
11285
+ artifacts: merged,
10730
11286
  codeOutputs: turn.codeOutputs || []
10731
11287
  };
10732
11288
  }
@@ -11125,6 +11681,6 @@ function createHttpDataSource(config) {
11125
11681
  return new HttpDataSource(config);
11126
11682
  }
11127
11683
 
11128
- export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, MemoizedTabBar as TabBar, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getValidChildren, groupSessionsByDate, hasPermission, isImageMimeType, lightTheme, listItemVariants, messageContainerVariants, messageVariants, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toastVariants, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useFocusTrap, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
11684
+ export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, BiChatLayout, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, MemoizedTabBar as TabBar, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getValidChildren, groupSessionsByDate, hasPermission, isImageMimeType, isPermissionDeniedError, lightTheme, listItemVariants, messageContainerVariants, messageVariants, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toErrorDisplay, toastVariants, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useFocusTrap, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useSidebarState, useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
11129
11685
  //# sourceMappingURL=index.mjs.map
11130
11686
  //# sourceMappingURL=index.mjs.map