@sensiblestats/widget-react 0.3.0 → 0.4.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/CHANGELOG.md +6 -0
- package/dist/index.cjs +107 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +107 -40
- package/dist/index.js.map +1 -1
- package/dist/styles.css +17 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @sensiblestats/widget-react
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Render `betting_insight` events as insight cards (market, selection + line, odds with an optional live badge, supporting stats, and the responsible-gambling disclaimer). **Bug fix:** the reducer previously had no case for `betting_insight` and no fallthrough, so any unmodelled event returned `undefined` and corrupted state — the next event then crashed the widget (`Cannot read properties of undefined (reading 'length')`). Unknown event types are now ignored safely and can never break the UI.
|
|
8
|
+
|
|
3
9
|
## 0.3.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -132,16 +132,19 @@ function str(v) {
|
|
|
132
132
|
function num(v) {
|
|
133
133
|
return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
|
|
134
134
|
}
|
|
135
|
-
function
|
|
136
|
-
if (!Array.isArray(
|
|
135
|
+
function readStatCells(raw) {
|
|
136
|
+
if (!Array.isArray(raw)) return [];
|
|
137
137
|
const cells = [];
|
|
138
|
-
for (const entry of
|
|
138
|
+
for (const entry of raw) {
|
|
139
139
|
const label = str(entry.label);
|
|
140
140
|
const value = num(entry.value) ?? str(entry.value);
|
|
141
141
|
if (label !== void 0 && value !== void 0) cells.push({ label, value });
|
|
142
142
|
}
|
|
143
143
|
return cells;
|
|
144
144
|
}
|
|
145
|
+
function readStats(card) {
|
|
146
|
+
return readStatCells(card.stats);
|
|
147
|
+
}
|
|
145
148
|
function toCardVM(card) {
|
|
146
149
|
const entityType = str(card.entityType)?.toLowerCase();
|
|
147
150
|
const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
|
|
@@ -167,6 +170,24 @@ function toChipVM(intent) {
|
|
|
167
170
|
function chipFromText(text) {
|
|
168
171
|
return { text };
|
|
169
172
|
}
|
|
173
|
+
function toInsightVM(insight) {
|
|
174
|
+
const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
|
|
175
|
+
const selection = [str(insight.selectionLabel), str(insight.line)].filter(Boolean).join(" ") || void 0;
|
|
176
|
+
const value = insight.odds?.value;
|
|
177
|
+
const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
|
|
178
|
+
return {
|
|
179
|
+
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
180
|
+
market,
|
|
181
|
+
selection,
|
|
182
|
+
odds,
|
|
183
|
+
// The wire payload carries bookmakerId (not a name); render a name only if one is present.
|
|
184
|
+
bookmaker: str(insight.odds?.bookmakerName),
|
|
185
|
+
isLive: insight.odds?.isLive === true,
|
|
186
|
+
text: str(insight.text) ?? "",
|
|
187
|
+
stats: readStatCells(insight.stats),
|
|
188
|
+
disclaimer: str(insight.disclaimer)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
170
191
|
|
|
171
192
|
// src/reducer.ts
|
|
172
193
|
var POPUP_MAX = 160;
|
|
@@ -193,6 +214,8 @@ function applyEvent(state, event) {
|
|
|
193
214
|
return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, toCardVM(event.data.card)] })) };
|
|
194
215
|
case "action_button":
|
|
195
216
|
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
217
|
+
case "betting_insight":
|
|
218
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) };
|
|
196
219
|
case "intent_chip": {
|
|
197
220
|
const chip = toChipVM(event.data.intent);
|
|
198
221
|
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
@@ -210,6 +233,7 @@ function applyEvent(state, event) {
|
|
|
210
233
|
return { ...state, error: suppress ? state.error : event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
211
234
|
}
|
|
212
235
|
}
|
|
236
|
+
return state;
|
|
213
237
|
}
|
|
214
238
|
function reducer(state, action) {
|
|
215
239
|
switch (action.kind) {
|
|
@@ -219,11 +243,11 @@ function reducer(state, action) {
|
|
|
219
243
|
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
220
244
|
case "USER_SENT": {
|
|
221
245
|
const user = { role: "user", id: action.userId, text: action.displayText ?? action.input.message };
|
|
222
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false };
|
|
246
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false };
|
|
223
247
|
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null };
|
|
224
248
|
}
|
|
225
249
|
case "GREETING_SENT": {
|
|
226
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false, isGreeting: true };
|
|
250
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false, isGreeting: true };
|
|
227
251
|
return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null };
|
|
228
252
|
}
|
|
229
253
|
case "DISMISS_POPUP":
|
|
@@ -411,37 +435,63 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
411
435
|
] });
|
|
412
436
|
}
|
|
413
437
|
|
|
414
|
-
// src/components/
|
|
438
|
+
// src/components/BettingInsightList.tsx
|
|
415
439
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
440
|
+
function BettingInsightList({ insights }) {
|
|
441
|
+
if (!insights || insights.length === 0) return null;
|
|
442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ss-w-binsight", children: [
|
|
443
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ss-w-bi-head", children: [
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ss-w-bi-mkt", children: [
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-bi-market", children: it.market }),
|
|
446
|
+
it.selection ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-bi-sel", children: it.selection }) : null
|
|
447
|
+
] }),
|
|
448
|
+
it.odds ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ss-w-bi-odds", children: [
|
|
449
|
+
it.isLive ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-bi-live", children: "Live" }) : null,
|
|
450
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: it.odds }),
|
|
451
|
+
it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
452
|
+
] }) : null
|
|
453
|
+
] }),
|
|
454
|
+
it.text ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
455
|
+
it.stats.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ss-w-bi-stats", children: it.stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ss-w-bi-stat", children: [
|
|
456
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: s.value }),
|
|
457
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: s.label })
|
|
458
|
+
] }, `${s.label}:${s.value}`)) }) : null,
|
|
459
|
+
it.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
460
|
+
] }, it.id)) });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/components/ActionButtons.tsx
|
|
464
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
416
465
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
417
466
|
if (actions.length === 0 && !loading) return null;
|
|
418
|
-
return /* @__PURE__ */ (0,
|
|
419
|
-
actions.map((a, i) => /* @__PURE__ */ (0,
|
|
420
|
-
actions.length === 0 && loading ? /* @__PURE__ */ (0,
|
|
421
|
-
/* @__PURE__ */ (0,
|
|
422
|
-
/* @__PURE__ */ (0,
|
|
467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ss-w-actions", children: [
|
|
468
|
+
actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
469
|
+
actions.length === 0 && loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ss-w-abtn-shimmer" }),
|
|
471
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ss-w-abtn-shimmer" })
|
|
423
472
|
] }) : null
|
|
424
473
|
] });
|
|
425
474
|
}
|
|
426
475
|
|
|
427
476
|
// src/components/ChatMessage.tsx
|
|
428
|
-
var
|
|
477
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
429
478
|
function ChatMessage({ message, disabled, onAct, ui }) {
|
|
430
479
|
if (message.role === "user") {
|
|
431
|
-
return /* @__PURE__ */ (0,
|
|
480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
432
481
|
}
|
|
433
|
-
return /* @__PURE__ */ (0,
|
|
434
|
-
message.text ? /* @__PURE__ */ (0,
|
|
435
|
-
/* @__PURE__ */ (0,
|
|
436
|
-
/* @__PURE__ */ (0,
|
|
482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
483
|
+
message.text ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Markdown, { text: message.text }) : null,
|
|
484
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
485
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BettingInsightList, { insights: message.insights }),
|
|
486
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
437
487
|
] });
|
|
438
488
|
}
|
|
439
489
|
|
|
440
490
|
// src/components/IntentChips.tsx
|
|
441
|
-
var
|
|
491
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
442
492
|
function IntentChips({ chips, onPick }) {
|
|
443
493
|
if (chips.length === 0) return null;
|
|
444
|
-
return /* @__PURE__ */ (0,
|
|
494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
445
495
|
}
|
|
446
496
|
|
|
447
497
|
// src/scroll.ts
|
|
@@ -451,7 +501,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
451
501
|
}
|
|
452
502
|
|
|
453
503
|
// src/components/MessageList.tsx
|
|
454
|
-
var
|
|
504
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
455
505
|
function MessageList({ controller, ui }) {
|
|
456
506
|
const { state, send } = controller;
|
|
457
507
|
const listRef = (0, import_react3.useRef)(null);
|
|
@@ -461,7 +511,7 @@ function MessageList({ controller, ui }) {
|
|
|
461
511
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
462
512
|
}, [state.messages, state.status]);
|
|
463
513
|
const empty = state.messages.length === 0;
|
|
464
|
-
return /* @__PURE__ */ (0,
|
|
514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
465
515
|
"div",
|
|
466
516
|
{
|
|
467
517
|
className: "ss-w-list",
|
|
@@ -471,7 +521,7 @@ function MessageList({ controller, ui }) {
|
|
|
471
521
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
472
522
|
},
|
|
473
523
|
children: [
|
|
474
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
524
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
475
525
|
ChatMessage,
|
|
476
526
|
{
|
|
477
527
|
message: m,
|
|
@@ -481,15 +531,15 @@ function MessageList({ controller, ui }) {
|
|
|
481
531
|
},
|
|
482
532
|
m.id
|
|
483
533
|
)),
|
|
484
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
534
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
485
535
|
} }) : null,
|
|
486
|
-
state.status ? /* @__PURE__ */ (0,
|
|
487
|
-
state.error ? /* @__PURE__ */ (0,
|
|
488
|
-
/* @__PURE__ */ (0,
|
|
489
|
-
/* @__PURE__ */ (0,
|
|
536
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
537
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
538
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
539
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
490
540
|
] }) : null,
|
|
491
|
-
empty ? /* @__PURE__ */ (0,
|
|
492
|
-
/* @__PURE__ */ (0,
|
|
541
|
+
empty ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { ref: endRef })
|
|
493
543
|
]
|
|
494
544
|
}
|
|
495
545
|
);
|
|
@@ -497,7 +547,7 @@ function MessageList({ controller, ui }) {
|
|
|
497
547
|
|
|
498
548
|
// src/components/ChatInput.tsx
|
|
499
549
|
var import_react4 = require("react");
|
|
500
|
-
var
|
|
550
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
501
551
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
502
552
|
const [value, setValue] = (0, import_react4.useState)("");
|
|
503
553
|
const submit = () => {
|
|
@@ -512,14 +562,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
512
562
|
submit();
|
|
513
563
|
}
|
|
514
564
|
};
|
|
515
|
-
return /* @__PURE__ */ (0,
|
|
516
|
-
/* @__PURE__ */ (0,
|
|
517
|
-
streaming ? /* @__PURE__ */ (0,
|
|
565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-input", children: [
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
567
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SendIcon, {}) })
|
|
518
568
|
] });
|
|
519
569
|
}
|
|
520
570
|
|
|
521
571
|
// src/components/ChatPanel.tsx
|
|
522
|
-
var
|
|
572
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
523
573
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
524
574
|
function useIsModal() {
|
|
525
575
|
const [modal, setModal] = (0, import_react5.useState)(false);
|
|
@@ -543,10 +593,10 @@ function ChatPanel({ controller, ui }) {
|
|
|
543
593
|
window.addEventListener("keydown", onKey);
|
|
544
594
|
return () => window.removeEventListener("keydown", onKey);
|
|
545
595
|
}, [close]);
|
|
546
|
-
return /* @__PURE__ */ (0,
|
|
547
|
-
/* @__PURE__ */ (0,
|
|
548
|
-
/* @__PURE__ */ (0,
|
|
549
|
-
/* @__PURE__ */ (0,
|
|
596
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
597
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageList, { controller, ui }),
|
|
599
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
550
600
|
] });
|
|
551
601
|
}
|
|
552
602
|
|
|
@@ -645,6 +695,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
645
695
|
.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }
|
|
646
696
|
.ss-w-cards-more:disabled { opacity: .5; cursor: default; }
|
|
647
697
|
|
|
698
|
+
/* betting insights */
|
|
699
|
+
.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }
|
|
700
|
+
.ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }
|
|
701
|
+
.ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }
|
|
702
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; min-width: 0; }
|
|
703
|
+
.ss-w-bi-market { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }
|
|
704
|
+
.ss-w-bi-sel { font-weight: 660; }
|
|
705
|
+
.ss-w-bi-odds { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }
|
|
706
|
+
.ss-w-bi-odds b { font-size: 15px; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); }
|
|
707
|
+
.ss-w-bi-book { font-size: 10px; color: var(--ss-w-faint); }
|
|
708
|
+
.ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; }
|
|
709
|
+
.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }
|
|
710
|
+
.ss-w-bi-stats { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
711
|
+
.ss-w-bi-stat b { display: block; font-variant-numeric: tabular-nums; font-weight: 660; }
|
|
712
|
+
.ss-w-bi-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
713
|
+
.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }
|
|
714
|
+
|
|
648
715
|
/* action buttons */
|
|
649
716
|
.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
650
717
|
.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }
|
|
@@ -674,7 +741,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
674
741
|
`;
|
|
675
742
|
|
|
676
743
|
// src/StatsWidget.tsx
|
|
677
|
-
var
|
|
744
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
678
745
|
function buildClient(props) {
|
|
679
746
|
try {
|
|
680
747
|
if ("client" in props && props.client) {
|
|
@@ -710,7 +777,7 @@ function StatsWidget(props) {
|
|
|
710
777
|
}, [built, ui.injectStyles]);
|
|
711
778
|
if (!built) return null;
|
|
712
779
|
const attrs = themeAttrs(ui);
|
|
713
|
-
return /* @__PURE__ */ (0,
|
|
780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatPanel, { controller, ui }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
714
781
|
ChatFab,
|
|
715
782
|
{
|
|
716
783
|
label: ui.launcherLabel,
|