@twentyfirstmedia/ui-core 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/admin.d.ts.map +1 -1
- package/dist/components/admin.js +95 -71
- package/dist/components/admin.js.map +1 -1
- package/dist/components/agents.d.ts.map +1 -1
- package/dist/components/agents.js +49 -35
- package/dist/components/agents.js.map +1 -1
- package/dist/components/app-chrome.d.ts.map +1 -1
- package/dist/components/app-chrome.js +6 -2
- package/dist/components/app-chrome.js.map +1 -1
- package/dist/components/approvals.d.ts.map +1 -1
- package/dist/components/approvals.js +22 -18
- package/dist/components/approvals.js.map +1 -1
- package/dist/components/building-blocks.d.ts.map +1 -1
- package/dist/components/building-blocks.js +6 -2
- package/dist/components/building-blocks.js.map +1 -1
- package/dist/components/charts.d.ts.map +1 -1
- package/dist/components/charts.js +20 -10
- package/dist/components/charts.js.map +1 -1
- package/dist/components/chat.d.ts.map +1 -1
- package/dist/components/chat.js +31 -19
- package/dist/components/chat.js.map +1 -1
- package/dist/components/commerce.d.ts +2 -2
- package/dist/components/commerce.d.ts.map +1 -1
- package/dist/components/commerce.js +45 -31
- package/dist/components/commerce.js.map +1 -1
- package/dist/components/data-display.d.ts +5 -9
- package/dist/components/data-display.d.ts.map +1 -1
- package/dist/components/data-display.js +34 -35
- package/dist/components/data-display.js.map +1 -1
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +15 -10
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/developer.d.ts.map +1 -1
- package/dist/components/developer.js +20 -11
- package/dist/components/developer.js.map +1 -1
- package/dist/components/feedback.d.ts.map +1 -1
- package/dist/components/feedback.js +12 -6
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/form.d.ts +2 -1
- package/dist/components/form.d.ts.map +1 -1
- package/dist/components/form.js +12 -9
- package/dist/components/form.js.map +1 -1
- package/dist/components/forms.d.ts +2 -1
- package/dist/components/forms.d.ts.map +1 -1
- package/dist/components/forms.js +92 -42
- package/dist/components/forms.js.map +1 -1
- package/dist/components/foundation.d.ts +5 -2
- package/dist/components/foundation.d.ts.map +1 -1
- package/dist/components/foundation.js +15 -12
- package/dist/components/foundation.js.map +1 -1
- package/dist/components/inputs.d.ts.map +1 -1
- package/dist/components/inputs.js +3 -1
- package/dist/components/inputs.js.map +1 -1
- package/dist/components/mail.d.ts.map +1 -1
- package/dist/components/mail.js +15 -10
- package/dist/components/mail.js.map +1 -1
- package/dist/components/media.d.ts.map +1 -1
- package/dist/components/media.js +39 -18
- package/dist/components/media.js.map +1 -1
- package/dist/components/navigation.d.ts.map +1 -1
- package/dist/components/navigation.js +21 -9
- package/dist/components/navigation.js.map +1 -1
- package/dist/components/operations.d.ts.map +1 -1
- package/dist/components/operations.js +37 -27
- package/dist/components/operations.js.map +1 -1
- package/dist/components/previews.d.ts.map +1 -1
- package/dist/components/previews.js +14 -10
- package/dist/components/previews.js.map +1 -1
- package/dist/components/primitives.d.ts.map +1 -1
- package/dist/components/primitives.js +4 -1
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/real-estate.d.ts.map +1 -1
- package/dist/components/real-estate.js +43 -28
- package/dist/components/real-estate.js.map +1 -1
- package/dist/components/rich-text-editor.d.ts.map +1 -1
- package/dist/components/rich-text-editor.js +18 -15
- package/dist/components/rich-text-editor.js.map +1 -1
- package/dist/components/select-menu.d.ts.map +1 -1
- package/dist/components/select-menu.js +4 -1
- package/dist/components/select-menu.js.map +1 -1
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +8 -3
- package/dist/components/shell.js.map +1 -1
- package/dist/components/site.d.ts.map +1 -1
- package/dist/components/site.js +17 -13
- package/dist/components/site.js.map +1 -1
- package/dist/components/types.d.ts +102 -3
- package/dist/components/types.d.ts.map +1 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +50 -34
- package/dist/components/workspace.js.map +1 -1
- package/dist/context.d.ts +39 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +76 -0
- package/dist/context.js.map +1 -0
- package/dist/format.d.ts +33 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +75 -10
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +18 -11
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +11 -18
- package/dist/provider.js.map +1 -1
- package/dist/strings.d.ts +503 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +537 -0
- package/dist/strings.js.map +1 -0
- package/package.json +1 -1
- package/src/components/admin.tsx +117 -93
- package/src/components/agents.tsx +55 -41
- package/src/components/app-chrome.tsx +6 -2
- package/src/components/approvals.tsx +26 -22
- package/src/components/building-blocks.tsx +6 -2
- package/src/components/charts.tsx +21 -11
- package/src/components/chat.tsx +45 -35
- package/src/components/commerce.tsx +61 -53
- package/src/components/data-display.tsx +38 -45
- package/src/components/data-table.tsx +20 -15
- package/src/components/developer.tsx +26 -15
- package/src/components/feedback.tsx +19 -7
- package/src/components/form.tsx +17 -9
- package/src/components/forms.tsx +131 -53
- package/src/components/foundation.tsx +23 -36
- package/src/components/inputs.tsx +4 -2
- package/src/components/mail.tsx +16 -11
- package/src/components/media.tsx +64 -21
- package/src/components/navigation.tsx +25 -13
- package/src/components/operations.tsx +40 -32
- package/src/components/previews.tsx +17 -15
- package/src/components/primitives.tsx +8 -5
- package/src/components/real-estate.tsx +55 -35
- package/src/components/rich-text-editor.tsx +20 -17
- package/src/components/select-menu.tsx +5 -2
- package/src/components/shell.tsx +8 -3
- package/src/components/site.tsx +18 -14
- package/src/components/types.ts +111 -3
- package/src/components/workspace.tsx +79 -60
- package/src/context.ts +112 -0
- package/src/format.ts +108 -15
- package/src/index.ts +43 -0
- package/src/provider.tsx +36 -40
- package/src/strings.ts +1500 -0
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
|
-
import {
|
|
5
|
+
import { useFormat, useStrings } from "../context.js";
|
|
6
|
+
import { AGENTS_STRINGS } from "../strings.js";
|
|
6
7
|
import { Icon } from "../Icon.js";
|
|
7
8
|
import { useControlled } from "../hooks.js";
|
|
8
9
|
import { AgentMark, TypingDots } from "./chat.js";
|
|
@@ -38,6 +39,7 @@ import type {
|
|
|
38
39
|
|
|
39
40
|
/* ── Agents ── */
|
|
40
41
|
export function AgentCard(p: AgentCardProps) {
|
|
42
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
41
43
|
return (
|
|
42
44
|
<div
|
|
43
45
|
className={cx("tf-agentcard", p.onClick && "click")}
|
|
@@ -53,7 +55,7 @@ export function AgentCard(p: AgentCardProps) {
|
|
|
53
55
|
{p.onChat && (
|
|
54
56
|
<IconButton
|
|
55
57
|
icon="mail"
|
|
56
|
-
label={
|
|
58
|
+
label={t.chatWith(p.name)}
|
|
57
59
|
size="sm"
|
|
58
60
|
onClick={(e) => {
|
|
59
61
|
e.stopPropagation();
|
|
@@ -67,9 +69,9 @@ export function AgentCard(p: AgentCardProps) {
|
|
|
67
69
|
dense
|
|
68
70
|
items={
|
|
69
71
|
[
|
|
70
|
-
[
|
|
71
|
-
[
|
|
72
|
-
[
|
|
72
|
+
[t.model, p.model],
|
|
73
|
+
[t.costToday, p.cost, true],
|
|
74
|
+
[t.lastAction, p.last],
|
|
73
75
|
].filter((r) => r[1] != null) as KeyValueItem[]
|
|
74
76
|
}
|
|
75
77
|
/>
|
|
@@ -104,6 +106,7 @@ export function AgentDetails(p: AgentDetailsProps) {
|
|
|
104
106
|
);
|
|
105
107
|
}
|
|
106
108
|
export function ChatList(p: ChatListProps) {
|
|
109
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
107
110
|
const q = React.useState("");
|
|
108
111
|
const groups = (p.groups || [])
|
|
109
112
|
.map((g) =>
|
|
@@ -118,7 +121,7 @@ export function ChatList(p: ChatListProps) {
|
|
|
118
121
|
return (
|
|
119
122
|
<div className="tf-chatlist">
|
|
120
123
|
<SearchField
|
|
121
|
-
placeholder={p.searchPlaceholder ||
|
|
124
|
+
placeholder={p.searchPlaceholder || t.searchChats}
|
|
122
125
|
value={q[0]}
|
|
123
126
|
onChange={(e) => {
|
|
124
127
|
q[1](e.target.value);
|
|
@@ -134,7 +137,7 @@ export function ChatList(p: ChatListProps) {
|
|
|
134
137
|
padding: 12,
|
|
135
138
|
}}
|
|
136
139
|
>
|
|
137
|
-
{
|
|
140
|
+
{t.noChatsMatch}
|
|
138
141
|
</p>
|
|
139
142
|
) : (
|
|
140
143
|
groups.map((g) => (
|
|
@@ -191,10 +194,11 @@ export function ChatWorkspace(p: ChatWorkspaceProps) {
|
|
|
191
194
|
);
|
|
192
195
|
}
|
|
193
196
|
export function SearchHits(p: SearchHitsProps) {
|
|
197
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
194
198
|
return (
|
|
195
199
|
<div className="tf-hits">
|
|
196
200
|
{(p.items || []).length === 0 ? (
|
|
197
|
-
<EmptyState icon="search" title=
|
|
201
|
+
<EmptyState icon="search" title={t.nothingFound} text={p.emptyText} />
|
|
198
202
|
) : (
|
|
199
203
|
p.items.map((x) => {
|
|
200
204
|
const parts = String(x.text).split(
|
|
@@ -225,14 +229,16 @@ export function SearchHits(p: SearchHitsProps) {
|
|
|
225
229
|
);
|
|
226
230
|
}
|
|
227
231
|
export function ThinkingLine(p: ThinkingLineProps) {
|
|
232
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
228
233
|
return (
|
|
229
234
|
<div className="tf-thinking" role="status">
|
|
230
235
|
<TypingDots />
|
|
231
|
-
<span>{p.text ||
|
|
236
|
+
<span>{p.text || t.thinking}</span>
|
|
232
237
|
</div>
|
|
233
238
|
);
|
|
234
239
|
}
|
|
235
240
|
export function FeedbackRating(p: FeedbackRatingProps) {
|
|
241
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
236
242
|
const v = useControlled<"up" | "down" | null>(p.value, null, (x) => {
|
|
237
243
|
if (x) p.onRate?.(x);
|
|
238
244
|
}),
|
|
@@ -242,7 +248,7 @@ export function FeedbackRating(p: FeedbackRatingProps) {
|
|
|
242
248
|
return (
|
|
243
249
|
<span className="tf-feedback-done">
|
|
244
250
|
<Icon name="check" size={13} />
|
|
245
|
-
{p.thanks ||
|
|
251
|
+
{p.thanks || t.thanksNoted}
|
|
246
252
|
</span>
|
|
247
253
|
);
|
|
248
254
|
return (
|
|
@@ -259,7 +265,7 @@ export function FeedbackRating(p: FeedbackRatingProps) {
|
|
|
259
265
|
type="button"
|
|
260
266
|
className={cx("tf-msg-act", v[0] === "up" && "on")}
|
|
261
267
|
aria-pressed={v[0] === "up"}
|
|
262
|
-
aria-label=
|
|
268
|
+
aria-label={t.good}
|
|
263
269
|
onClick={() => {
|
|
264
270
|
v[1]("up");
|
|
265
271
|
if (!p.askOnUp) {
|
|
@@ -274,7 +280,7 @@ export function FeedbackRating(p: FeedbackRatingProps) {
|
|
|
274
280
|
type="button"
|
|
275
281
|
className={cx("tf-msg-act", v[0] === "down" && "on")}
|
|
276
282
|
aria-pressed={v[0] === "down"}
|
|
277
|
-
aria-label=
|
|
283
|
+
aria-label={t.notGood}
|
|
278
284
|
onClick={() => {
|
|
279
285
|
v[1]("down");
|
|
280
286
|
}}
|
|
@@ -294,14 +300,14 @@ export function FeedbackRating(p: FeedbackRatingProps) {
|
|
|
294
300
|
<input
|
|
295
301
|
className="tf-input"
|
|
296
302
|
autoFocus
|
|
297
|
-
placeholder={p.placeholder ||
|
|
303
|
+
placeholder={p.placeholder || t.whatShouldBeDifferent}
|
|
298
304
|
value={c[0]}
|
|
299
305
|
onChange={(e) => {
|
|
300
306
|
c[1](e.target.value);
|
|
301
307
|
}}
|
|
302
308
|
/>
|
|
303
309
|
<Button type="submit" size="sm">
|
|
304
|
-
{
|
|
310
|
+
{t.send}
|
|
305
311
|
</Button>
|
|
306
312
|
</form>
|
|
307
313
|
)}
|
|
@@ -341,6 +347,7 @@ export function ActivityFeed(p: ActivityFeedProps) {
|
|
|
341
347
|
);
|
|
342
348
|
}
|
|
343
349
|
export function DailyBriefing(p: DailyBriefingProps) {
|
|
350
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
344
351
|
return (
|
|
345
352
|
<div className="tf-briefing">
|
|
346
353
|
<div className="tf-briefing-head">
|
|
@@ -364,7 +371,7 @@ export function DailyBriefing(p: DailyBriefingProps) {
|
|
|
364
371
|
padding: 0,
|
|
365
372
|
}}
|
|
366
373
|
>
|
|
367
|
-
{p.attentionTitle ||
|
|
374
|
+
{p.attentionTitle || t.needsYou}
|
|
368
375
|
</span>
|
|
369
376
|
{p.attention.map((a, i) => (
|
|
370
377
|
<button key={i} type="button" className="tf-briefing-item" onClick={a.onClick}>
|
|
@@ -388,7 +395,7 @@ export function DailyBriefing(p: DailyBriefingProps) {
|
|
|
388
395
|
padding: 0,
|
|
389
396
|
}}
|
|
390
397
|
>
|
|
391
|
-
{p.suggestionsTitle ||
|
|
398
|
+
{p.suggestionsTitle || t.suggestions}
|
|
392
399
|
</span>
|
|
393
400
|
<ul className="tf-briefing-sugg">
|
|
394
401
|
{p.suggestions.map((s, i) => (
|
|
@@ -401,24 +408,25 @@ export function DailyBriefing(p: DailyBriefingProps) {
|
|
|
401
408
|
);
|
|
402
409
|
}
|
|
403
410
|
export function BudgetStop(p: BudgetStopProps) {
|
|
411
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
412
|
+
const { formatMoney } = useFormat();
|
|
404
413
|
return (
|
|
405
414
|
<div className="tf-budgetstop">
|
|
406
415
|
<Alert
|
|
407
416
|
tone="danger"
|
|
408
|
-
title={p.title ||
|
|
417
|
+
title={p.title || t.budgetUsedUp}
|
|
409
418
|
action={
|
|
410
419
|
p.onRaise && (
|
|
411
420
|
<Button size="sm" variant="secondary" onClick={p.onRaise}>
|
|
412
|
-
{p.actionLabel ||
|
|
421
|
+
{p.actionLabel || t.raiseBudget}
|
|
413
422
|
</Button>
|
|
414
423
|
)
|
|
415
424
|
}
|
|
416
425
|
>
|
|
417
|
-
{p.text ||
|
|
418
|
-
"Everything is kept. Agents continue where they stopped once the budget allows it."}
|
|
426
|
+
{p.text || t.budgetText}
|
|
419
427
|
</Alert>
|
|
420
428
|
<Meter
|
|
421
|
-
label=
|
|
429
|
+
label={t.spentThisMonth}
|
|
422
430
|
value={p.spent}
|
|
423
431
|
max={p.budget}
|
|
424
432
|
text={formatMoney(p.spent) + " / " + formatMoney(p.budget)}
|
|
@@ -428,8 +436,8 @@ export function BudgetStop(p: BudgetStopProps) {
|
|
|
428
436
|
<KeyValue
|
|
429
437
|
dense
|
|
430
438
|
items={[
|
|
431
|
-
[
|
|
432
|
-
[
|
|
439
|
+
[t.paused, p.paused],
|
|
440
|
+
[t.stillRunning, p.running || t.nothing],
|
|
433
441
|
]}
|
|
434
442
|
/>
|
|
435
443
|
)}
|
|
@@ -437,6 +445,7 @@ export function BudgetStop(p: BudgetStopProps) {
|
|
|
437
445
|
);
|
|
438
446
|
}
|
|
439
447
|
export function MemoryViewer(p: MemoryViewerProps) {
|
|
448
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
440
449
|
const q = React.useState(""),
|
|
441
450
|
scope = React.useState<string | null>(null);
|
|
442
451
|
const scopes: string[] = [];
|
|
@@ -452,7 +461,7 @@ export function MemoryViewer(p: MemoryViewerProps) {
|
|
|
452
461
|
<div className="tf-memory">
|
|
453
462
|
<div className="tf-filterbar">
|
|
454
463
|
<SearchField
|
|
455
|
-
placeholder=
|
|
464
|
+
placeholder={t.searchMemory}
|
|
456
465
|
value={q[0]}
|
|
457
466
|
onChange={(e) => {
|
|
458
467
|
q[1](e.target.value);
|
|
@@ -475,7 +484,7 @@ export function MemoryViewer(p: MemoryViewerProps) {
|
|
|
475
484
|
))}
|
|
476
485
|
</div>
|
|
477
486
|
{list.length === 0 ? (
|
|
478
|
-
<p className="tf-card-desc">{
|
|
487
|
+
<p className="tf-card-desc">{t.nothingRemembered}</p>
|
|
479
488
|
) : (
|
|
480
489
|
list.map((m) => (
|
|
481
490
|
<div key={m.id} className="tf-memitem">
|
|
@@ -497,7 +506,7 @@ export function MemoryViewer(p: MemoryViewerProps) {
|
|
|
497
506
|
{p.onEdit && (
|
|
498
507
|
<IconButton
|
|
499
508
|
icon="edit"
|
|
500
|
-
label=
|
|
509
|
+
label={t.edit}
|
|
501
510
|
size="sm"
|
|
502
511
|
variant="ghost"
|
|
503
512
|
onClick={() => {
|
|
@@ -508,7 +517,7 @@ export function MemoryViewer(p: MemoryViewerProps) {
|
|
|
508
517
|
{p.onDelete && (
|
|
509
518
|
<IconButton
|
|
510
519
|
icon="trash"
|
|
511
|
-
label=
|
|
520
|
+
label={t.forget}
|
|
512
521
|
size="sm"
|
|
513
522
|
variant="ghost"
|
|
514
523
|
onClick={() => {
|
|
@@ -525,6 +534,7 @@ export function MemoryViewer(p: MemoryViewerProps) {
|
|
|
525
534
|
);
|
|
526
535
|
}
|
|
527
536
|
export function OverrideDiff(p: OverrideDiffProps) {
|
|
537
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
528
538
|
const a = String(p.before || "").split("\n"),
|
|
529
539
|
b = String(p.after || "").split("\n"),
|
|
530
540
|
rows = [];
|
|
@@ -561,12 +571,12 @@ export function OverrideDiff(p: OverrideDiffProps) {
|
|
|
561
571
|
>
|
|
562
572
|
{p.onDiscard && (
|
|
563
573
|
<Button size="sm" variant="ghost" onClick={p.onDiscard}>
|
|
564
|
-
{p.discardLabel ||
|
|
574
|
+
{p.discardLabel || t.discardOverride}
|
|
565
575
|
</Button>
|
|
566
576
|
)}
|
|
567
577
|
{p.onPromote && (
|
|
568
578
|
<Button size="sm" variant="soft" icon="branch" onClick={p.onPromote}>
|
|
569
|
-
{p.promoteLabel ||
|
|
579
|
+
{p.promoteLabel || t.moveToCode}
|
|
570
580
|
</Button>
|
|
571
581
|
)}
|
|
572
582
|
</span>
|
|
@@ -590,6 +600,7 @@ const TRIGGER_ICON: Record<string, IconName> = {
|
|
|
590
600
|
mail: "mail",
|
|
591
601
|
};
|
|
592
602
|
export function TriggerList(p: TriggerListProps) {
|
|
603
|
+
const strings = useStrings(AGENTS_STRINGS);
|
|
593
604
|
return (
|
|
594
605
|
<div className="tf-triggers">
|
|
595
606
|
{(p.items || []).map((t) => (
|
|
@@ -616,11 +627,11 @@ export function TriggerList(p: TriggerListProps) {
|
|
|
616
627
|
/>
|
|
617
628
|
)}
|
|
618
629
|
{p.onRun && (
|
|
619
|
-
<Tooltip label=
|
|
630
|
+
<Tooltip label={strings.runNow}>
|
|
620
631
|
<button
|
|
621
632
|
type="button"
|
|
622
633
|
className="tf-iconbtn tf-iconbtn-soft tf-iconbtn-sm"
|
|
623
|
-
aria-label=
|
|
634
|
+
aria-label={strings.runNow}
|
|
624
635
|
onClick={() => {
|
|
625
636
|
p.onRun?.(t);
|
|
626
637
|
}}
|
|
@@ -635,11 +646,12 @@ export function TriggerList(p: TriggerListProps) {
|
|
|
635
646
|
);
|
|
636
647
|
}
|
|
637
648
|
export function ScheduleCalendar(p: ScheduleCalendarProps) {
|
|
649
|
+
const { locale } = useFormat();
|
|
638
650
|
const from = p.from != null ? p.from : 6,
|
|
639
651
|
to = p.to != null ? p.to : 22,
|
|
640
652
|
hours = [];
|
|
641
653
|
for (let i = from; i < to; i++) hours.push(i);
|
|
642
|
-
const days = p.days || weekdays(),
|
|
654
|
+
const days = p.days || weekdays(locale),
|
|
643
655
|
rowH = 32;
|
|
644
656
|
return (
|
|
645
657
|
<div
|
|
@@ -729,6 +741,7 @@ export function OrgChart(p: OrgChartProps) {
|
|
|
729
741
|
);
|
|
730
742
|
}
|
|
731
743
|
export function VoiceMode(p: VoiceModeProps) {
|
|
744
|
+
const t = useStrings(AGENTS_STRINGS);
|
|
732
745
|
const st = p.state || "listening",
|
|
733
746
|
bars = [];
|
|
734
747
|
for (let i = 0; i < 24; i++) bars.push(i);
|
|
@@ -737,13 +750,14 @@ export function VoiceMode(p: VoiceModeProps) {
|
|
|
737
750
|
<AgentMark tint={p.tint || "lilac"} size={72} live={st !== "idle"} />
|
|
738
751
|
<b className="tf-voice-name">{p.name}</b>
|
|
739
752
|
<span className="tf-voice-state">
|
|
740
|
-
{p.stateLabel ||
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
753
|
+
{p.stateLabel ||
|
|
754
|
+
(st === "listening"
|
|
755
|
+
? t.listening
|
|
756
|
+
: st === "thinking"
|
|
757
|
+
? t.thinking
|
|
758
|
+
: st === "speaking"
|
|
759
|
+
? t.speaking
|
|
760
|
+
: t.paused)}
|
|
747
761
|
</span>
|
|
748
762
|
<div className="tf-voice-wave" aria-hidden>
|
|
749
763
|
{bars.map((b) => (
|
|
@@ -766,7 +780,7 @@ export function VoiceMode(p: VoiceModeProps) {
|
|
|
766
780
|
{p.onMute && (
|
|
767
781
|
<IconButton
|
|
768
782
|
icon={p.muted ? "x" : "user"}
|
|
769
|
-
label={p.muted ?
|
|
783
|
+
label={p.muted ? t.unmute : t.mute}
|
|
770
784
|
variant="soft"
|
|
771
785
|
size="lg"
|
|
772
786
|
onClick={p.onMute}
|
|
@@ -777,7 +791,7 @@ export function VoiceMode(p: VoiceModeProps) {
|
|
|
777
791
|
type="button"
|
|
778
792
|
className="tf-voice-end"
|
|
779
793
|
onClick={p.onEnd}
|
|
780
|
-
aria-label=
|
|
794
|
+
aria-label={t.endConversation}
|
|
781
795
|
>
|
|
782
796
|
<Icon name="x" size={20} />
|
|
783
797
|
</button>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
|
+
import { useStrings } from "../context.js";
|
|
4
|
+
import { APP_CHROME_STRINGS } from "../strings.js";
|
|
3
5
|
import { cx } from "../cx.js";
|
|
4
6
|
import { Icon } from "../Icon.js";
|
|
5
7
|
import { Badge, TintIcon } from "./foundation.js";
|
|
@@ -15,8 +17,9 @@ import type {
|
|
|
15
17
|
|
|
16
18
|
/* ── App chrome ── */
|
|
17
19
|
export function MobileTabBar(p: MobileTabBarProps) {
|
|
20
|
+
const t = useStrings(APP_CHROME_STRINGS);
|
|
18
21
|
return (
|
|
19
|
-
<nav className="tf-tabbar" aria-label={p.label ||
|
|
22
|
+
<nav className="tf-tabbar" aria-label={p.label || t.mainNavigation}>
|
|
20
23
|
{(p.items || []).map((it) => {
|
|
21
24
|
const on = it.id === p.active;
|
|
22
25
|
return (
|
|
@@ -123,6 +126,7 @@ export function ConfigPRSummary(p: ConfigPRSummaryProps) {
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
export function ModuleRegistry(p: ModuleRegistryProps) {
|
|
129
|
+
const t = useStrings(APP_CHROME_STRINGS);
|
|
126
130
|
return (
|
|
127
131
|
<div className="tf-modules">
|
|
128
132
|
{(p.items || []).map((m) => (
|
|
@@ -147,7 +151,7 @@ export function ModuleRegistry(p: ModuleRegistryProps) {
|
|
|
147
151
|
</span>
|
|
148
152
|
)}
|
|
149
153
|
{m.core ? (
|
|
150
|
-
<Tooltip label={p.coreLabel ||
|
|
154
|
+
<Tooltip label={p.coreLabel || t.coreModule}>
|
|
151
155
|
<span className="tf-module-lock" tabIndex={0}>
|
|
152
156
|
<Icon name="lock" size={14} />
|
|
153
157
|
</span>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
|
+
import { useStrings } from "../context.js";
|
|
5
|
+
import { APPROVALS_STRINGS } from "../strings.js";
|
|
4
6
|
import { Icon } from "../Icon.js";
|
|
5
7
|
import { StatusShape } from "./status.js";
|
|
6
8
|
import { Badge, Button } from "./foundation.js";
|
|
@@ -16,34 +18,35 @@ import type {
|
|
|
16
18
|
} from "./types.js";
|
|
17
19
|
|
|
18
20
|
/* ── Approval A–D ── */
|
|
19
|
-
const FAMILY: Record<RiskFamily,
|
|
20
|
-
money:
|
|
21
|
-
infra:
|
|
22
|
-
comms:
|
|
23
|
-
marketing:
|
|
24
|
-
apps:
|
|
25
|
-
legal:
|
|
21
|
+
const FAMILY: Record<RiskFamily, IconName> = {
|
|
22
|
+
money: "card",
|
|
23
|
+
infra: "server",
|
|
24
|
+
comms: "mail",
|
|
25
|
+
marketing: "trend",
|
|
26
|
+
apps: "code",
|
|
27
|
+
legal: "book",
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
export function ApprovalCard(p: ApprovalCardProps) {
|
|
31
|
+
const t = useStrings(APPROVALS_STRINGS);
|
|
29
32
|
const opts: ApprovalOption[] = p.options || [
|
|
30
33
|
{
|
|
31
34
|
key: "A",
|
|
32
|
-
label: p.approveLabel ||
|
|
35
|
+
label: p.approveLabel || t.approveAsShown,
|
|
33
36
|
},
|
|
34
37
|
{
|
|
35
38
|
key: "B",
|
|
36
|
-
label:
|
|
37
|
-
input:
|
|
39
|
+
label: t.approveWithChange,
|
|
40
|
+
input: t.whatShouldChange,
|
|
38
41
|
},
|
|
39
42
|
{
|
|
40
43
|
key: "C",
|
|
41
|
-
label:
|
|
44
|
+
label: t.discard,
|
|
42
45
|
},
|
|
43
46
|
{
|
|
44
47
|
key: "D",
|
|
45
|
-
label:
|
|
46
|
-
input:
|
|
48
|
+
label: t.differentInstruction,
|
|
49
|
+
input: t.whatInstead,
|
|
47
50
|
},
|
|
48
51
|
];
|
|
49
52
|
const open = React.useState<ApprovalKey | null>(null),
|
|
@@ -115,7 +118,7 @@ export function ApprovalCard(p: ApprovalCardProps) {
|
|
|
115
118
|
>
|
|
116
119
|
<div className="tf-approval-top">
|
|
117
120
|
<StatusShape status="signal" />
|
|
118
|
-
<b>{p.heading ||
|
|
121
|
+
<b>{p.heading || t.approvalNeeded}</b>
|
|
119
122
|
{(p.agent || p.project) && (
|
|
120
123
|
<span className="tf-approval-who">
|
|
121
124
|
{[p.agent, p.project].filter(Boolean).join(" · ")}
|
|
@@ -123,8 +126,8 @@ export function ApprovalCard(p: ApprovalCardProps) {
|
|
|
123
126
|
)}
|
|
124
127
|
{fam && (
|
|
125
128
|
<Badge tone="neutral" dot={false} className="tf-family">
|
|
126
|
-
<Icon name={fam
|
|
127
|
-
{p.familyLabel ||
|
|
129
|
+
<Icon name={fam} size={12} />
|
|
130
|
+
{p.familyLabel || (p.family && t.riskFamily[p.family])}
|
|
128
131
|
</Badge>
|
|
129
132
|
)}
|
|
130
133
|
{p.age && <span className="tf-approval-age">{p.age}</span>}
|
|
@@ -178,7 +181,7 @@ export function ApprovalCard(p: ApprovalCardProps) {
|
|
|
178
181
|
open[1](null);
|
|
179
182
|
}}
|
|
180
183
|
>
|
|
181
|
-
{
|
|
184
|
+
{t.cancel}
|
|
182
185
|
</Button>
|
|
183
186
|
<Button
|
|
184
187
|
size="sm"
|
|
@@ -187,7 +190,7 @@ export function ApprovalCard(p: ApprovalCardProps) {
|
|
|
187
190
|
decide(o);
|
|
188
191
|
}}
|
|
189
192
|
>
|
|
190
|
-
{o.key + " · " +
|
|
193
|
+
{o.key + " · " + t.send}
|
|
191
194
|
</Button>
|
|
192
195
|
</div>
|
|
193
196
|
</div>
|
|
@@ -212,12 +215,13 @@ export function ApprovalCard(p: ApprovalCardProps) {
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
export function ApprovalInbox(p: ApprovalInboxProps) {
|
|
218
|
+
const t = useStrings(APPROVALS_STRINGS);
|
|
215
219
|
const items = (p.items || []).slice().sort((a, b) => (b.ageMin || 0) - (a.ageMin || 0));
|
|
216
220
|
return (
|
|
217
221
|
<div
|
|
218
222
|
className="tf-inbox"
|
|
219
223
|
role="listbox"
|
|
220
|
-
aria-label={p.label ||
|
|
224
|
+
aria-label={p.label || t.approvals}
|
|
221
225
|
onKeyDown={(e) => {
|
|
222
226
|
const i = items.findIndex((x) => x.id === p.selected);
|
|
223
227
|
if (e.key === "j" || e.key === "ArrowDown") {
|
|
@@ -236,7 +240,7 @@ export function ApprovalInbox(p: ApprovalInboxProps) {
|
|
|
236
240
|
<EmptyState
|
|
237
241
|
icon="check"
|
|
238
242
|
tint="mint"
|
|
239
|
-
title={p.emptyTitle ||
|
|
243
|
+
title={p.emptyTitle || t.nothingWaiting}
|
|
240
244
|
text={p.emptyText}
|
|
241
245
|
/>
|
|
242
246
|
) : (
|
|
@@ -260,8 +264,8 @@ export function ApprovalInbox(p: ApprovalInboxProps) {
|
|
|
260
264
|
</span>
|
|
261
265
|
{fam && (
|
|
262
266
|
<Badge tone="neutral" dot={false} className="tf-family">
|
|
263
|
-
<Icon name={fam
|
|
264
|
-
{x.familyLabel ||
|
|
267
|
+
<Icon name={fam} size={12} />
|
|
268
|
+
{x.familyLabel || (x.family && t.riskFamily[x.family])}
|
|
265
269
|
</Badge>
|
|
266
270
|
)}
|
|
267
271
|
<span className={cx("tf-inbox-age", x.urgent && "warn")}>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { useStrings } from "../context.js";
|
|
5
|
+
import { BUILDING_BLOCKS_STRINGS } from "../strings.js";
|
|
4
6
|
import { cx } from "../cx.js";
|
|
5
7
|
import { useControlled, useOutside } from "../hooks.js";
|
|
6
8
|
import { Icon } from "../Icon.js";
|
|
@@ -55,11 +57,12 @@ export function KeyValue(p: KeyValueProps) {
|
|
|
55
57
|
);
|
|
56
58
|
}
|
|
57
59
|
export function Spinner(p: SpinnerProps) {
|
|
60
|
+
const t = useStrings(BUILDING_BLOCKS_STRINGS);
|
|
58
61
|
return (
|
|
59
62
|
<span
|
|
60
63
|
className={cx("tf-spinner", p.size === "lg" && "lg")}
|
|
61
64
|
role="status"
|
|
62
|
-
aria-label={p.label ||
|
|
65
|
+
aria-label={p.label || t.loading}
|
|
63
66
|
/>
|
|
64
67
|
);
|
|
65
68
|
}
|
|
@@ -339,6 +342,7 @@ export function InlineEdit(p: InlineEditProps) {
|
|
|
339
342
|
* jump to the limits, double-click resets.
|
|
340
343
|
*/
|
|
341
344
|
export function ResizablePanels(p: ResizablePanelsProps) {
|
|
345
|
+
const t = useStrings(BUILDING_BLOCKS_STRINGS);
|
|
342
346
|
const n = (p.panels || []).length;
|
|
343
347
|
const vertical = p.orientation === "vertical";
|
|
344
348
|
const min = p.min ?? 10;
|
|
@@ -411,7 +415,7 @@ export function ResizablePanels(p: ResizablePanelsProps) {
|
|
|
411
415
|
className="tf-panels-handle"
|
|
412
416
|
role="separator"
|
|
413
417
|
aria-orientation={vertical ? "horizontal" : "vertical"}
|
|
414
|
-
aria-label={
|
|
418
|
+
aria-label={t.resizePanel(p.labels?.[i], i + 1)}
|
|
415
419
|
aria-valuenow={Math.round(sizes[i] ?? 0)}
|
|
416
420
|
aria-valuemin={min}
|
|
417
421
|
aria-valuemax={Math.round((sizes[i] ?? 0) + (sizes[i + 1] ?? 0) - min)}
|