@green-on-grey/ui-kit 0.2.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chat/AgentMenu.d.ts +36 -0
- package/dist/chat/index.d.ts +1 -0
- package/dist/chat.js +230 -158
- package/dist/chat.js.map +1 -1
- package/dist/locales/index.d.ts +5 -0
- package/dist/locales.js +5 -0
- package/dist/locales.js.map +1 -1
- package/dist/manifest.json +9 -1
- package/dist/styles.css +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ const resources = { en: { translation: en, uikit: kit.en }, ru: { translation: r
|
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
26
|
import { Avatar, Icon, Modal, ToastProvider, TopBar, useToast } from "@green-on-grey/ui-kit";
|
|
27
|
-
import { Chat, ChatLayout, ConversationList } from "@green-on-grey/ui-kit/chat";
|
|
27
|
+
import { AgentButton, AgentMenu, Chat, ChatLayout, ConversationList } from "@green-on-grey/ui-kit/chat";
|
|
28
28
|
import { LoginScreen } from "@green-on-grey/ui-kit/login";
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type IconName } from "../components/Icon";
|
|
3
|
+
/** One of the ways an agent can look and talk; what it means only the product knows (R7). */
|
|
4
|
+
export interface AgentOption {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
icon: IconName;
|
|
8
|
+
}
|
|
9
|
+
/** The round button of the agent: its icon, and the menu behind it. */
|
|
10
|
+
export declare function AgentButton({ icon, label, title, expanded, small, disabled, onClick }: {
|
|
11
|
+
icon: IconName;
|
|
12
|
+
label: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
expanded?: boolean;
|
|
15
|
+
small?: boolean;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
onClick?: () => void;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
/** The menu of the agent (FTR.NAB.CMN-0005 R15, design §6.6): its name and a
|
|
20
|
+
* choice among the options of the product, as tiles with icons. The name is
|
|
21
|
+
* saved on Enter and on leaving the field; a pick is saved at once. */
|
|
22
|
+
export declare function AgentMenu({ label, name, options, value, optionsLabel, hint, narrow, onRename, onPick, onClose }: {
|
|
23
|
+
/** The name of the dialog for a screen reader. */
|
|
24
|
+
label: string;
|
|
25
|
+
name: string;
|
|
26
|
+
options: AgentOption[];
|
|
27
|
+
value: string;
|
|
28
|
+
optionsLabel: ReactNode;
|
|
29
|
+
hint?: ReactNode;
|
|
30
|
+
/** A narrow place — a side panel: the options go in one column. */
|
|
31
|
+
narrow?: boolean;
|
|
32
|
+
onRename: (name: string) => void;
|
|
33
|
+
onPick: (key: string) => void;
|
|
34
|
+
/** Must keep its identity between renders. */
|
|
35
|
+
onClose: () => void;
|
|
36
|
+
}): import("react").JSX.Element;
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Chat } from "./Chat";
|
|
2
2
|
export { ChatLayout, ConversationList, NewTopicModal } from "./ConversationList";
|
|
3
|
+
export { AgentButton, AgentMenu, type AgentOption } from "./AgentMenu";
|
|
3
4
|
export { useRecorder } from "./useRecorder";
|
|
4
5
|
export type { ChatAttachment, ChatConfirmation, ChatConversation, ChatMark, ChatMessage, ChatProps, ChatStep, ChatUpload, ChatWait, ConversationListProps, } from "./types";
|
package/dist/chat.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { c as e, d as t, i as n, l as r } from "./ui-CGgZtEVm.js";
|
|
2
|
-
import { n as
|
|
3
|
-
import { Fragment as
|
|
4
|
-
import { useCallback as
|
|
5
|
-
import { useTranslation as
|
|
1
|
+
import { c as e, d as t, i as n, l as r, s as i } from "./ui-CGgZtEVm.js";
|
|
2
|
+
import { n as a, t as o } from "./i18n-BJ8rsBp6.js";
|
|
3
|
+
import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
4
|
+
import { useCallback as u, useEffect as d, useLayoutEffect as f, useRef as p, useState as m } from "react";
|
|
5
|
+
import { useTranslation as h } from "react-i18next";
|
|
6
6
|
//#region src/chat/MessageView.tsx
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
return new Intl.DateTimeFormat(
|
|
7
|
+
var g = (e) => e === "zh" ? "zh-CN" : e;
|
|
8
|
+
function _(e, t) {
|
|
9
|
+
return new Intl.DateTimeFormat(g(t), {
|
|
10
10
|
hour: "2-digit",
|
|
11
11
|
minute: "2-digit"
|
|
12
12
|
}).format(new Date(e));
|
|
13
13
|
}
|
|
14
|
-
function
|
|
14
|
+
function v(e, t) {
|
|
15
15
|
return t || e.length <= 3 ? e : e.slice(-2);
|
|
16
16
|
}
|
|
17
|
-
var
|
|
17
|
+
var y = {
|
|
18
18
|
done: {
|
|
19
19
|
icon: "check",
|
|
20
20
|
cls: "ok"
|
|
@@ -28,30 +28,30 @@ var v = {
|
|
|
28
28
|
cls: "run"
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
function
|
|
32
|
-
let { t:
|
|
33
|
-
if (e.role === "note") return /* @__PURE__ */
|
|
31
|
+
function b({ m: e, busy: n, onRetry: i }) {
|
|
32
|
+
let { t: a, i18n: u } = h(o), [d, f] = m(!1);
|
|
33
|
+
if (e.role === "note") return /* @__PURE__ */ c("div", {
|
|
34
34
|
className: "sysnote",
|
|
35
35
|
children: e.text
|
|
36
36
|
});
|
|
37
|
-
let
|
|
37
|
+
let p = e.mark && /* @__PURE__ */ l("div", {
|
|
38
38
|
className: "chan",
|
|
39
39
|
children: [
|
|
40
|
-
/* @__PURE__ */
|
|
40
|
+
/* @__PURE__ */ c(t, {
|
|
41
41
|
name: e.mark.icon,
|
|
42
42
|
size: 12
|
|
43
43
|
}),
|
|
44
44
|
" ",
|
|
45
45
|
e.mark.text,
|
|
46
46
|
" · ",
|
|
47
|
-
|
|
47
|
+
_(e.createdAt, u.language)
|
|
48
48
|
]
|
|
49
|
-
}),
|
|
49
|
+
}), g = e.attachments && e.attachments.length > 0 && /* @__PURE__ */ c("div", {
|
|
50
50
|
className: "atts",
|
|
51
|
-
children: e.attachments.map((e) => /* @__PURE__ */
|
|
51
|
+
children: e.attachments.map((e) => /* @__PURE__ */ l("a", {
|
|
52
52
|
href: e.href,
|
|
53
53
|
children: [
|
|
54
|
-
/* @__PURE__ */
|
|
54
|
+
/* @__PURE__ */ c(t, {
|
|
55
55
|
name: "clip",
|
|
56
56
|
size: 12
|
|
57
57
|
}),
|
|
@@ -60,83 +60,83 @@ function y({ m: e, busy: n, onRetry: i }) {
|
|
|
60
60
|
]
|
|
61
61
|
}, e.id))
|
|
62
62
|
});
|
|
63
|
-
if (e.role === "user") return /* @__PURE__ */
|
|
63
|
+
if (e.role === "user") return /* @__PURE__ */ l("div", {
|
|
64
64
|
className: "m u",
|
|
65
65
|
children: [
|
|
66
|
-
|
|
66
|
+
p,
|
|
67
67
|
e.content,
|
|
68
|
-
e.text && /* @__PURE__ */
|
|
68
|
+
e.text && /* @__PURE__ */ c("div", {
|
|
69
69
|
className: "bub",
|
|
70
70
|
children: e.text
|
|
71
71
|
}),
|
|
72
|
-
|
|
73
|
-
e.wait && /* @__PURE__ */
|
|
72
|
+
g,
|
|
73
|
+
e.wait && /* @__PURE__ */ c("div", {
|
|
74
74
|
className: `turnstate${e.wait.state === "queued" ? " q" : ""}`,
|
|
75
75
|
role: "status",
|
|
76
|
-
children: e.wait.state === "queued" ? /* @__PURE__ */
|
|
76
|
+
children: e.wait.state === "queued" ? /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c(t, {
|
|
77
77
|
name: "clock",
|
|
78
78
|
size: 12
|
|
79
|
-
}),
|
|
79
|
+
}), a("chat.wait.queued", { count: e.wait.position })] }) : /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("span", {
|
|
80
80
|
className: "spin",
|
|
81
81
|
"aria-hidden": "true"
|
|
82
|
-
}),
|
|
82
|
+
}), a("chat.wait.starting")] })
|
|
83
83
|
})
|
|
84
84
|
]
|
|
85
85
|
});
|
|
86
86
|
let b = e.steps ?? [], x = (e.status === "streaming" || e.status === "pending") && !e.text && !e.content;
|
|
87
|
-
return /* @__PURE__ */
|
|
87
|
+
return /* @__PURE__ */ l("div", {
|
|
88
88
|
className: "m a",
|
|
89
89
|
children: [
|
|
90
|
-
|
|
91
|
-
b.length > 3 && /* @__PURE__ */
|
|
90
|
+
p,
|
|
91
|
+
b.length > 3 && /* @__PURE__ */ c("button", {
|
|
92
92
|
className: "tools-fold",
|
|
93
93
|
onClick: () => f((e) => !e),
|
|
94
94
|
"aria-expanded": d,
|
|
95
|
-
children: d ?
|
|
95
|
+
children: d ? a("chat.hideSteps") : a("chat.moreSteps", { count: b.length - 2 })
|
|
96
96
|
}),
|
|
97
|
-
|
|
97
|
+
v(b, d).map((e) => /* @__PURE__ */ l("div", {
|
|
98
98
|
className: "tool",
|
|
99
99
|
title: e.title,
|
|
100
|
-
children: [/* @__PURE__ */
|
|
101
|
-
name:
|
|
100
|
+
children: [/* @__PURE__ */ c(t, {
|
|
101
|
+
name: y[e.status].icon,
|
|
102
102
|
size: 14,
|
|
103
|
-
className:
|
|
104
|
-
}), /* @__PURE__ */
|
|
103
|
+
className: y[e.status].cls
|
|
104
|
+
}), /* @__PURE__ */ c("span", {
|
|
105
105
|
className: "tx",
|
|
106
106
|
children: e.text
|
|
107
107
|
})]
|
|
108
108
|
}, e.id)),
|
|
109
|
-
x && /* @__PURE__ */
|
|
109
|
+
x && /* @__PURE__ */ c("div", {
|
|
110
110
|
className: "bub",
|
|
111
|
-
children: /* @__PURE__ */
|
|
111
|
+
children: /* @__PURE__ */ l("span", {
|
|
112
112
|
className: "typing",
|
|
113
|
-
"aria-label":
|
|
113
|
+
"aria-label": a("chat.typing"),
|
|
114
114
|
children: [
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ c("i", {}),
|
|
116
|
+
/* @__PURE__ */ c("i", {}),
|
|
117
|
+
/* @__PURE__ */ c("i", {})
|
|
118
118
|
]
|
|
119
119
|
})
|
|
120
120
|
}),
|
|
121
|
-
e.content ?? (e.text && /* @__PURE__ */
|
|
121
|
+
e.content ?? (e.text && /* @__PURE__ */ c("div", {
|
|
122
122
|
className: "bub",
|
|
123
|
-
children: /* @__PURE__ */
|
|
123
|
+
children: /* @__PURE__ */ c(r, { text: e.text })
|
|
124
124
|
})),
|
|
125
|
-
|
|
126
|
-
e.error && /* @__PURE__ */
|
|
125
|
+
g,
|
|
126
|
+
e.error && /* @__PURE__ */ l("div", {
|
|
127
127
|
className: `llmerr${e.error.transient ? " amber" : ""}`,
|
|
128
128
|
role: "alert",
|
|
129
129
|
style: { marginTop: 6 },
|
|
130
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ c("span", { children: e.error.text }), i && /* @__PURE__ */ c("div", {
|
|
131
131
|
className: "row",
|
|
132
|
-
children: /* @__PURE__ */
|
|
132
|
+
children: /* @__PURE__ */ l("button", {
|
|
133
133
|
className: "btn sm",
|
|
134
134
|
disabled: n,
|
|
135
135
|
onClick: i,
|
|
136
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ c(t, {
|
|
137
137
|
name: "refresh",
|
|
138
138
|
size: 14
|
|
139
|
-
}),
|
|
139
|
+
}), a("chat.retry")]
|
|
140
140
|
})
|
|
141
141
|
})]
|
|
142
142
|
})
|
|
@@ -145,30 +145,30 @@ function y({ m: e, busy: n, onRetry: i }) {
|
|
|
145
145
|
}
|
|
146
146
|
//#endregion
|
|
147
147
|
//#region src/chat/useRecorder.ts
|
|
148
|
-
function
|
|
149
|
-
let e = typeof window < "u" && "MediaRecorder" in window && !!navigator.mediaDevices?.getUserMedia, [t, n] =
|
|
150
|
-
window.clearInterval(
|
|
151
|
-
}, []), g =
|
|
148
|
+
function x() {
|
|
149
|
+
let e = typeof window < "u" && "MediaRecorder" in window && !!navigator.mediaDevices?.getUserMedia, [t, n] = m(!1), [r, i] = m(0), [a, o] = m(!1), s = p(null), c = p([]), l = p(void 0), f = p(null), h = u(() => {
|
|
150
|
+
window.clearInterval(l.current), s.current?.stream.getTracks().forEach((e) => e.stop()), s.current = null, n(!1);
|
|
151
|
+
}, []), g = u(async () => {
|
|
152
152
|
if (e && !s.current) {
|
|
153
153
|
o(!1);
|
|
154
154
|
try {
|
|
155
155
|
let e = await navigator.mediaDevices.getUserMedia({ audio: !0 }), t = new MediaRecorder(e);
|
|
156
156
|
c.current = [], t.ondataavailable = (e) => e.data.size > 0 && c.current.push(e.data), t.onstop = () => {
|
|
157
157
|
let e = c.current.length ? new Blob(c.current, { type: t.mimeType || "audio/webm" }) : null;
|
|
158
|
-
h(),
|
|
158
|
+
h(), f.current?.(e), f.current = null;
|
|
159
159
|
}, s.current = t, t.start(), i(0), n(!0);
|
|
160
160
|
let r = Date.now();
|
|
161
|
-
|
|
161
|
+
l.current = window.setInterval(() => i(Math.floor((Date.now() - r) / 1e3)), 250);
|
|
162
162
|
} catch {
|
|
163
163
|
o(!0), h();
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
-
}, [e, h]), _ =
|
|
166
|
+
}, [e, h]), _ = u(() => new Promise((e) => {
|
|
167
167
|
let t = s.current;
|
|
168
168
|
if (!t || t.state === "inactive") return e(null);
|
|
169
|
-
|
|
169
|
+
f.current = e, t.stop();
|
|
170
170
|
}), []);
|
|
171
|
-
return
|
|
171
|
+
return d(() => () => h(), [h]), {
|
|
172
172
|
supported: e,
|
|
173
173
|
recording: t,
|
|
174
174
|
seconds: `${Math.floor(r / 60)}:${String(r % 60).padStart(2, "0")}`,
|
|
@@ -179,9 +179,9 @@ function b() {
|
|
|
179
179
|
}
|
|
180
180
|
//#endregion
|
|
181
181
|
//#region src/chat/Chat.tsx
|
|
182
|
-
function
|
|
183
|
-
let r =
|
|
184
|
-
|
|
182
|
+
function S(n) {
|
|
183
|
+
let r = a(), i = e(), [o, u] = m(""), [d, h] = m([]), [g, _] = m(!1), [v, y] = m(null), S = p(null), C = p(null), w = x(), { messages: T, busy: E = !1 } = n, D = T[0]?.id, O = T[T.length - 1], k = O?.id, A = O?.text.length, j = O?.steps?.length, M = p({ height: 0 });
|
|
184
|
+
f(() => {
|
|
185
185
|
let e = S.current;
|
|
186
186
|
if (!e) return;
|
|
187
187
|
let t = M.current;
|
|
@@ -199,15 +199,15 @@ function x(n) {
|
|
|
199
199
|
]);
|
|
200
200
|
let N = async (e, t) => {
|
|
201
201
|
let r = e.trim();
|
|
202
|
-
if (!(!r &&
|
|
203
|
-
await n.onSend(r,
|
|
202
|
+
if (!(!r && d.length === 0 || E || n.readOnly)) try {
|
|
203
|
+
await n.onSend(r, d.map((e) => e.id), t), u(""), h([]), y(null);
|
|
204
204
|
} catch {}
|
|
205
205
|
}, P = async (e) => {
|
|
206
206
|
if (e?.length && n.onUpload) {
|
|
207
207
|
_(!0);
|
|
208
208
|
for (let t of Array.from(e)) {
|
|
209
209
|
if (n.upload && t.size > n.upload.maxBytes) {
|
|
210
|
-
|
|
210
|
+
i({
|
|
211
211
|
kind: "error",
|
|
212
212
|
title: r("chat.tooLarge"),
|
|
213
213
|
text: t.name
|
|
@@ -223,71 +223,71 @@ function x(n) {
|
|
|
223
223
|
let e = await w.stop();
|
|
224
224
|
if (!e || !n.onTranscribe) return;
|
|
225
225
|
let t = await n.onTranscribe(e).catch(() => null);
|
|
226
|
-
t !== null && (t ?
|
|
226
|
+
t !== null && (t ? y(t) : i({
|
|
227
227
|
kind: "error",
|
|
228
228
|
title: r("chat.voice.notRecognized")
|
|
229
229
|
}));
|
|
230
230
|
}, I = (e) => {
|
|
231
231
|
(e.key === " " || e.key === "Enter") && (e.preventDefault(), !e.repeat && (w.recording ? F() : w.start()));
|
|
232
232
|
}, L = r("chat.placeholder", { name: n.agentName });
|
|
233
|
-
return /* @__PURE__ */
|
|
233
|
+
return /* @__PURE__ */ l("section", {
|
|
234
234
|
className: "nb-chat",
|
|
235
235
|
"aria-label": r("chat.title"),
|
|
236
236
|
children: [
|
|
237
237
|
n.header,
|
|
238
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ l("div", {
|
|
239
239
|
className: "msgs",
|
|
240
240
|
ref: S,
|
|
241
241
|
"aria-live": "polite",
|
|
242
242
|
children: [
|
|
243
|
-
n.hasOlder && n.onLoadOlder && /* @__PURE__ */
|
|
243
|
+
n.hasOlder && n.onLoadOlder && /* @__PURE__ */ c("button", {
|
|
244
244
|
className: "btn ghost sm",
|
|
245
245
|
style: { alignSelf: "center" },
|
|
246
246
|
disabled: n.loadingOlder,
|
|
247
247
|
onClick: n.onLoadOlder,
|
|
248
248
|
children: r("chat.loadOlder")
|
|
249
249
|
}),
|
|
250
|
-
n.historyError && /* @__PURE__ */
|
|
250
|
+
n.historyError && /* @__PURE__ */ c("div", {
|
|
251
251
|
className: "err-text",
|
|
252
252
|
children: n.historyError
|
|
253
253
|
}),
|
|
254
|
-
T.length === 0 && !n.loading && !n.historyError && /* @__PURE__ */
|
|
254
|
+
T.length === 0 && !n.loading && !n.historyError && /* @__PURE__ */ l("div", {
|
|
255
255
|
className: "empty",
|
|
256
256
|
children: [
|
|
257
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ c("div", {
|
|
258
258
|
className: "ic",
|
|
259
|
-
children: /* @__PURE__ */
|
|
259
|
+
children: /* @__PURE__ */ c(t, { name: "spark" })
|
|
260
260
|
}),
|
|
261
|
-
/* @__PURE__ */
|
|
261
|
+
/* @__PURE__ */ c("b", { children: r("chat.emptyTitle", { name: n.agentName }) }),
|
|
262
262
|
n.emptyHint
|
|
263
263
|
]
|
|
264
264
|
}),
|
|
265
|
-
T.map((e) => /* @__PURE__ */
|
|
265
|
+
T.map((e) => /* @__PURE__ */ c(b, {
|
|
266
266
|
m: e,
|
|
267
267
|
busy: E,
|
|
268
268
|
onRetry: n.onRetry && (() => n.onRetry?.(e.id))
|
|
269
269
|
}, e.id)),
|
|
270
|
-
n.onConfirm && (n.confirmations ?? []).map((e) => /* @__PURE__ */
|
|
270
|
+
n.onConfirm && (n.confirmations ?? []).map((e) => /* @__PURE__ */ l("div", {
|
|
271
271
|
className: "confirm",
|
|
272
272
|
role: "group",
|
|
273
273
|
"aria-label": r("chat.confirm.title"),
|
|
274
274
|
children: [
|
|
275
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ l("div", {
|
|
276
276
|
className: "h",
|
|
277
|
-
children: [/* @__PURE__ */
|
|
277
|
+
children: [/* @__PURE__ */ c(t, {
|
|
278
278
|
name: "alert",
|
|
279
279
|
size: 16
|
|
280
280
|
}), r("chat.confirm.title")]
|
|
281
281
|
}),
|
|
282
|
-
/* @__PURE__ */
|
|
283
|
-
e.preview !== void 0 && /* @__PURE__ */
|
|
284
|
-
/* @__PURE__ */
|
|
282
|
+
/* @__PURE__ */ c("div", { children: r("chat.confirm.text", { action: e.summary }) }),
|
|
283
|
+
e.preview !== void 0 && /* @__PURE__ */ c("pre", { children: e.preview }),
|
|
284
|
+
/* @__PURE__ */ l("div", {
|
|
285
285
|
className: "acts",
|
|
286
|
-
children: [/* @__PURE__ */
|
|
286
|
+
children: [/* @__PURE__ */ c("button", {
|
|
287
287
|
className: "btn sm primary",
|
|
288
288
|
onClick: () => n.onConfirm?.(e.id, !0),
|
|
289
289
|
children: r("chat.confirm.approve")
|
|
290
|
-
}), /* @__PURE__ */
|
|
290
|
+
}), /* @__PURE__ */ c("button", {
|
|
291
291
|
className: "btn sm",
|
|
292
292
|
onClick: () => n.onConfirm?.(e.id, !1),
|
|
293
293
|
children: r("chat.confirm.reject")
|
|
@@ -297,26 +297,26 @@ function x(n) {
|
|
|
297
297
|
}, e.id))
|
|
298
298
|
]
|
|
299
299
|
}),
|
|
300
|
-
n.readOnly ? /* @__PURE__ */
|
|
300
|
+
n.readOnly ? /* @__PURE__ */ c("div", {
|
|
301
301
|
className: "composer",
|
|
302
302
|
style: {
|
|
303
303
|
justifyContent: "space-between",
|
|
304
304
|
alignItems: "center"
|
|
305
305
|
},
|
|
306
306
|
children: n.readOnly
|
|
307
|
-
}) : v === null ? /* @__PURE__ */
|
|
307
|
+
}) : v === null ? /* @__PURE__ */ l(s, { children: [
|
|
308
308
|
n.aboveComposer,
|
|
309
|
-
|
|
309
|
+
d.length > 0 && /* @__PURE__ */ c("div", {
|
|
310
310
|
className: "pending-files",
|
|
311
|
-
children:
|
|
311
|
+
children: d.map((e) => /* @__PURE__ */ l("span", {
|
|
312
312
|
className: "chip",
|
|
313
313
|
children: [
|
|
314
|
-
/* @__PURE__ */
|
|
314
|
+
/* @__PURE__ */ c(t, {
|
|
315
315
|
name: "clip",
|
|
316
316
|
size: 12
|
|
317
317
|
}),
|
|
318
318
|
e.fileName,
|
|
319
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ c("button", {
|
|
320
320
|
className: "iconbtn",
|
|
321
321
|
style: {
|
|
322
322
|
width: 18,
|
|
@@ -324,7 +324,7 @@ function x(n) {
|
|
|
324
324
|
},
|
|
325
325
|
"aria-label": r("remove"),
|
|
326
326
|
onClick: () => h((t) => t.filter((t) => t.id !== e.id)),
|
|
327
|
-
children: /* @__PURE__ */
|
|
327
|
+
children: /* @__PURE__ */ c(t, {
|
|
328
328
|
name: "x",
|
|
329
329
|
size: 12
|
|
330
330
|
})
|
|
@@ -332,16 +332,16 @@ function x(n) {
|
|
|
332
332
|
]
|
|
333
333
|
}, e.id))
|
|
334
334
|
}),
|
|
335
|
-
/* @__PURE__ */
|
|
335
|
+
/* @__PURE__ */ l("div", {
|
|
336
336
|
className: "composer",
|
|
337
337
|
children: [
|
|
338
|
-
n.onUpload && /* @__PURE__ */
|
|
338
|
+
n.onUpload && /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("button", {
|
|
339
339
|
className: "iconbtn",
|
|
340
340
|
"aria-label": r("chat.attach"),
|
|
341
341
|
disabled: g,
|
|
342
342
|
onClick: () => C.current?.click(),
|
|
343
|
-
children: /* @__PURE__ */
|
|
344
|
-
}), /* @__PURE__ */
|
|
343
|
+
children: /* @__PURE__ */ c(t, { name: "clip" })
|
|
344
|
+
}), /* @__PURE__ */ c("input", {
|
|
345
345
|
ref: C,
|
|
346
346
|
type: "file",
|
|
347
347
|
multiple: !0,
|
|
@@ -349,20 +349,20 @@ function x(n) {
|
|
|
349
349
|
accept: n.upload?.accept,
|
|
350
350
|
onChange: (e) => P(e.target.files)
|
|
351
351
|
})] }),
|
|
352
|
-
w.recording ? /* @__PURE__ */
|
|
352
|
+
w.recording ? /* @__PURE__ */ c("div", {
|
|
353
353
|
className: "rec-box",
|
|
354
354
|
children: r("chat.voice.recording", { seconds: w.seconds })
|
|
355
|
-
}) : /* @__PURE__ */
|
|
355
|
+
}) : /* @__PURE__ */ c("textarea", {
|
|
356
356
|
rows: 1,
|
|
357
|
-
value:
|
|
357
|
+
value: o,
|
|
358
358
|
placeholder: L,
|
|
359
359
|
"aria-label": L,
|
|
360
360
|
onChange: (e) => u(e.target.value),
|
|
361
361
|
onKeyDown: (e) => {
|
|
362
|
-
e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), N(
|
|
362
|
+
e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), N(o, !1));
|
|
363
363
|
}
|
|
364
364
|
}),
|
|
365
|
-
n.onTranscribe && /* @__PURE__ */
|
|
365
|
+
n.onTranscribe && /* @__PURE__ */ c("button", {
|
|
366
366
|
className: `iconbtn${w.recording ? " rec" : ""}`,
|
|
367
367
|
disabled: !w.supported,
|
|
368
368
|
"aria-label": w.recording ? r("chat.voice.stop") : r("chat.voice.hold"),
|
|
@@ -373,51 +373,51 @@ function x(n) {
|
|
|
373
373
|
onPointerUp: () => w.recording && F(),
|
|
374
374
|
onPointerLeave: () => w.recording && F(),
|
|
375
375
|
onKeyDown: I,
|
|
376
|
-
children: /* @__PURE__ */
|
|
376
|
+
children: /* @__PURE__ */ c(t, { name: "mic" })
|
|
377
377
|
}),
|
|
378
|
-
n.onCancel && E ? /* @__PURE__ */
|
|
378
|
+
n.onCancel && E ? /* @__PURE__ */ c("button", {
|
|
379
379
|
className: "iconbtn fill",
|
|
380
380
|
"aria-label": r("chat.stop"),
|
|
381
381
|
onClick: n.onCancel,
|
|
382
|
-
children: /* @__PURE__ */
|
|
383
|
-
}) : /* @__PURE__ */
|
|
382
|
+
children: /* @__PURE__ */ c(t, { name: "stop" })
|
|
383
|
+
}) : /* @__PURE__ */ c("button", {
|
|
384
384
|
className: "iconbtn fill",
|
|
385
385
|
"aria-label": r("chat.send"),
|
|
386
|
-
disabled: !
|
|
387
|
-
onClick: () => N(
|
|
388
|
-
children: /* @__PURE__ */
|
|
386
|
+
disabled: !o.trim() && d.length === 0 || E,
|
|
387
|
+
onClick: () => N(o, !1),
|
|
388
|
+
children: /* @__PURE__ */ c(t, { name: "send" })
|
|
389
389
|
})
|
|
390
390
|
]
|
|
391
391
|
}),
|
|
392
|
-
w.error && /* @__PURE__ */
|
|
392
|
+
w.error && /* @__PURE__ */ c("div", {
|
|
393
393
|
className: "err-text",
|
|
394
394
|
style: { padding: "0 12px 8px" },
|
|
395
395
|
children: r("chat.voice.micDenied")
|
|
396
396
|
})
|
|
397
|
-
] }) : /* @__PURE__ */
|
|
397
|
+
] }) : /* @__PURE__ */ l("div", {
|
|
398
398
|
className: "transcript",
|
|
399
399
|
style: { margin: 10 },
|
|
400
400
|
children: [
|
|
401
|
-
/* @__PURE__ */
|
|
401
|
+
/* @__PURE__ */ c("div", {
|
|
402
402
|
className: "small muted",
|
|
403
403
|
style: { marginBottom: 4 },
|
|
404
404
|
children: r("chat.voice.review")
|
|
405
405
|
}),
|
|
406
|
-
/* @__PURE__ */
|
|
406
|
+
/* @__PURE__ */ c("textarea", {
|
|
407
407
|
className: "inp",
|
|
408
408
|
rows: 3,
|
|
409
409
|
value: v,
|
|
410
|
-
onChange: (e) =>
|
|
410
|
+
onChange: (e) => y(e.target.value),
|
|
411
411
|
"aria-label": r("chat.voice.review")
|
|
412
412
|
}),
|
|
413
|
-
/* @__PURE__ */
|
|
413
|
+
/* @__PURE__ */ l("div", {
|
|
414
414
|
className: "row2",
|
|
415
415
|
style: { marginTop: 8 },
|
|
416
|
-
children: [/* @__PURE__ */
|
|
416
|
+
children: [/* @__PURE__ */ c("button", {
|
|
417
417
|
className: "btn ghost sm",
|
|
418
|
-
onClick: () =>
|
|
418
|
+
onClick: () => y(null),
|
|
419
419
|
children: r("delete")
|
|
420
|
-
}), /* @__PURE__ */
|
|
420
|
+
}), /* @__PURE__ */ c("button", {
|
|
421
421
|
className: "btn primary sm",
|
|
422
422
|
disabled: !v.trim() || E,
|
|
423
423
|
onClick: () => N(v, !0),
|
|
@@ -431,145 +431,217 @@ function x(n) {
|
|
|
431
431
|
}
|
|
432
432
|
//#endregion
|
|
433
433
|
//#region src/chat/ConversationList.tsx
|
|
434
|
-
function
|
|
435
|
-
let f =
|
|
436
|
-
|
|
434
|
+
function C({ conversations: e, currentId: n, open: r, onPick: i, onClose: o, onCreate: u }) {
|
|
435
|
+
let f = a(), [p, h] = m(!1);
|
|
436
|
+
d(() => {
|
|
437
437
|
if (!r) return;
|
|
438
|
-
let e = (e) => e.key === "Escape" &&
|
|
438
|
+
let e = (e) => e.key === "Escape" && o();
|
|
439
439
|
return document.addEventListener("keydown", e), () => document.removeEventListener("keydown", e);
|
|
440
|
-
}, [r,
|
|
441
|
-
let g = (e) => /* @__PURE__ */
|
|
440
|
+
}, [r, o]);
|
|
441
|
+
let g = (e) => /* @__PURE__ */ l("button", {
|
|
442
442
|
className: `it${e.id === n ? " on" : ""}${e.group === "archive" ? " arch" : ""}`,
|
|
443
|
-
onClick: () =>
|
|
443
|
+
onClick: () => i(e.id),
|
|
444
444
|
"aria-current": e.id === n,
|
|
445
445
|
children: [
|
|
446
|
-
/* @__PURE__ */
|
|
446
|
+
/* @__PURE__ */ c(t, {
|
|
447
447
|
name: e.icon ?? "msg2",
|
|
448
448
|
size: 16
|
|
449
449
|
}),
|
|
450
|
-
/* @__PURE__ */
|
|
450
|
+
/* @__PURE__ */ c("span", {
|
|
451
451
|
className: "nm",
|
|
452
452
|
children: e.title
|
|
453
453
|
}),
|
|
454
|
-
!!e.unread && /* @__PURE__ */
|
|
454
|
+
!!e.unread && /* @__PURE__ */ c("span", {
|
|
455
455
|
className: "unread",
|
|
456
456
|
"aria-label": f("chat.unread", { count: e.unread }),
|
|
457
457
|
children: e.unread
|
|
458
458
|
}),
|
|
459
|
-
/* @__PURE__ */
|
|
459
|
+
/* @__PURE__ */ c("span", {
|
|
460
460
|
className: "sub",
|
|
461
461
|
children: e.when
|
|
462
462
|
})
|
|
463
463
|
]
|
|
464
464
|
}, e.id), _ = (t) => e.filter((e) => e.group === t), v = _("topic"), y = _("archive");
|
|
465
|
-
return /* @__PURE__ */
|
|
466
|
-
/* @__PURE__ */
|
|
465
|
+
return /* @__PURE__ */ l(s, { children: [
|
|
466
|
+
/* @__PURE__ */ l("nav", {
|
|
467
467
|
className: `nb-side${r ? " open" : ""}`,
|
|
468
468
|
"aria-label": f("chat.conversations"),
|
|
469
469
|
children: [
|
|
470
|
-
|
|
470
|
+
u && /* @__PURE__ */ l("button", {
|
|
471
471
|
className: "btn sm",
|
|
472
472
|
style: {
|
|
473
473
|
width: "100%",
|
|
474
474
|
justifyContent: "center"
|
|
475
475
|
},
|
|
476
476
|
onClick: () => h(!0),
|
|
477
|
-
children: [/* @__PURE__ */
|
|
477
|
+
children: [/* @__PURE__ */ c(t, {
|
|
478
478
|
name: "plus",
|
|
479
479
|
size: 15
|
|
480
480
|
}), f("chat.newTopic")]
|
|
481
481
|
}),
|
|
482
|
-
/* @__PURE__ */
|
|
482
|
+
/* @__PURE__ */ c("div", {
|
|
483
483
|
className: "h",
|
|
484
484
|
children: f("chat.conversation")
|
|
485
485
|
}),
|
|
486
486
|
_("main").map(g),
|
|
487
|
-
/* @__PURE__ */
|
|
487
|
+
/* @__PURE__ */ c("div", {
|
|
488
488
|
className: "h",
|
|
489
489
|
children: f("chat.topics")
|
|
490
490
|
}),
|
|
491
|
-
v.length === 0 && /* @__PURE__ */
|
|
491
|
+
v.length === 0 && /* @__PURE__ */ c("div", {
|
|
492
492
|
className: "small muted",
|
|
493
493
|
style: { padding: "0 10px" },
|
|
494
494
|
children: f("chat.noTopics")
|
|
495
495
|
}),
|
|
496
496
|
v.map(g),
|
|
497
|
-
y.length > 0 && /* @__PURE__ */
|
|
497
|
+
y.length > 0 && /* @__PURE__ */ c("div", {
|
|
498
498
|
className: "h",
|
|
499
499
|
children: f("chat.archive")
|
|
500
500
|
}),
|
|
501
501
|
y.map(g)
|
|
502
502
|
]
|
|
503
503
|
}),
|
|
504
|
-
r && /* @__PURE__ */
|
|
504
|
+
r && /* @__PURE__ */ c("button", {
|
|
505
505
|
type: "button",
|
|
506
506
|
className: "nb-scrim",
|
|
507
507
|
"aria-label": f("close"),
|
|
508
|
-
onClick:
|
|
508
|
+
onClick: o
|
|
509
509
|
}),
|
|
510
|
-
|
|
510
|
+
p && u && /* @__PURE__ */ c(T, {
|
|
511
511
|
onClose: () => h(!1),
|
|
512
|
-
onCreate:
|
|
512
|
+
onCreate: u
|
|
513
513
|
})
|
|
514
514
|
] });
|
|
515
515
|
}
|
|
516
|
-
function
|
|
517
|
-
return /* @__PURE__ */
|
|
516
|
+
function w({ narrow: e, children: t }) {
|
|
517
|
+
return /* @__PURE__ */ c("div", {
|
|
518
518
|
className: `nb-app${e ? " narrow" : ""}`,
|
|
519
519
|
children: t
|
|
520
520
|
});
|
|
521
521
|
}
|
|
522
|
-
function
|
|
523
|
-
let r =
|
|
524
|
-
if (
|
|
525
|
-
d(!0),
|
|
522
|
+
function T({ onClose: e, onCreate: t }) {
|
|
523
|
+
let r = a(), [i, o] = m(""), [u, d] = m(!1), [f, p] = m(null), h = async () => {
|
|
524
|
+
if (i.trim() && !u) {
|
|
525
|
+
d(!0), p(null);
|
|
526
526
|
try {
|
|
527
|
-
await t(
|
|
527
|
+
await t(i.trim()), e();
|
|
528
528
|
} catch (e) {
|
|
529
|
-
|
|
529
|
+
p(e instanceof Error ? e.message : String(e)), d(!1);
|
|
530
530
|
}
|
|
531
531
|
}
|
|
532
532
|
};
|
|
533
|
-
return /* @__PURE__ */
|
|
533
|
+
return /* @__PURE__ */ l(n, {
|
|
534
534
|
title: r("chat.newTopic"),
|
|
535
535
|
onClose: e,
|
|
536
|
-
footer: /* @__PURE__ */
|
|
536
|
+
footer: /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("button", {
|
|
537
537
|
className: "btn ghost",
|
|
538
538
|
onClick: e,
|
|
539
539
|
children: r("cancel")
|
|
540
|
-
}), /* @__PURE__ */
|
|
540
|
+
}), /* @__PURE__ */ c("button", {
|
|
541
541
|
className: "btn primary",
|
|
542
|
-
disabled: !
|
|
542
|
+
disabled: !i.trim() || u,
|
|
543
543
|
onClick: h,
|
|
544
544
|
children: r("create")
|
|
545
545
|
})] }),
|
|
546
|
-
children: [/* @__PURE__ */
|
|
546
|
+
children: [/* @__PURE__ */ l("div", {
|
|
547
547
|
className: "field",
|
|
548
548
|
children: [
|
|
549
|
-
/* @__PURE__ */
|
|
549
|
+
/* @__PURE__ */ c("label", {
|
|
550
550
|
htmlFor: "topic-title",
|
|
551
551
|
children: r("chat.topicTitle")
|
|
552
552
|
}),
|
|
553
|
-
/* @__PURE__ */
|
|
553
|
+
/* @__PURE__ */ c("input", {
|
|
554
554
|
id: "topic-title",
|
|
555
555
|
className: "inp",
|
|
556
|
-
value:
|
|
556
|
+
value: i,
|
|
557
557
|
maxLength: 120,
|
|
558
|
-
onChange: (e) =>
|
|
558
|
+
onChange: (e) => o(e.target.value),
|
|
559
559
|
onKeyDown: (e) => e.key === "Enter" && h()
|
|
560
560
|
}),
|
|
561
|
-
/* @__PURE__ */
|
|
561
|
+
/* @__PURE__ */ c("div", {
|
|
562
562
|
className: "hint",
|
|
563
563
|
children: r("chat.topicHint")
|
|
564
564
|
})
|
|
565
565
|
]
|
|
566
|
-
}), f && /* @__PURE__ */
|
|
566
|
+
}), f && /* @__PURE__ */ c("div", {
|
|
567
567
|
className: "err-text",
|
|
568
568
|
children: f
|
|
569
569
|
})]
|
|
570
570
|
});
|
|
571
571
|
}
|
|
572
572
|
//#endregion
|
|
573
|
-
|
|
573
|
+
//#region src/chat/AgentMenu.tsx
|
|
574
|
+
function E({ icon: e, label: n, title: r, expanded: i, small: a, disabled: o, onClick: s }) {
|
|
575
|
+
return /* @__PURE__ */ c("button", {
|
|
576
|
+
type: "button",
|
|
577
|
+
className: `agentbtn${a ? " s" : ""}`,
|
|
578
|
+
disabled: o,
|
|
579
|
+
"aria-label": n,
|
|
580
|
+
"aria-expanded": i,
|
|
581
|
+
title: r,
|
|
582
|
+
onMouseDown: (e) => i && e.stopPropagation(),
|
|
583
|
+
onClick: s,
|
|
584
|
+
children: /* @__PURE__ */ c(t, {
|
|
585
|
+
name: e,
|
|
586
|
+
size: a ? 15 : 18
|
|
587
|
+
})
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
function D({ label: e, name: n, options: r, value: o, optionsLabel: s, hint: u, narrow: d, onRename: f, onPick: p, onClose: h }) {
|
|
591
|
+
let g = a(), [_, v] = m(n), y = i(!0, h);
|
|
592
|
+
return /* @__PURE__ */ l("div", {
|
|
593
|
+
className: `agentmenu${d ? " narrow" : ""}`,
|
|
594
|
+
ref: y,
|
|
595
|
+
role: "dialog",
|
|
596
|
+
"aria-label": e,
|
|
597
|
+
children: [
|
|
598
|
+
/* @__PURE__ */ c("div", {
|
|
599
|
+
className: "lab",
|
|
600
|
+
children: g("agentName")
|
|
601
|
+
}),
|
|
602
|
+
/* @__PURE__ */ c("input", {
|
|
603
|
+
className: "inp",
|
|
604
|
+
value: _,
|
|
605
|
+
maxLength: 40,
|
|
606
|
+
autoFocus: !0,
|
|
607
|
+
"aria-label": g("agentName"),
|
|
608
|
+
onChange: (e) => v(e.target.value),
|
|
609
|
+
onBlur: () => {
|
|
610
|
+
let e = _.trim();
|
|
611
|
+
e && e !== n && f(e);
|
|
612
|
+
},
|
|
613
|
+
onKeyDown: (e) => e.key === "Enter" && e.target.blur()
|
|
614
|
+
}),
|
|
615
|
+
/* @__PURE__ */ c("div", {
|
|
616
|
+
className: "lab",
|
|
617
|
+
style: { marginTop: 14 },
|
|
618
|
+
children: s
|
|
619
|
+
}),
|
|
620
|
+
/* @__PURE__ */ c("div", {
|
|
621
|
+
className: "agentoptions",
|
|
622
|
+
children: r.map((e) => /* @__PURE__ */ l("button", {
|
|
623
|
+
type: "button",
|
|
624
|
+
className: `agentoption${o === e.key ? " on" : ""}`,
|
|
625
|
+
"aria-pressed": o === e.key,
|
|
626
|
+
onClick: () => p(e.key),
|
|
627
|
+
children: [/* @__PURE__ */ c("span", {
|
|
628
|
+
className: "ic",
|
|
629
|
+
children: /* @__PURE__ */ c(t, {
|
|
630
|
+
name: e.icon,
|
|
631
|
+
size: 15
|
|
632
|
+
})
|
|
633
|
+
}), e.label]
|
|
634
|
+
}, e.key))
|
|
635
|
+
}),
|
|
636
|
+
u && /* @__PURE__ */ c("div", {
|
|
637
|
+
className: "hint",
|
|
638
|
+
style: { marginTop: 10 },
|
|
639
|
+
children: u
|
|
640
|
+
})
|
|
641
|
+
]
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
//#endregion
|
|
645
|
+
export { E as AgentButton, D as AgentMenu, S as Chat, w as ChatLayout, C as ConversationList, T as NewTopicModal, x as useRecorder };
|
|
574
646
|
|
|
575
647
|
//# sourceMappingURL=chat.js.map
|
package/dist/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","names":["_Fragment","_Fragment","_Fragment","useToast","Icon","Modal","Markdown","useKitT","UIKIT_NS","intlLocale","lng","markTime","language","iso","visibleSteps","open","steps","STEP","MessageView","useTranslation","setOpen","useState","m","mark","i18n","atts","a","Fragment","t","waiting","v","s","onRetry","busy","useRecorder","supported","recording","setRecording","seconds","setSeconds","error","setError","rec","useRef","chunks","timer","stopped","cleanup","useCallback","tr","start","stream","r","blob","began","stop","resolve","useEffect","Chat","toast","text","setText","pending","setPending","uploading","setUploading","transcript","setTranscript","listRef","fileRef","recorder","props","first","messages","tail","last","tailText","tailSteps","lastLayout","el","was","send","msg","body","f","voice","attach","files","x","stopAndTranscribe","voiceKey","placeholder","c","y","ConversationList","creating","setCreating","onKey","onClose","item","currentId","onPick","inGroup","conversations","g","topics","archive","onCreate","NewTopicModal","ChatLayout","narrow","title","setTitle","create"],"sources":["../src/chat/MessageView.tsx","../src/chat/useRecorder.ts","../src/chat/Chat.tsx","../src/chat/ConversationList.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { Markdown } from \"../components/Markdown\";\nimport { UIKIT_NS } from \"../i18n\";\nimport type { ChatMessage, ChatStep } from \"./types\";\n\n/** The locale of Intl formatting for a language code of the products. */\nconst intlLocale = (lng: string) => (lng === \"zh\" ? \"zh-CN\" : lng);\n\n/** The time of a caption: hours and minutes in the language of the interface. */\nexport function markTime(iso: string, language: string): string {\n return new Intl.DateTimeFormat(intlLocale(language), { hour: \"2-digit\", minute: \"2-digit\" }).format(new Date(iso));\n}\n\n/** More than three steps are folded to the last two (design §6.4). */\nexport function visibleSteps(steps: ChatStep[], open: boolean): ChatStep[] {\n return open || steps.length <= 3 ? steps : steps.slice(-2);\n}\n\n/** The icon of a step and its colour class by the state of the step. */\nconst STEP = {\n done: { icon: \"check\", cls: \"ok\" },\n error: { icon: \"alert\", cls: \"er\" },\n running: { icon: \"clock\", cls: \"run\" },\n} as const;\n\n/** One message of the conversation (design §6.4). */\nexport function MessageView({ m, busy, onRetry }: { m: ChatMessage; busy: boolean; onRetry?: () => void }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n if (m.role === \"note\") return <div className=\"sysnote\">{m.text}</div>;\n const mark = m.mark && <div className=\"chan\"><Icon name={m.mark.icon} size={12} /> {m.mark.text} · {markTime(m.createdAt, i18n.language)}</div>;\n const atts = m.attachments && m.attachments.length > 0 && (\n <div className=\"atts\">\n {m.attachments.map((a) => <a key={a.id} href={a.href}><Icon name=\"clip\" size={12} /> {a.fileName}</a>)}\n </div>\n );\n if (m.role === \"user\") {\n return (\n <div className=\"m u\">\n {mark}\n {m.content}\n {m.text && <div className=\"bub\">{m.text}</div>}\n {atts}\n {m.wait && (\n <div className={`turnstate${m.wait.state === \"queued\" ? \" q\" : \"\"}`} role=\"status\">\n {m.wait.state === \"queued\"\n ? <><Icon name=\"clock\" size={12} />{t(\"chat.wait.queued\", { count: m.wait.position })}</>\n : <><span className=\"spin\" aria-hidden=\"true\" />{t(\"chat.wait.starting\")}</>}\n </div>\n )}\n </div>\n );\n }\n const steps = m.steps ?? [];\n const waiting = (m.status === \"streaming\" || m.status === \"pending\") && !m.text && !m.content;\n return (\n <div className=\"m a\">\n {mark}\n {steps.length > 3 && (\n <button className=\"tools-fold\" onClick={() => setOpen((v) => !v)} aria-expanded={open}>\n {open ? t(\"chat.hideSteps\") : t(\"chat.moreSteps\", { count: steps.length - 2 })}\n </button>\n )}\n {visibleSteps(steps, open).map((s) => (\n <div key={s.id} className=\"tool\" title={s.title}>\n <Icon name={STEP[s.status].icon} size={14} className={STEP[s.status].cls} />\n <span className=\"tx\">{s.text}</span>\n </div>\n ))}\n {waiting && <div className=\"bub\"><span className=\"typing\" aria-label={t(\"chat.typing\")}><i /><i /><i /></span></div>}\n {m.content ?? (m.text && <div className=\"bub\"><Markdown text={m.text} /></div>)}\n {atts}\n {m.error && (\n <div className={`llmerr${m.error.transient ? \" amber\" : \"\"}`} role=\"alert\" style={{ marginTop: 6 }}>\n <span>{m.error.text}</span>\n {onRetry && (\n <div className=\"row\">\n <button className=\"btn sm\" disabled={busy} onClick={onRetry}><Icon name=\"refresh\" size={14} />{t(\"chat.retry\")}</button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Push-to-talk recording with MediaRecorder. */\nexport function useRecorder() {\n const supported = typeof window !== \"undefined\" && \"MediaRecorder\" in window && !!navigator.mediaDevices?.getUserMedia;\n const [recording, setRecording] = useState(false);\n const [seconds, setSeconds] = useState(0);\n const [error, setError] = useState(false);\n const rec = useRef<MediaRecorder | null>(null);\n const chunks = useRef<Blob[]>([]);\n const timer = useRef<number | undefined>(undefined);\n const stopped = useRef<((b: Blob | null) => void) | null>(null);\n\n const cleanup = useCallback(() => {\n window.clearInterval(timer.current);\n rec.current?.stream.getTracks().forEach((tr) => tr.stop());\n rec.current = null;\n setRecording(false);\n }, []);\n\n const start = useCallback(async () => {\n if (!supported || rec.current) return;\n setError(false);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const r = new MediaRecorder(stream);\n chunks.current = [];\n r.ondataavailable = (e) => e.data.size > 0 && chunks.current.push(e.data);\n r.onstop = () => {\n const blob = chunks.current.length ? new Blob(chunks.current, { type: r.mimeType || \"audio/webm\" }) : null;\n cleanup();\n stopped.current?.(blob);\n stopped.current = null;\n };\n rec.current = r;\n r.start();\n setSeconds(0);\n setRecording(true);\n const began = Date.now();\n timer.current = window.setInterval(() => setSeconds(Math.floor((Date.now() - began) / 1000)), 250);\n } catch {\n setError(true);\n cleanup();\n }\n }, [supported, cleanup]);\n\n const stop = useCallback(() => new Promise<Blob | null>((resolve) => {\n const r = rec.current;\n if (!r || r.state === \"inactive\") return resolve(null);\n stopped.current = resolve;\n r.stop();\n }), []);\n\n useEffect(() => () => cleanup(), [cleanup]);\n\n const mm = Math.floor(seconds / 60);\n const ss = String(seconds % 60).padStart(2, \"0\");\n return { supported, recording, seconds: `${mm}:${ss}`, error, start, stop };\n}\n","import { useLayoutEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { useToast } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport { MessageView } from \"./MessageView\";\nimport type { ChatProps, ChatUpload } from \"./types\";\nimport { useRecorder } from \"./useRecorder\";\n\n/** The conversation: the messages and the composer (FTR.NAB.CMN-0005 R11–R13,\n * design §6). The behaviour is the one of the chat of Nabu. A control exists\n * only when the product gave its handler: no `onCancel` — no cancel button. */\nexport function Chat(props: ChatProps) {\n const t = useKitT();\n const toast = useToast();\n const [text, setText] = useState(\"\");\n const [pending, setPending] = useState<ChatUpload[]>([]);\n const [uploading, setUploading] = useState(false);\n const [transcript, setTranscript] = useState<string | null>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const recorder = useRecorder();\n const { messages, busy = false } = props;\n\n const first = messages[0]?.id;\n const tail = messages[messages.length - 1];\n const last = tail?.id;\n const tailText = tail?.text.length;\n const tailSteps = tail?.steps?.length;\n // The ends and the height of the list at the last layout: earlier messages\n // loaded above it keep the place of the list.\n const lastLayout = useRef<{ first?: string; last?: string; height: number }>({ height: 0 });\n // The list follows new messages and the growth of the last one: the dependencies are the trigger.\n useLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n const was = lastLayout.current;\n // history is prepended when the start of the list changed and its end did not;\n // another conversation changes both\n const prepended = was.first !== undefined && first !== was.first && last === was.last;\n el.scrollTop = prepended ? el.scrollTop + (el.scrollHeight - was.height) : el.scrollHeight;\n lastLayout.current = { first, last, height: el.scrollHeight };\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the length and the growth of the tail only trigger\n }, [messages.length, first, last, tailText, tailSteps]);\n\n const send = async (body: string, voice: boolean) => {\n const msg = body.trim();\n if ((!msg && pending.length === 0) || busy || props.readOnly) return;\n try {\n await props.onSend(msg, pending.map((f) => f.id), voice);\n setText(\"\");\n setPending([]);\n setTranscript(null);\n } catch {\n // the product has told the user; the text stays in the composer\n }\n };\n\n const attach = async (files: FileList | null) => {\n if (!files?.length || !props.onUpload) return;\n setUploading(true);\n for (const f of Array.from(files)) {\n if (props.upload && f.size > props.upload.maxBytes) {\n toast({ kind: \"error\", title: t(\"chat.tooLarge\"), text: f.name });\n continue;\n }\n const a = await props.onUpload(f).catch(() => null);\n if (a) setPending((x) => [...x, a]);\n }\n setUploading(false);\n if (fileRef.current) fileRef.current.value = \"\";\n };\n\n const stopAndTranscribe = async () => {\n const blob = await recorder.stop();\n if (!blob || !props.onTranscribe) return;\n const r = await props.onTranscribe(blob).catch(() => null);\n if (r === null) return;\n if (!r) toast({ kind: \"error\", title: t(\"chat.voice.notRecognized\") });\n else setTranscript(r);\n };\n // Without a pointer the same button starts and stops the recording (R18).\n const voiceKey = (e: KeyboardEvent) => {\n if (e.key !== \" \" && e.key !== \"Enter\") return;\n e.preventDefault();\n if (e.repeat) return;\n if (recorder.recording) void stopAndTranscribe();\n else void recorder.start();\n };\n\n const placeholder = t(\"chat.placeholder\", { name: props.agentName });\n return (\n <section className=\"nb-chat\" aria-label={t(\"chat.title\")}>\n {props.header}\n <div className=\"msgs\" ref={listRef} aria-live=\"polite\">\n {props.hasOlder && props.onLoadOlder && (\n <button className=\"btn ghost sm\" style={{ alignSelf: \"center\" }} disabled={props.loadingOlder} onClick={props.onLoadOlder}>\n {t(\"chat.loadOlder\")}\n </button>\n )}\n {props.historyError && <div className=\"err-text\">{props.historyError}</div>}\n {messages.length === 0 && !props.loading && !props.historyError && (\n <div className=\"empty\"><div className=\"ic\"><Icon name=\"spark\" /></div><b>{t(\"chat.emptyTitle\", { name: props.agentName })}</b>{props.emptyHint}</div>\n )}\n {messages.map((m) => <MessageView key={m.id} m={m} busy={busy} onRetry={props.onRetry && (() => props.onRetry?.(m.id))} />)}\n {props.onConfirm && (props.confirmations ?? []).map((c) => (\n <div className=\"confirm\" key={c.id} role=\"group\" aria-label={t(\"chat.confirm.title\")}>\n <div className=\"h\"><Icon name=\"alert\" size={16} />{t(\"chat.confirm.title\")}</div>\n <div>{t(\"chat.confirm.text\", { action: c.summary })}</div>\n {c.preview !== undefined && <pre>{c.preview}</pre>}\n <div className=\"acts\">\n {/* never tied to `busy`: the agent asks in the middle of its turn */}\n <button className=\"btn sm primary\" onClick={() => props.onConfirm?.(c.id, true)}>{t(\"chat.confirm.approve\")}</button>\n <button className=\"btn sm\" onClick={() => props.onConfirm?.(c.id, false)}>{t(\"chat.confirm.reject\")}</button>\n </div>\n </div>\n ))}\n </div>\n\n {props.readOnly ? (\n <div className=\"composer\" style={{ justifyContent: \"space-between\", alignItems: \"center\" }}>{props.readOnly}</div>\n ) : transcript !== null ? (\n <div className=\"transcript\" style={{ margin: 10 }}>\n <div className=\"small muted\" style={{ marginBottom: 4 }}>{t(\"chat.voice.review\")}</div>\n <textarea className=\"inp\" rows={3} value={transcript} onChange={(e) => setTranscript(e.target.value)} aria-label={t(\"chat.voice.review\")} />\n <div className=\"row2\" style={{ marginTop: 8 }}>\n <button className=\"btn ghost sm\" onClick={() => setTranscript(null)}>{t(\"delete\")}</button>\n <button className=\"btn primary sm\" disabled={!transcript.trim() || busy} onClick={() => send(transcript, true)}>{t(\"chat.send\")}</button>\n </div>\n </div>\n ) : (\n <>\n {props.aboveComposer}\n {pending.length > 0 && (\n <div className=\"pending-files\">\n {pending.map((f) => (\n <span key={f.id} className=\"chip\">\n <Icon name=\"clip\" size={12} />{f.fileName}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")}\n onClick={() => setPending((x) => x.filter((y) => y.id !== f.id))}><Icon name=\"x\" size={12} /></button>\n </span>\n ))}\n </div>\n )}\n <div className=\"composer\">\n {props.onUpload && (\n <>\n <button className=\"iconbtn\" aria-label={t(\"chat.attach\")} disabled={uploading} onClick={() => fileRef.current?.click()}><Icon name=\"clip\" /></button>\n <input ref={fileRef} type=\"file\" multiple hidden accept={props.upload?.accept} onChange={(e) => attach(e.target.files)} />\n </>\n )}\n {recorder.recording ? (\n <div className=\"rec-box\">{t(\"chat.voice.recording\", { seconds: recorder.seconds })}</div>\n ) : (\n <textarea rows={1} value={text} placeholder={placeholder} aria-label={placeholder} onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n void send(text, false);\n }\n }} />\n )}\n {props.onTranscribe && (\n <button className={`iconbtn${recorder.recording ? \" rec\" : \"\"}`} disabled={!recorder.supported}\n aria-label={recorder.recording ? t(\"chat.voice.stop\") : t(\"chat.voice.hold\")}\n title={recorder.supported ? t(\"chat.voice.hold\") : t(\"chat.voice.unsupported\")}\n onPointerDown={(e) => { e.preventDefault(); if (!recorder.recording) void recorder.start(); }}\n onPointerUp={() => recorder.recording && stopAndTranscribe()}\n onPointerLeave={() => recorder.recording && stopAndTranscribe()}\n onKeyDown={voiceKey}>\n <Icon name=\"mic\" />\n </button>\n )}\n {props.onCancel && busy ? (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.stop\")} onClick={props.onCancel}><Icon name=\"stop\" /></button>\n ) : (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.send\")} disabled={(!text.trim() && pending.length === 0) || busy} onClick={() => send(text, false)}>\n <Icon name=\"send\" />\n </button>\n )}\n </div>\n {recorder.error && <div className=\"err-text\" style={{ padding: \"0 12px 8px\" }}>{t(\"chat.voice.micDenied\")}</div>}\n </>\n )}\n </section>\n );\n}\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { Modal } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatConversation, ConversationListProps } from \"./types\";\n\n/** The conversations of the user: the main one, the topics, the archive (design\n * §6.2). In a wide place the list stands left of the messages; on a phone and in\n * a narrow place it lies over them while open and closes by a pick, a tap\n * beside it or Escape. */\nexport function ConversationList({ conversations, currentId, open, onPick, onClose, onCreate }: ConversationListProps) {\n const t = useKitT();\n const [creating, setCreating] = useState(false);\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onClose]);\n\n const item = (c: ChatConversation) => (\n <button key={c.id} className={`it${c.id === currentId ? \" on\" : \"\"}${c.group === \"archive\" ? \" arch\" : \"\"}`}\n onClick={() => onPick(c.id)} aria-current={c.id === currentId}>\n <Icon name={c.icon ?? \"msg2\"} size={16} />\n <span className=\"nm\">{c.title}</span>\n {!!c.unread && <span className=\"unread\" aria-label={t(\"chat.unread\", { count: c.unread })}>{c.unread}</span>}\n <span className=\"sub\">{c.when}</span>\n </button>\n );\n const inGroup = (g: ChatConversation[\"group\"]) => conversations.filter((c) => c.group === g);\n const topics = inGroup(\"topic\");\n const archive = inGroup(\"archive\");\n return (\n <>\n <nav className={`nb-side${open ? \" open\" : \"\"}`} aria-label={t(\"chat.conversations\")}>\n {onCreate && (\n <button className=\"btn sm\" style={{ width: \"100%\", justifyContent: \"center\" }} onClick={() => setCreating(true)}>\n <Icon name=\"plus\" size={15} />{t(\"chat.newTopic\")}\n </button>\n )}\n <div className=\"h\">{t(\"chat.conversation\")}</div>\n {inGroup(\"main\").map(item)}\n <div className=\"h\">{t(\"chat.topics\")}</div>\n {topics.length === 0 && <div className=\"small muted\" style={{ padding: \"0 10px\" }}>{t(\"chat.noTopics\")}</div>}\n {topics.map(item)}\n {archive.length > 0 && <div className=\"h\">{t(\"chat.archive\")}</div>}\n {archive.map(item)}\n </nav>\n {/* over the messages: a tap beside the list closes it */}\n {open && <button type=\"button\" className=\"nb-scrim\" aria-label={t(\"close\")} onClick={onClose} />}\n {creating && onCreate && <NewTopicModal onClose={() => setCreating(false)} onCreate={onCreate} />}\n </>\n );\n}\n\n/** The place of a chat: the list of conversations, the conversation and what the\n * product puts beside them. `narrow` is for a side panel: the list lies over the\n * messages as on a phone, whatever the width of the window. */\nexport function ChatLayout({ narrow, children }: { narrow?: boolean; children: ReactNode }) {\n return <div className={`nb-app${narrow ? \" narrow\" : \"\"}`}>{children}</div>;\n}\n\n/** The dialog of a new topic: one field, Enter creates. */\nexport function NewTopicModal({ onClose, onCreate }: { onClose: () => void; onCreate: (title: string) => Promise<void> }) {\n const t = useKitT();\n const [title, setTitle] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const create = async () => {\n if (!title.trim() || pending) return;\n setPending(true);\n setError(null);\n try {\n await onCreate(title.trim());\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setPending(false);\n }\n };\n return (\n <Modal title={t(\"chat.newTopic\")} onClose={onClose} footer={<>\n <button className=\"btn ghost\" onClick={onClose}>{t(\"cancel\")}</button>\n <button className=\"btn primary\" disabled={!title.trim() || pending} onClick={create}>{t(\"create\")}</button>\n </>}>\n <div className=\"field\">\n <label htmlFor=\"topic-title\">{t(\"chat.topicTitle\")}</label>\n <input id=\"topic-title\" className=\"inp\" value={title} maxLength={120} onChange={(e) => setTitle(e.target.value)}\n onKeyDown={(e) => e.key === \"Enter\" && create()} />\n <div className=\"hint\">{t(\"chat.topicHint\")}</div>\n </div>\n {error && <div className=\"err-text\">{error}</div>}\n </Modal>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat.js","names":["_Fragment","_Fragment","_Fragment","useToast","Icon","Modal","Markdown","useOutside","useKitT","UIKIT_NS","intlLocale","lng","markTime","language","iso","visibleSteps","open","steps","STEP","MessageView","useTranslation","setOpen","useState","m","mark","i18n","atts","a","Fragment","t","waiting","v","s","onRetry","busy","useRecorder","supported","recording","setRecording","seconds","setSeconds","error","setError","rec","useRef","chunks","timer","stopped","cleanup","useCallback","tr","start","stream","r","blob","began","stop","resolve","useEffect","Chat","toast","text","setText","pending","setPending","uploading","setUploading","transcript","setTranscript","listRef","fileRef","recorder","props","first","messages","tail","last","tailText","tailSteps","lastLayout","el","was","send","msg","body","f","voice","attach","files","x","stopAndTranscribe","voiceKey","placeholder","c","y","ConversationList","creating","setCreating","onKey","onClose","item","currentId","onPick","inGroup","conversations","g","topics","archive","onCreate","NewTopicModal","ChatLayout","narrow","title","setTitle","create","AgentButton","small","label","expanded","icon","AgentMenu","draft","setDraft","name","ref","next","onRename","optionsLabel","options","value","o","hint"],"sources":["../src/chat/MessageView.tsx","../src/chat/useRecorder.ts","../src/chat/Chat.tsx","../src/chat/ConversationList.tsx","../src/chat/AgentMenu.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Icon } from \"../components/Icon\";\nimport { Markdown } from \"../components/Markdown\";\nimport { UIKIT_NS } from \"../i18n\";\nimport type { ChatMessage, ChatStep } from \"./types\";\n\n/** The locale of Intl formatting for a language code of the products. */\nconst intlLocale = (lng: string) => (lng === \"zh\" ? \"zh-CN\" : lng);\n\n/** The time of a caption: hours and minutes in the language of the interface. */\nexport function markTime(iso: string, language: string): string {\n return new Intl.DateTimeFormat(intlLocale(language), { hour: \"2-digit\", minute: \"2-digit\" }).format(new Date(iso));\n}\n\n/** More than three steps are folded to the last two (design §6.4). */\nexport function visibleSteps(steps: ChatStep[], open: boolean): ChatStep[] {\n return open || steps.length <= 3 ? steps : steps.slice(-2);\n}\n\n/** The icon of a step and its colour class by the state of the step. */\nconst STEP = {\n done: { icon: \"check\", cls: \"ok\" },\n error: { icon: \"alert\", cls: \"er\" },\n running: { icon: \"clock\", cls: \"run\" },\n} as const;\n\n/** One message of the conversation (design §6.4). */\nexport function MessageView({ m, busy, onRetry }: { m: ChatMessage; busy: boolean; onRetry?: () => void }) {\n const { t, i18n } = useTranslation(UIKIT_NS);\n const [open, setOpen] = useState(false);\n if (m.role === \"note\") return <div className=\"sysnote\">{m.text}</div>;\n const mark = m.mark && <div className=\"chan\"><Icon name={m.mark.icon} size={12} /> {m.mark.text} · {markTime(m.createdAt, i18n.language)}</div>;\n const atts = m.attachments && m.attachments.length > 0 && (\n <div className=\"atts\">\n {m.attachments.map((a) => <a key={a.id} href={a.href}><Icon name=\"clip\" size={12} /> {a.fileName}</a>)}\n </div>\n );\n if (m.role === \"user\") {\n return (\n <div className=\"m u\">\n {mark}\n {m.content}\n {m.text && <div className=\"bub\">{m.text}</div>}\n {atts}\n {m.wait && (\n <div className={`turnstate${m.wait.state === \"queued\" ? \" q\" : \"\"}`} role=\"status\">\n {m.wait.state === \"queued\"\n ? <><Icon name=\"clock\" size={12} />{t(\"chat.wait.queued\", { count: m.wait.position })}</>\n : <><span className=\"spin\" aria-hidden=\"true\" />{t(\"chat.wait.starting\")}</>}\n </div>\n )}\n </div>\n );\n }\n const steps = m.steps ?? [];\n const waiting = (m.status === \"streaming\" || m.status === \"pending\") && !m.text && !m.content;\n return (\n <div className=\"m a\">\n {mark}\n {steps.length > 3 && (\n <button className=\"tools-fold\" onClick={() => setOpen((v) => !v)} aria-expanded={open}>\n {open ? t(\"chat.hideSteps\") : t(\"chat.moreSteps\", { count: steps.length - 2 })}\n </button>\n )}\n {visibleSteps(steps, open).map((s) => (\n <div key={s.id} className=\"tool\" title={s.title}>\n <Icon name={STEP[s.status].icon} size={14} className={STEP[s.status].cls} />\n <span className=\"tx\">{s.text}</span>\n </div>\n ))}\n {waiting && <div className=\"bub\"><span className=\"typing\" aria-label={t(\"chat.typing\")}><i /><i /><i /></span></div>}\n {m.content ?? (m.text && <div className=\"bub\"><Markdown text={m.text} /></div>)}\n {atts}\n {m.error && (\n <div className={`llmerr${m.error.transient ? \" amber\" : \"\"}`} role=\"alert\" style={{ marginTop: 6 }}>\n <span>{m.error.text}</span>\n {onRetry && (\n <div className=\"row\">\n <button className=\"btn sm\" disabled={busy} onClick={onRetry}><Icon name=\"refresh\" size={14} />{t(\"chat.retry\")}</button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/** Push-to-talk recording with MediaRecorder. */\nexport function useRecorder() {\n const supported = typeof window !== \"undefined\" && \"MediaRecorder\" in window && !!navigator.mediaDevices?.getUserMedia;\n const [recording, setRecording] = useState(false);\n const [seconds, setSeconds] = useState(0);\n const [error, setError] = useState(false);\n const rec = useRef<MediaRecorder | null>(null);\n const chunks = useRef<Blob[]>([]);\n const timer = useRef<number | undefined>(undefined);\n const stopped = useRef<((b: Blob | null) => void) | null>(null);\n\n const cleanup = useCallback(() => {\n window.clearInterval(timer.current);\n rec.current?.stream.getTracks().forEach((tr) => tr.stop());\n rec.current = null;\n setRecording(false);\n }, []);\n\n const start = useCallback(async () => {\n if (!supported || rec.current) return;\n setError(false);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const r = new MediaRecorder(stream);\n chunks.current = [];\n r.ondataavailable = (e) => e.data.size > 0 && chunks.current.push(e.data);\n r.onstop = () => {\n const blob = chunks.current.length ? new Blob(chunks.current, { type: r.mimeType || \"audio/webm\" }) : null;\n cleanup();\n stopped.current?.(blob);\n stopped.current = null;\n };\n rec.current = r;\n r.start();\n setSeconds(0);\n setRecording(true);\n const began = Date.now();\n timer.current = window.setInterval(() => setSeconds(Math.floor((Date.now() - began) / 1000)), 250);\n } catch {\n setError(true);\n cleanup();\n }\n }, [supported, cleanup]);\n\n const stop = useCallback(() => new Promise<Blob | null>((resolve) => {\n const r = rec.current;\n if (!r || r.state === \"inactive\") return resolve(null);\n stopped.current = resolve;\n r.stop();\n }), []);\n\n useEffect(() => () => cleanup(), [cleanup]);\n\n const mm = Math.floor(seconds / 60);\n const ss = String(seconds % 60).padStart(2, \"0\");\n return { supported, recording, seconds: `${mm}:${ss}`, error, start, stop };\n}\n","import { useLayoutEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { useToast } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport { MessageView } from \"./MessageView\";\nimport type { ChatProps, ChatUpload } from \"./types\";\nimport { useRecorder } from \"./useRecorder\";\n\n/** The conversation: the messages and the composer (FTR.NAB.CMN-0005 R11–R13,\n * design §6). The behaviour is the one of the chat of Nabu. A control exists\n * only when the product gave its handler: no `onCancel` — no cancel button. */\nexport function Chat(props: ChatProps) {\n const t = useKitT();\n const toast = useToast();\n const [text, setText] = useState(\"\");\n const [pending, setPending] = useState<ChatUpload[]>([]);\n const [uploading, setUploading] = useState(false);\n const [transcript, setTranscript] = useState<string | null>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const recorder = useRecorder();\n const { messages, busy = false } = props;\n\n const first = messages[0]?.id;\n const tail = messages[messages.length - 1];\n const last = tail?.id;\n const tailText = tail?.text.length;\n const tailSteps = tail?.steps?.length;\n // The ends and the height of the list at the last layout: earlier messages\n // loaded above it keep the place of the list.\n const lastLayout = useRef<{ first?: string; last?: string; height: number }>({ height: 0 });\n // The list follows new messages and the growth of the last one: the dependencies are the trigger.\n useLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n const was = lastLayout.current;\n // history is prepended when the start of the list changed and its end did not;\n // another conversation changes both\n const prepended = was.first !== undefined && first !== was.first && last === was.last;\n el.scrollTop = prepended ? el.scrollTop + (el.scrollHeight - was.height) : el.scrollHeight;\n lastLayout.current = { first, last, height: el.scrollHeight };\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the length and the growth of the tail only trigger\n }, [messages.length, first, last, tailText, tailSteps]);\n\n const send = async (body: string, voice: boolean) => {\n const msg = body.trim();\n if ((!msg && pending.length === 0) || busy || props.readOnly) return;\n try {\n await props.onSend(msg, pending.map((f) => f.id), voice);\n setText(\"\");\n setPending([]);\n setTranscript(null);\n } catch {\n // the product has told the user; the text stays in the composer\n }\n };\n\n const attach = async (files: FileList | null) => {\n if (!files?.length || !props.onUpload) return;\n setUploading(true);\n for (const f of Array.from(files)) {\n if (props.upload && f.size > props.upload.maxBytes) {\n toast({ kind: \"error\", title: t(\"chat.tooLarge\"), text: f.name });\n continue;\n }\n const a = await props.onUpload(f).catch(() => null);\n if (a) setPending((x) => [...x, a]);\n }\n setUploading(false);\n if (fileRef.current) fileRef.current.value = \"\";\n };\n\n const stopAndTranscribe = async () => {\n const blob = await recorder.stop();\n if (!blob || !props.onTranscribe) return;\n const r = await props.onTranscribe(blob).catch(() => null);\n if (r === null) return;\n if (!r) toast({ kind: \"error\", title: t(\"chat.voice.notRecognized\") });\n else setTranscript(r);\n };\n // Without a pointer the same button starts and stops the recording (R18).\n const voiceKey = (e: KeyboardEvent) => {\n if (e.key !== \" \" && e.key !== \"Enter\") return;\n e.preventDefault();\n if (e.repeat) return;\n if (recorder.recording) void stopAndTranscribe();\n else void recorder.start();\n };\n\n const placeholder = t(\"chat.placeholder\", { name: props.agentName });\n return (\n <section className=\"nb-chat\" aria-label={t(\"chat.title\")}>\n {props.header}\n <div className=\"msgs\" ref={listRef} aria-live=\"polite\">\n {props.hasOlder && props.onLoadOlder && (\n <button className=\"btn ghost sm\" style={{ alignSelf: \"center\" }} disabled={props.loadingOlder} onClick={props.onLoadOlder}>\n {t(\"chat.loadOlder\")}\n </button>\n )}\n {props.historyError && <div className=\"err-text\">{props.historyError}</div>}\n {messages.length === 0 && !props.loading && !props.historyError && (\n <div className=\"empty\"><div className=\"ic\"><Icon name=\"spark\" /></div><b>{t(\"chat.emptyTitle\", { name: props.agentName })}</b>{props.emptyHint}</div>\n )}\n {messages.map((m) => <MessageView key={m.id} m={m} busy={busy} onRetry={props.onRetry && (() => props.onRetry?.(m.id))} />)}\n {props.onConfirm && (props.confirmations ?? []).map((c) => (\n <div className=\"confirm\" key={c.id} role=\"group\" aria-label={t(\"chat.confirm.title\")}>\n <div className=\"h\"><Icon name=\"alert\" size={16} />{t(\"chat.confirm.title\")}</div>\n <div>{t(\"chat.confirm.text\", { action: c.summary })}</div>\n {c.preview !== undefined && <pre>{c.preview}</pre>}\n <div className=\"acts\">\n {/* never tied to `busy`: the agent asks in the middle of its turn */}\n <button className=\"btn sm primary\" onClick={() => props.onConfirm?.(c.id, true)}>{t(\"chat.confirm.approve\")}</button>\n <button className=\"btn sm\" onClick={() => props.onConfirm?.(c.id, false)}>{t(\"chat.confirm.reject\")}</button>\n </div>\n </div>\n ))}\n </div>\n\n {props.readOnly ? (\n <div className=\"composer\" style={{ justifyContent: \"space-between\", alignItems: \"center\" }}>{props.readOnly}</div>\n ) : transcript !== null ? (\n <div className=\"transcript\" style={{ margin: 10 }}>\n <div className=\"small muted\" style={{ marginBottom: 4 }}>{t(\"chat.voice.review\")}</div>\n <textarea className=\"inp\" rows={3} value={transcript} onChange={(e) => setTranscript(e.target.value)} aria-label={t(\"chat.voice.review\")} />\n <div className=\"row2\" style={{ marginTop: 8 }}>\n <button className=\"btn ghost sm\" onClick={() => setTranscript(null)}>{t(\"delete\")}</button>\n <button className=\"btn primary sm\" disabled={!transcript.trim() || busy} onClick={() => send(transcript, true)}>{t(\"chat.send\")}</button>\n </div>\n </div>\n ) : (\n <>\n {props.aboveComposer}\n {pending.length > 0 && (\n <div className=\"pending-files\">\n {pending.map((f) => (\n <span key={f.id} className=\"chip\">\n <Icon name=\"clip\" size={12} />{f.fileName}\n <button className=\"iconbtn\" style={{ width: 18, height: 18 }} aria-label={t(\"remove\")}\n onClick={() => setPending((x) => x.filter((y) => y.id !== f.id))}><Icon name=\"x\" size={12} /></button>\n </span>\n ))}\n </div>\n )}\n <div className=\"composer\">\n {props.onUpload && (\n <>\n <button className=\"iconbtn\" aria-label={t(\"chat.attach\")} disabled={uploading} onClick={() => fileRef.current?.click()}><Icon name=\"clip\" /></button>\n <input ref={fileRef} type=\"file\" multiple hidden accept={props.upload?.accept} onChange={(e) => attach(e.target.files)} />\n </>\n )}\n {recorder.recording ? (\n <div className=\"rec-box\">{t(\"chat.voice.recording\", { seconds: recorder.seconds })}</div>\n ) : (\n <textarea rows={1} value={text} placeholder={placeholder} aria-label={placeholder} onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n void send(text, false);\n }\n }} />\n )}\n {props.onTranscribe && (\n <button className={`iconbtn${recorder.recording ? \" rec\" : \"\"}`} disabled={!recorder.supported}\n aria-label={recorder.recording ? t(\"chat.voice.stop\") : t(\"chat.voice.hold\")}\n title={recorder.supported ? t(\"chat.voice.hold\") : t(\"chat.voice.unsupported\")}\n onPointerDown={(e) => { e.preventDefault(); if (!recorder.recording) void recorder.start(); }}\n onPointerUp={() => recorder.recording && stopAndTranscribe()}\n onPointerLeave={() => recorder.recording && stopAndTranscribe()}\n onKeyDown={voiceKey}>\n <Icon name=\"mic\" />\n </button>\n )}\n {props.onCancel && busy ? (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.stop\")} onClick={props.onCancel}><Icon name=\"stop\" /></button>\n ) : (\n <button className=\"iconbtn fill\" aria-label={t(\"chat.send\")} disabled={(!text.trim() && pending.length === 0) || busy} onClick={() => send(text, false)}>\n <Icon name=\"send\" />\n </button>\n )}\n </div>\n {recorder.error && <div className=\"err-text\" style={{ padding: \"0 12px 8px\" }}>{t(\"chat.voice.micDenied\")}</div>}\n </>\n )}\n </section>\n );\n}\n","import { useEffect, useState, type ReactNode } from \"react\";\nimport { Icon } from \"../components/Icon\";\nimport { Modal } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\nimport type { ChatConversation, ConversationListProps } from \"./types\";\n\n/** The conversations of the user: the main one, the topics, the archive (design\n * §6.2). In a wide place the list stands left of the messages; on a phone and in\n * a narrow place it lies over them while open and closes by a pick, a tap\n * beside it or Escape. */\nexport function ConversationList({ conversations, currentId, open, onPick, onClose, onCreate }: ConversationListProps) {\n const t = useKitT();\n const [creating, setCreating] = useState(false);\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onClose]);\n\n const item = (c: ChatConversation) => (\n <button key={c.id} className={`it${c.id === currentId ? \" on\" : \"\"}${c.group === \"archive\" ? \" arch\" : \"\"}`}\n onClick={() => onPick(c.id)} aria-current={c.id === currentId}>\n <Icon name={c.icon ?? \"msg2\"} size={16} />\n <span className=\"nm\">{c.title}</span>\n {!!c.unread && <span className=\"unread\" aria-label={t(\"chat.unread\", { count: c.unread })}>{c.unread}</span>}\n <span className=\"sub\">{c.when}</span>\n </button>\n );\n const inGroup = (g: ChatConversation[\"group\"]) => conversations.filter((c) => c.group === g);\n const topics = inGroup(\"topic\");\n const archive = inGroup(\"archive\");\n return (\n <>\n <nav className={`nb-side${open ? \" open\" : \"\"}`} aria-label={t(\"chat.conversations\")}>\n {onCreate && (\n <button className=\"btn sm\" style={{ width: \"100%\", justifyContent: \"center\" }} onClick={() => setCreating(true)}>\n <Icon name=\"plus\" size={15} />{t(\"chat.newTopic\")}\n </button>\n )}\n <div className=\"h\">{t(\"chat.conversation\")}</div>\n {inGroup(\"main\").map(item)}\n <div className=\"h\">{t(\"chat.topics\")}</div>\n {topics.length === 0 && <div className=\"small muted\" style={{ padding: \"0 10px\" }}>{t(\"chat.noTopics\")}</div>}\n {topics.map(item)}\n {archive.length > 0 && <div className=\"h\">{t(\"chat.archive\")}</div>}\n {archive.map(item)}\n </nav>\n {/* over the messages: a tap beside the list closes it */}\n {open && <button type=\"button\" className=\"nb-scrim\" aria-label={t(\"close\")} onClick={onClose} />}\n {creating && onCreate && <NewTopicModal onClose={() => setCreating(false)} onCreate={onCreate} />}\n </>\n );\n}\n\n/** The place of a chat: the list of conversations, the conversation and what the\n * product puts beside them. `narrow` is for a side panel: the list lies over the\n * messages as on a phone, whatever the width of the window. */\nexport function ChatLayout({ narrow, children }: { narrow?: boolean; children: ReactNode }) {\n return <div className={`nb-app${narrow ? \" narrow\" : \"\"}`}>{children}</div>;\n}\n\n/** The dialog of a new topic: one field, Enter creates. */\nexport function NewTopicModal({ onClose, onCreate }: { onClose: () => void; onCreate: (title: string) => Promise<void> }) {\n const t = useKitT();\n const [title, setTitle] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const create = async () => {\n if (!title.trim() || pending) return;\n setPending(true);\n setError(null);\n try {\n await onCreate(title.trim());\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setPending(false);\n }\n };\n return (\n <Modal title={t(\"chat.newTopic\")} onClose={onClose} footer={<>\n <button className=\"btn ghost\" onClick={onClose}>{t(\"cancel\")}</button>\n <button className=\"btn primary\" disabled={!title.trim() || pending} onClick={create}>{t(\"create\")}</button>\n </>}>\n <div className=\"field\">\n <label htmlFor=\"topic-title\">{t(\"chat.topicTitle\")}</label>\n <input id=\"topic-title\" className=\"inp\" value={title} maxLength={120} onChange={(e) => setTitle(e.target.value)}\n onKeyDown={(e) => e.key === \"Enter\" && create()} />\n <div className=\"hint\">{t(\"chat.topicHint\")}</div>\n </div>\n {error && <div className=\"err-text\">{error}</div>}\n </Modal>\n );\n}\n","import { useState, type ReactNode } from \"react\";\nimport { Icon, type IconName } from \"../components/Icon\";\nimport { useOutside } from \"../components/ui\";\nimport { useKitT } from \"../i18n\";\n\n/** One of the ways an agent can look and talk; what it means only the product knows (R7). */\nexport interface AgentOption { key: string; label: string; icon: IconName }\n\n/** The round button of the agent: its icon, and the menu behind it. */\nexport function AgentButton({ icon, label, title, expanded, small, disabled, onClick }: {\n icon: IconName; label: string; title?: string; expanded?: boolean; small?: boolean; disabled?: boolean; onClick?: () => void;\n}) {\n return (\n <button type=\"button\" className={`agentbtn${small ? \" s\" : \"\"}`} disabled={disabled} aria-label={label} aria-expanded={expanded} title={title}\n // the menu closes on an outside mousedown; keep this click a toggle\n onMouseDown={(e) => expanded && e.stopPropagation()} onClick={onClick}>\n <Icon name={icon} size={small ? 15 : 18} />\n </button>\n );\n}\n\n/** The menu of the agent (FTR.NAB.CMN-0005 R15, design §6.6): its name and a\n * choice among the options of the product, as tiles with icons. The name is\n * saved on Enter and on leaving the field; a pick is saved at once. */\nexport function AgentMenu({ label, name, options, value, optionsLabel, hint, narrow, onRename, onPick, onClose }: {\n /** The name of the dialog for a screen reader. */\n label: string;\n name: string;\n options: AgentOption[];\n value: string;\n optionsLabel: ReactNode;\n hint?: ReactNode;\n /** A narrow place — a side panel: the options go in one column. */\n narrow?: boolean;\n onRename: (name: string) => void;\n onPick: (key: string) => void;\n /** Must keep its identity between renders. */\n onClose: () => void;\n}) {\n const t = useKitT();\n const [draft, setDraft] = useState(name);\n const ref = useOutside<HTMLDivElement>(true, onClose);\n const save = () => {\n const next = draft.trim();\n if (next && next !== name) onRename(next);\n };\n return (\n <div className={`agentmenu${narrow ? \" narrow\" : \"\"}`} ref={ref} role=\"dialog\" aria-label={label}>\n <div className=\"lab\">{t(\"agentName\")}</div>\n <input className=\"inp\" value={draft} maxLength={40} autoFocus aria-label={t(\"agentName\")}\n onChange={(e) => setDraft(e.target.value)} onBlur={save}\n onKeyDown={(e) => e.key === \"Enter\" && (e.target as HTMLInputElement).blur()} />\n <div className=\"lab\" style={{ marginTop: 14 }}>{optionsLabel}</div>\n <div className=\"agentoptions\">\n {options.map((o) => (\n <button key={o.key} type=\"button\" className={`agentoption${value === o.key ? \" on\" : \"\"}`} aria-pressed={value === o.key} onClick={() => onPick(o.key)}>\n <span className=\"ic\"><Icon name={o.icon} size={15} /></span>\n {o.label}\n </button>\n ))}\n </div>\n {hint && <div className=\"hint\" style={{ marginTop: 10 }}>{hint}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
|
package/dist/locales/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const resources: {
|
|
|
8
8
|
close: string;
|
|
9
9
|
delete: string;
|
|
10
10
|
remove: string;
|
|
11
|
+
agentName: string;
|
|
11
12
|
topbar: {
|
|
12
13
|
sections: string;
|
|
13
14
|
profile: string;
|
|
@@ -62,6 +63,7 @@ export declare const resources: {
|
|
|
62
63
|
close: string;
|
|
63
64
|
delete: string;
|
|
64
65
|
remove: string;
|
|
66
|
+
agentName: string;
|
|
65
67
|
topbar: {
|
|
66
68
|
sections: string;
|
|
67
69
|
profile: string;
|
|
@@ -116,6 +118,7 @@ export declare const resources: {
|
|
|
116
118
|
close: string;
|
|
117
119
|
delete: string;
|
|
118
120
|
remove: string;
|
|
121
|
+
agentName: string;
|
|
119
122
|
topbar: {
|
|
120
123
|
sections: string;
|
|
121
124
|
profile: string;
|
|
@@ -170,6 +173,7 @@ export declare const resources: {
|
|
|
170
173
|
close: string;
|
|
171
174
|
delete: string;
|
|
172
175
|
remove: string;
|
|
176
|
+
agentName: string;
|
|
173
177
|
topbar: {
|
|
174
178
|
sections: string;
|
|
175
179
|
profile: string;
|
|
@@ -224,6 +228,7 @@ export declare const resources: {
|
|
|
224
228
|
close: string;
|
|
225
229
|
delete: string;
|
|
226
230
|
remove: string;
|
|
231
|
+
agentName: string;
|
|
227
232
|
topbar: {
|
|
228
233
|
sections: string;
|
|
229
234
|
profile: string;
|
package/dist/locales.js
CHANGED
|
@@ -9,6 +9,7 @@ var t = {
|
|
|
9
9
|
close: "Close",
|
|
10
10
|
delete: "Delete",
|
|
11
11
|
remove: "Remove",
|
|
12
|
+
agentName: "Agent name",
|
|
12
13
|
topbar: {
|
|
13
14
|
sections: "Sections",
|
|
14
15
|
profile: "Profile"
|
|
@@ -63,6 +64,7 @@ var t = {
|
|
|
63
64
|
close: "Закрыть",
|
|
64
65
|
delete: "Удалить",
|
|
65
66
|
remove: "Убрать",
|
|
67
|
+
agentName: "Имя агента",
|
|
66
68
|
topbar: {
|
|
67
69
|
sections: "Разделы",
|
|
68
70
|
profile: "Профиль"
|
|
@@ -117,6 +119,7 @@ var t = {
|
|
|
117
119
|
close: "Schließen",
|
|
118
120
|
delete: "Löschen",
|
|
119
121
|
remove: "Entfernen",
|
|
122
|
+
agentName: "Name des Agenten",
|
|
120
123
|
topbar: {
|
|
121
124
|
sections: "Bereiche",
|
|
122
125
|
profile: "Profil"
|
|
@@ -171,6 +174,7 @@ var t = {
|
|
|
171
174
|
close: "Cerrar",
|
|
172
175
|
delete: "Eliminar",
|
|
173
176
|
remove: "Quitar",
|
|
177
|
+
agentName: "Nombre del agente",
|
|
174
178
|
topbar: {
|
|
175
179
|
sections: "Secciones",
|
|
176
180
|
profile: "Perfil"
|
|
@@ -225,6 +229,7 @@ var t = {
|
|
|
225
229
|
close: "关闭",
|
|
226
230
|
delete: "删除",
|
|
227
231
|
remove: "移除",
|
|
232
|
+
agentName: "智能体名称",
|
|
228
233
|
topbar: {
|
|
229
234
|
sections: "栏目",
|
|
230
235
|
profile: "个人资料"
|
package/dist/locales.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","topbar","chat","loading","cancel","create","close","remove","topbar","chat","loading","cancel","create","close","remove","topbar","chat","loading","cancel","create","close","remove","topbar","chat","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n }\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n }\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n }\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n }\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n }\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAa6B,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
|
|
1
|
+
{"version":3,"file":"locales.js","names":["loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","loading","cancel","create","close","remove","agentName","topbar","chat","UIKIT_NS","resources","\"delete\"","\"sections\"","\"profile\"","\"title\"","\"conversations\"","\"conversation\"","\"topics\"","\"archive\"","\"noTopics\"","\"newTopic\"","\"topicTitle\"","\"topicHint\"","\"loadOlder\"","\"emptyTitle\"","\"placeholder\"","\"send\"","\"attach\"","\"typing\"","\"moreSteps\"","\"hideSteps\"","\"unread\"","\"retry\"","\"tooLarge\"","\"stop\"","\"voice\"","\"hold\"","\"recording\"","\"review\"","\"notRecognized\"","\"micDenied\"","\"unsupported\"","\"confirm\"","\"text\"","\"approve\"","\"reject\"","\"wait\"","\"starting\"","\"queued\""],"sources":["../src/locales/en.json","../src/locales/ru.json","../src/locales/de.json","../src/locales/es.json","../src/locales/zh.json","../src/locales/index.ts"],"sourcesContent":["{\n \"loading\": \"Loading…\",\n \"cancel\": \"Cancel\",\n \"create\": \"Create\",\n \"close\": \"Close\",\n \"delete\": \"Delete\",\n \"remove\": \"Remove\",\n \"agentName\": \"Agent name\",\n \"topbar\": {\n \"sections\": \"Sections\",\n \"profile\": \"Profile\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversations\",\n \"conversation\": \"Conversation\",\n \"topics\": \"Topics\",\n \"archive\": \"Archive\",\n \"noTopics\": \"No topics yet\",\n \"newTopic\": \"New topic\",\n \"topicTitle\": \"Topic\",\n \"topicHint\": \"A topic has its own history and the same memory and space.\",\n \"loadOlder\": \"Earlier messages\",\n \"emptyTitle\": \"Hi, I am {name}\",\n \"placeholder\": \"Message {name}…\",\n \"send\": \"Send\",\n \"attach\": \"Attach files\",\n \"typing\": \"The agent is typing\",\n \"moreSteps\": \"{count, plural, one {# more step} other {# more steps}}\",\n \"hideSteps\": \"Hide steps\",\n \"unread\": \"{count, plural, one {# unread answer} other {# unread answers}}\",\n \"retry\": \"Retry\",\n \"tooLarge\": \"The file is too large.\",\n \"stop\": \"Stop\",\n \"voice\": {\n \"hold\": \"Hold to record\",\n \"stop\": \"Stop recording\",\n \"recording\": \"Recording… {seconds} s\",\n \"review\": \"Check the transcript before sending\",\n \"notRecognized\": \"The speech was not recognized\",\n \"micDenied\": \"No access to the microphone\",\n \"unsupported\": \"Voice input is not supported in this browser\"\n },\n \"confirm\": {\n \"title\": \"Confirm the action\",\n \"text\": \"The agent wants to perform: {action}\",\n \"approve\": \"Execute\",\n \"reject\": \"Reject\"\n },\n \"wait\": {\n \"starting\": \"The agent is starting…\",\n \"queued\": \"{count, plural, =0 {In the queue · you are next} one {In the queue · # ahead of you} other {In the queue · # ahead of you}}\"\n }\n }\n}\n","{\n \"loading\": \"Загрузка…\",\n \"cancel\": \"Отмена\",\n \"create\": \"Создать\",\n \"close\": \"Закрыть\",\n \"delete\": \"Удалить\",\n \"remove\": \"Убрать\",\n \"agentName\": \"Имя агента\",\n \"topbar\": {\n \"sections\": \"Разделы\",\n \"profile\": \"Профиль\"\n },\n \"chat\": {\n \"title\": \"Чат\",\n \"conversations\": \"Разговоры\",\n \"conversation\": \"Разговор\",\n \"topics\": \"Темы\",\n \"archive\": \"Архив\",\n \"noTopics\": \"Тем пока нет\",\n \"newTopic\": \"Новая тема\",\n \"topicTitle\": \"Тема\",\n \"topicHint\": \"У темы своя история, а память и пространство — те же.\",\n \"loadOlder\": \"Более ранние сообщения\",\n \"emptyTitle\": \"Привет, я {name}\",\n \"placeholder\": \"Сообщение для {name}…\",\n \"send\": \"Отправить\",\n \"attach\": \"Прикрепить файлы\",\n \"typing\": \"Агент печатает\",\n \"moreSteps\": \"{count, plural, one {ещё # шаг} few {ещё # шага} many {ещё # шагов} other {ещё # шага}}\",\n \"hideSteps\": \"Скрыть шаги\",\n \"unread\": \"{count, plural, one {# непрочитанный ответ} few {# непрочитанных ответа} many {# непрочитанных ответов} other {# непрочитанных ответа}}\",\n \"retry\": \"Повторить\",\n \"tooLarge\": \"Файл слишком большой.\",\n \"stop\": \"Остановить\",\n \"voice\": {\n \"hold\": \"Удерживайте для записи\",\n \"stop\": \"Остановить запись\",\n \"recording\": \"Запись… {seconds} с\",\n \"review\": \"Проверьте расшифровку перед отправкой\",\n \"notRecognized\": \"Речь не распознана\",\n \"micDenied\": \"Нет доступа к микрофону\",\n \"unsupported\": \"Голосовой ввод не поддерживается этим браузером\"\n },\n \"confirm\": {\n \"title\": \"Подтвердите действие\",\n \"text\": \"Агент хочет выполнить: {action}\",\n \"approve\": \"Выполнить\",\n \"reject\": \"Отклонить\"\n },\n \"wait\": {\n \"starting\": \"Агент запускается…\",\n \"queued\": \"{count, plural, =0 {В очереди · вы следующий} other {В очереди · перед вами #}}\"\n }\n }\n}\n","{\n \"loading\": \"Wird geladen…\",\n \"cancel\": \"Abbrechen\",\n \"create\": \"Erstellen\",\n \"close\": \"Schließen\",\n \"delete\": \"Löschen\",\n \"remove\": \"Entfernen\",\n \"agentName\": \"Name des Agenten\",\n \"topbar\": {\n \"sections\": \"Bereiche\",\n \"profile\": \"Profil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Gespräche\",\n \"conversation\": \"Gespräch\",\n \"topics\": \"Themen\",\n \"archive\": \"Archiv\",\n \"noTopics\": \"Noch keine Themen\",\n \"newTopic\": \"Neues Thema\",\n \"topicTitle\": \"Thema\",\n \"topicHint\": \"Ein Thema hat einen eigenen Verlauf, aber dasselbe Gedächtnis und denselben Arbeitsbereich.\",\n \"loadOlder\": \"Frühere Nachrichten\",\n \"emptyTitle\": \"Hallo, ich bin {name}\",\n \"placeholder\": \"Nachricht an {name}…\",\n \"send\": \"Senden\",\n \"attach\": \"Dateien anhängen\",\n \"typing\": \"Der Agent schreibt\",\n \"moreSteps\": \"{count, plural, one {# weiterer Schritt} other {# weitere Schritte}}\",\n \"hideSteps\": \"Schritte ausblenden\",\n \"unread\": \"{count, plural, one {# ungelesene Antwort} other {# ungelesene Antworten}}\",\n \"retry\": \"Wiederholen\",\n \"tooLarge\": \"Die Datei ist zu groß.\",\n \"stop\": \"Stoppen\",\n \"voice\": {\n \"hold\": \"Zum Aufnehmen gedrückt halten\",\n \"stop\": \"Aufnahme beenden\",\n \"recording\": \"Aufnahme… {seconds} s\",\n \"review\": \"Prüfen Sie die Transkription vor dem Senden\",\n \"notRecognized\": \"Die Sprache wurde nicht erkannt\",\n \"micDenied\": \"Kein Zugriff auf das Mikrofon\",\n \"unsupported\": \"Spracheingabe wird von diesem Browser nicht unterstützt\"\n },\n \"confirm\": {\n \"title\": \"Aktion bestätigen\",\n \"text\": \"Der Agent möchte ausführen: {action}\",\n \"approve\": \"Ausführen\",\n \"reject\": \"Ablehnen\"\n },\n \"wait\": {\n \"starting\": \"Der Agent startet…\",\n \"queued\": \"{count, plural, =0 {In der Warteschlange · Sie sind als Nächstes dran} other {In der Warteschlange · # vor Ihnen}}\"\n }\n }\n}\n","{\n \"loading\": \"Cargando…\",\n \"cancel\": \"Cancelar\",\n \"create\": \"Crear\",\n \"close\": \"Cerrar\",\n \"delete\": \"Eliminar\",\n \"remove\": \"Quitar\",\n \"agentName\": \"Nombre del agente\",\n \"topbar\": {\n \"sections\": \"Secciones\",\n \"profile\": \"Perfil\"\n },\n \"chat\": {\n \"title\": \"Chat\",\n \"conversations\": \"Conversaciones\",\n \"conversation\": \"Conversación\",\n \"topics\": \"Temas\",\n \"archive\": \"Archivo\",\n \"noTopics\": \"Aún no hay temas\",\n \"newTopic\": \"Nuevo tema\",\n \"topicTitle\": \"Tema\",\n \"topicHint\": \"Un tema tiene su propio historial y la misma memoria y espacio.\",\n \"loadOlder\": \"Mensajes anteriores\",\n \"emptyTitle\": \"Hola, soy {name}\",\n \"placeholder\": \"Mensaje para {name}…\",\n \"send\": \"Enviar\",\n \"attach\": \"Adjuntar archivos\",\n \"typing\": \"El agente está escribiendo\",\n \"moreSteps\": \"{count, plural, one {# paso más} other {# pasos más}}\",\n \"hideSteps\": \"Ocultar pasos\",\n \"unread\": \"{count, plural, one {# respuesta sin leer} other {# respuestas sin leer}}\",\n \"retry\": \"Reintentar\",\n \"tooLarge\": \"El archivo es demasiado grande.\",\n \"stop\": \"Detener\",\n \"voice\": {\n \"hold\": \"Mantenga pulsado para grabar\",\n \"stop\": \"Detener la grabación\",\n \"recording\": \"Grabando… {seconds} s\",\n \"review\": \"Revise la transcripción antes de enviar\",\n \"notRecognized\": \"No se reconoció la voz\",\n \"micDenied\": \"Sin acceso al micrófono\",\n \"unsupported\": \"Este navegador no admite la entrada de voz\"\n },\n \"confirm\": {\n \"title\": \"Confirme la acción\",\n \"text\": \"El agente quiere ejecutar: {action}\",\n \"approve\": \"Ejecutar\",\n \"reject\": \"Rechazar\"\n },\n \"wait\": {\n \"starting\": \"El agente se está iniciando…\",\n \"queued\": \"{count, plural, =0 {En cola · usted es el siguiente} other {En cola · # por delante}}\"\n }\n }\n}\n","{\n \"loading\": \"加载中…\",\n \"cancel\": \"取消\",\n \"create\": \"创建\",\n \"close\": \"关闭\",\n \"delete\": \"删除\",\n \"remove\": \"移除\",\n \"agentName\": \"智能体名称\",\n \"topbar\": {\n \"sections\": \"栏目\",\n \"profile\": \"个人资料\"\n },\n \"chat\": {\n \"title\": \"聊天\",\n \"conversations\": \"对话\",\n \"conversation\": \"对话\",\n \"topics\": \"话题\",\n \"archive\": \"归档\",\n \"noTopics\": \"暂无话题\",\n \"newTopic\": \"新话题\",\n \"topicTitle\": \"话题\",\n \"topicHint\": \"话题有独立的历史记录,记忆和空间与主对话相同。\",\n \"loadOlder\": \"更早的消息\",\n \"emptyTitle\": \"你好,我是 {name}\",\n \"placeholder\": \"给 {name} 发消息…\",\n \"send\": \"发送\",\n \"attach\": \"附加文件\",\n \"typing\": \"智能体正在输入\",\n \"moreSteps\": \"{count, plural, other {另外 # 个步骤}}\",\n \"hideSteps\": \"隐藏步骤\",\n \"unread\": \"{count} 条未读回复\",\n \"retry\": \"重试\",\n \"tooLarge\": \"文件太大。\",\n \"stop\": \"停止\",\n \"voice\": {\n \"hold\": \"按住录音\",\n \"stop\": \"停止录音\",\n \"recording\": \"录音中… {seconds} 秒\",\n \"review\": \"发送前请检查转写文本\",\n \"notRecognized\": \"未能识别语音\",\n \"micDenied\": \"无法访问麦克风\",\n \"unsupported\": \"此浏览器不支持语音输入\"\n },\n \"confirm\": {\n \"title\": \"确认操作\",\n \"text\": \"代理想要执行:{action}\",\n \"approve\": \"执行\",\n \"reject\": \"拒绝\"\n },\n \"wait\": {\n \"starting\": \"代理正在启动…\",\n \"queued\": \"{count, plural, =0 {排队中 · 您是下一位} other {排队中 · 前面还有 # 位}}\"\n }\n }\n}\n","import en from \"./en.json\";\nimport ru from \"./ru.json\";\nimport de from \"./de.json\";\nimport es from \"./es.json\";\nimport zh from \"./zh.json\";\n\n/** Strings of the components in the five languages of the products. A product adds\n * them to its i18next instance under the namespace `uikit`. */\nexport const resources = { en, ru, de, es, zh };\nexport type KitLanguage = keyof typeof resources;\nexport { UIKIT_NS } from \"../i18n\";\n"],"mappings":";;;AKQA,IAAaiC,IAAY;CAAE,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;CAAI,IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAA;AAAG"}
|
package/dist/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "1.0.1",
|
|
3
3
|
"classes": [
|
|
4
4
|
"a",
|
|
5
5
|
"action",
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
"acts",
|
|
8
8
|
"admin",
|
|
9
9
|
"agent",
|
|
10
|
+
"agentbtn",
|
|
11
|
+
"agentmenu",
|
|
12
|
+
"agentoption",
|
|
13
|
+
"agentoptions",
|
|
10
14
|
"amber",
|
|
11
15
|
"app",
|
|
12
16
|
"arch",
|
|
@@ -148,6 +152,10 @@
|
|
|
148
152
|
],
|
|
149
153
|
"roots": [
|
|
150
154
|
"admin",
|
|
155
|
+
"agentbtn",
|
|
156
|
+
"agentmenu",
|
|
157
|
+
"agentoption",
|
|
158
|
+
"agentoptions",
|
|
151
159
|
"app",
|
|
152
160
|
"avatar",
|
|
153
161
|
"brand",
|
package/dist/styles.css
CHANGED
|
@@ -1281,6 +1281,18 @@ select.inp.inherit {
|
|
|
1281
1281
|
.panel{position:fixed;inset:0;z-index:40;max-height:none;border-radius:0;border:0}
|
|
1282
1282
|
.kvrow{grid-template-columns:minmax(0,1fr)}}
|
|
1283
1283
|
|
|
1284
|
+
/* The agent: its round button and its menu — the name and the options of the product as tiles. */
|
|
1285
|
+
.agentbtn{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;color:#fff;background:linear-gradient(135deg,var(--violet),#12A876);border:0;cursor:pointer;box-shadow:0 0 0 3px var(--violet-soft);flex:none}
|
|
1286
|
+
.agentbtn.s{width:28px;height:28px;box-shadow:none}
|
|
1287
|
+
.agentmenu{position:absolute;top:62px;left:16px;width:340px;max-width:calc(100% - 32px);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-l);box-shadow:var(--shadow-l, 0 12px 32px rgba(0,0,0,.18));padding:14px;z-index:20}
|
|
1288
|
+
.agentmenu .lab{font-size:12px;color:var(--muted);margin:0 0 6px}
|
|
1289
|
+
.agentoptions{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
|
1290
|
+
/* a narrow place — a side panel: the tiles go in one column, or a long label would not fit */
|
|
1291
|
+
.agentmenu.narrow .agentoptions{grid-template-columns:1fr}
|
|
1292
|
+
.agentoption{display:flex;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--border);border-radius:var(--r-m);font-size:14px;background:var(--surface);color:var(--text)}
|
|
1293
|
+
.agentoption.on{border-color:var(--violet);box-shadow:0 0 0 1px var(--violet);color:var(--violet-text)}
|
|
1294
|
+
.agentoption .ic{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;color:#fff;background:linear-gradient(135deg,var(--violet),#12A876);flex:none}
|
|
1295
|
+
|
|
1284
1296
|
/* A long unbreakable line — a path in a tool step — never widens the list of messages. */
|
|
1285
1297
|
.msgs{overflow-x:hidden}
|
|
1286
1298
|
.m{min-width:0}
|
package/package.json
CHANGED