@sensiblestats/widget-react 0.7.2 → 0.9.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 +26 -0
- package/dist/index.cjs +269 -79
- 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 +257 -67
- package/dist/index.js.map +1 -1
- package/dist/styles.css +26 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -21,6 +21,10 @@ var STRINGS = {
|
|
|
21
21
|
oddsLabel: "Odds",
|
|
22
22
|
liveLabel: "Live",
|
|
23
23
|
addToSlip: "Add to slip",
|
|
24
|
+
marketPrices: "Market prices",
|
|
25
|
+
moreLines: "More lines",
|
|
26
|
+
hideLines: "Hide lines",
|
|
27
|
+
updatedLabel: "updated",
|
|
24
28
|
inSlip: "In slip",
|
|
25
29
|
slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
|
|
26
30
|
slipDuplicate: "Already in your slip",
|
|
@@ -47,6 +51,10 @@ var STRINGS = {
|
|
|
47
51
|
oddsLabel: "Oran",
|
|
48
52
|
liveLabel: "Canl\u0131",
|
|
49
53
|
addToSlip: "Kupona ekle",
|
|
54
|
+
marketPrices: "Piyasa fiyatlar\u0131",
|
|
55
|
+
moreLines: "Di\u011Fer \xE7izgiler",
|
|
56
|
+
hideLines: "\xC7izgileri gizle",
|
|
57
|
+
updatedLabel: "g\xFCncellendi",
|
|
50
58
|
inSlip: "Kuponda",
|
|
51
59
|
slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
|
|
52
60
|
slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
|
|
@@ -89,6 +97,10 @@ function normalizeUi(cfg) {
|
|
|
89
97
|
hideStats: strings.hideStats,
|
|
90
98
|
oddsLabel: strings.oddsLabel,
|
|
91
99
|
liveLabel: strings.liveLabel,
|
|
100
|
+
marketPrices: strings.marketPrices,
|
|
101
|
+
moreLines: strings.moreLines,
|
|
102
|
+
hideLines: strings.hideLines,
|
|
103
|
+
updatedLabel: strings.updatedLabel,
|
|
92
104
|
addToSlip: strings.addToSlip,
|
|
93
105
|
inSlip: strings.inSlip,
|
|
94
106
|
slipAdded: strings.slipAdded,
|
|
@@ -144,19 +156,27 @@ function readStatCells(raw) {
|
|
|
144
156
|
}
|
|
145
157
|
return cells;
|
|
146
158
|
}
|
|
147
|
-
function readStats(card) {
|
|
148
|
-
return readStatCells(card.stats);
|
|
149
|
-
}
|
|
150
159
|
function toCardVM(card) {
|
|
151
160
|
const entityType = str(card.entityType)?.toLowerCase();
|
|
152
161
|
const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
|
|
162
|
+
const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
|
|
163
|
+
const label = str(s.label);
|
|
164
|
+
if (!label) return null;
|
|
165
|
+
return {
|
|
166
|
+
competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
|
|
167
|
+
label,
|
|
168
|
+
image: str(s.imagePath),
|
|
169
|
+
stats: readStatCells(s.stats)
|
|
170
|
+
};
|
|
171
|
+
}).filter((s) => s !== null) : [];
|
|
153
172
|
return {
|
|
154
173
|
id: String(card.entityId),
|
|
155
174
|
kind,
|
|
156
175
|
name: card.canonicalName,
|
|
157
176
|
image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
|
|
158
177
|
sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
|
|
159
|
-
|
|
178
|
+
season: str(card.seasonName),
|
|
179
|
+
scopes
|
|
160
180
|
};
|
|
161
181
|
}
|
|
162
182
|
function toActionVM(action) {
|
|
@@ -218,6 +238,47 @@ function toSlipSelection(vm, conversationId) {
|
|
|
218
238
|
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
219
239
|
return selection;
|
|
220
240
|
}
|
|
241
|
+
function toMarketOddsVM(card) {
|
|
242
|
+
const rows = Array.isArray(card.rows) ? card.rows : [];
|
|
243
|
+
const toRow = (r, i) => {
|
|
244
|
+
const selection = [str(r.selectionLabel), str(r.line)].filter(Boolean).join(" ");
|
|
245
|
+
const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
|
|
246
|
+
return {
|
|
247
|
+
key: `${selection}:${str(r.line) ?? ""}:${i}`,
|
|
248
|
+
selection,
|
|
249
|
+
odds: price !== void 0 ? price.toFixed(2) : "",
|
|
250
|
+
oddsDecimal: price,
|
|
251
|
+
matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
|
|
252
|
+
quotedAtUtc: str(r.quotedAtUtc),
|
|
253
|
+
isMain: r.isMainLine !== false
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
const vms = rows.map(toRow).filter((r) => r.selection && r.odds);
|
|
257
|
+
const home = str(card.homeTeamName);
|
|
258
|
+
const away = str(card.awayTeamName);
|
|
259
|
+
const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
|
|
260
|
+
return {
|
|
261
|
+
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
262
|
+
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
263
|
+
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
264
|
+
competition: str(card.competitionName),
|
|
265
|
+
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
266
|
+
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
267
|
+
isLive: rows.some((r) => r.isLive === true),
|
|
268
|
+
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
269
|
+
mainRows: vms.filter((r) => r.isMain),
|
|
270
|
+
moreRows: vms.filter((r) => !r.isMain),
|
|
271
|
+
disclaimer: str(card.disclaimer),
|
|
272
|
+
addToSlipEnabled: card.addToSlipEnabled === true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function marketOddsRowToSlipSelection(vm, row, conversationId) {
|
|
276
|
+
if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
|
|
277
|
+
const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
|
|
278
|
+
if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
|
|
279
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
280
|
+
return selection;
|
|
281
|
+
}
|
|
221
282
|
|
|
222
283
|
// src/reducer.ts
|
|
223
284
|
var POPUP_MAX = 160;
|
|
@@ -249,6 +310,8 @@ function applyEvent(state, event) {
|
|
|
249
310
|
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
250
311
|
case "betting_insight":
|
|
251
312
|
return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) };
|
|
313
|
+
case "market_odds":
|
|
314
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, marketOdds: [...t.marketOdds, toMarketOddsVM(event.data.card)] })) };
|
|
252
315
|
case "intent_chip": {
|
|
253
316
|
const chip = toChipVM(event.data.intent);
|
|
254
317
|
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
@@ -284,11 +347,11 @@ function reducer(state, action) {
|
|
|
284
347
|
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
285
348
|
case "USER_SENT": {
|
|
286
349
|
const user = { role: "user", id: action.userId, text: action.displayText ?? action.input.message };
|
|
287
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false };
|
|
350
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], marketOdds: [], done: false };
|
|
288
351
|
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null };
|
|
289
352
|
}
|
|
290
353
|
case "GREETING_SENT": {
|
|
291
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false, isGreeting: true };
|
|
354
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], marketOdds: [], done: false, isGreeting: true };
|
|
292
355
|
return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null };
|
|
293
356
|
}
|
|
294
357
|
case "DISMISS_POPUP":
|
|
@@ -410,7 +473,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
410
473
|
}
|
|
411
474
|
|
|
412
475
|
// src/components/ChatPanel.tsx
|
|
413
|
-
import { useEffect as useEffect4, useState as
|
|
476
|
+
import { useEffect as useEffect4, useState as useState6 } from "react";
|
|
414
477
|
|
|
415
478
|
// src/components/ChatHeader.tsx
|
|
416
479
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -442,18 +505,58 @@ function Markdown({ text }) {
|
|
|
442
505
|
|
|
443
506
|
// src/components/EntityCardList.tsx
|
|
444
507
|
import { useState } from "react";
|
|
445
|
-
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
508
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
446
509
|
var MAX_VISIBLE = 3;
|
|
447
510
|
function initials(name) {
|
|
448
511
|
return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
|
|
449
512
|
}
|
|
450
|
-
function
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
513
|
+
function Crest({ scope }) {
|
|
514
|
+
return /* @__PURE__ */ jsx6("span", { className: "ss-w-ecard-crest", style: { backgroundImage: `url(${scope.image})` }, "aria-hidden": "true" });
|
|
515
|
+
}
|
|
516
|
+
function StatRow({ stats }) {
|
|
517
|
+
return /* @__PURE__ */ jsx6("div", { className: "ss-w-ecard-stats", children: stats.map((s) => /* @__PURE__ */ jsxs4("span", { className: "ss-w-stat", children: [
|
|
518
|
+
/* @__PURE__ */ jsx6("b", { children: s.value }),
|
|
519
|
+
/* @__PURE__ */ jsx6("span", { children: s.label })
|
|
520
|
+
] }, s.label)) });
|
|
521
|
+
}
|
|
522
|
+
function ScopeChips({ scopes }) {
|
|
523
|
+
const [active, setActive] = useState(0);
|
|
524
|
+
const current = scopes[active] ?? scopes[0];
|
|
525
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
526
|
+
/* @__PURE__ */ jsx6("div", { className: "ss-w-ecard-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx6(
|
|
527
|
+
"button",
|
|
528
|
+
{
|
|
529
|
+
type: "button",
|
|
530
|
+
className: "ss-w-ecard-chip",
|
|
531
|
+
"aria-pressed": i === active,
|
|
532
|
+
"aria-label": s.label,
|
|
533
|
+
title: s.label,
|
|
534
|
+
onClick: () => setActive(i),
|
|
535
|
+
children: s.image ? /* @__PURE__ */ jsx6(Crest, { scope: s }) : s.label
|
|
536
|
+
},
|
|
537
|
+
String(s.competitionId ?? "all")
|
|
538
|
+
)) }),
|
|
539
|
+
/* @__PURE__ */ jsx6(StatRow, { stats: current.stats }, String(current.competitionId ?? "all"))
|
|
540
|
+
] });
|
|
541
|
+
}
|
|
542
|
+
function CardScopes({ scopes }) {
|
|
543
|
+
if (scopes.length === 0) return null;
|
|
544
|
+
if (scopes.length === 1) {
|
|
545
|
+
const only = scopes[0];
|
|
546
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
547
|
+
/* @__PURE__ */ jsxs4("span", { className: "ss-w-ecard-tag", children: [
|
|
548
|
+
only.image ? /* @__PURE__ */ jsx6(Crest, { scope: only }) : null,
|
|
549
|
+
only.label
|
|
550
|
+
] }),
|
|
551
|
+
/* @__PURE__ */ jsx6(StatRow, { stats: only.stats })
|
|
552
|
+
] });
|
|
553
|
+
}
|
|
554
|
+
return /* @__PURE__ */ jsx6(ScopeChips, { scopes });
|
|
555
|
+
}
|
|
556
|
+
function EntityCardItem({ c }) {
|
|
557
|
+
const season = c.scopes.length > 0 ? c.season : void 0;
|
|
558
|
+
return /* @__PURE__ */ jsxs4("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
|
|
559
|
+
/* @__PURE__ */ jsxs4("div", { className: "ss-w-ecard-head", children: [
|
|
457
560
|
/* @__PURE__ */ jsx6(
|
|
458
561
|
"span",
|
|
459
562
|
{
|
|
@@ -465,13 +568,23 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
465
568
|
/* @__PURE__ */ jsxs4("span", { className: "ss-w-meta", children: [
|
|
466
569
|
c.kind !== "generic" ? /* @__PURE__ */ jsx6("span", { className: "ss-w-kind", children: c.kind }) : null,
|
|
467
570
|
/* @__PURE__ */ jsx6("span", { className: "ss-w-nm", children: c.name }),
|
|
468
|
-
c.sub ? /* @__PURE__ */
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
] }
|
|
474
|
-
] }
|
|
571
|
+
c.sub || season ? /* @__PURE__ */ jsxs4("span", { className: "ss-w-sub", children: [
|
|
572
|
+
c.sub,
|
|
573
|
+
c.sub && season ? " \xB7 " : "",
|
|
574
|
+
season ? /* @__PURE__ */ jsx6("span", { className: "ss-w-season", children: season }) : null
|
|
575
|
+
] }) : null
|
|
576
|
+
] })
|
|
577
|
+
] }),
|
|
578
|
+
/* @__PURE__ */ jsx6(CardScopes, { scopes: c.scopes })
|
|
579
|
+
] });
|
|
580
|
+
}
|
|
581
|
+
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
582
|
+
const [expanded, setExpanded] = useState(false);
|
|
583
|
+
if (cards.length === 0) return null;
|
|
584
|
+
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
585
|
+
const overflow = cards.length - MAX_VISIBLE;
|
|
586
|
+
return /* @__PURE__ */ jsxs4("div", { className: "ss-w-cards", children: [
|
|
587
|
+
visible.map((c) => /* @__PURE__ */ jsx6(EntityCardItem, { c }, c.id)),
|
|
475
588
|
overflow > 0 ? /* @__PURE__ */ jsx6("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
|
|
476
589
|
] });
|
|
477
590
|
}
|
|
@@ -533,13 +646,12 @@ function withTimeout(value) {
|
|
|
533
646
|
new Promise((_, reject) => setTimeout(() => reject(new Error("add-to-slip timed out")), ADD_TO_SLIP_TIMEOUT_MS))
|
|
534
647
|
]);
|
|
535
648
|
}
|
|
536
|
-
function
|
|
649
|
+
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
537
650
|
const [pending, setPending] = useState2(false);
|
|
538
651
|
const [settled, setSettled] = useState2(false);
|
|
539
652
|
const [toast, setToast] = useState2(null);
|
|
540
653
|
const dismiss = useCallback2(() => setToast(null), []);
|
|
541
654
|
const handler = slip.onAddToSlip;
|
|
542
|
-
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
543
655
|
if (!ui || !handler || !selection) return null;
|
|
544
656
|
const onClick = async () => {
|
|
545
657
|
setPending(true);
|
|
@@ -547,11 +659,11 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
547
659
|
const raw = await withTimeout(Promise.resolve(handler(selection)));
|
|
548
660
|
if (raw != null && !isAddToSlipResult(raw)) throw new Error("malformed add-to-slip result");
|
|
549
661
|
const result = raw ?? void 0;
|
|
550
|
-
setToast(resultToToast(result,
|
|
662
|
+
setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui));
|
|
551
663
|
setSettled(isTerminal(result));
|
|
552
664
|
if (wasAdded(result) && slip.onMarketClicked) {
|
|
553
665
|
try {
|
|
554
|
-
slip.onMarketClicked(
|
|
666
|
+
slip.onMarketClicked(marketName);
|
|
555
667
|
} catch {
|
|
556
668
|
}
|
|
557
669
|
}
|
|
@@ -575,6 +687,10 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
575
687
|
/* @__PURE__ */ jsx8(Toast, { toast, onDismiss: dismiss })
|
|
576
688
|
] });
|
|
577
689
|
}
|
|
690
|
+
function AddToSlipButton({ it, slip, ui }) {
|
|
691
|
+
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
692
|
+
return /* @__PURE__ */ jsx8(SlipButton, { selection, shownOdds: it.odds ?? "", marketName: it.market, slip, ui });
|
|
693
|
+
}
|
|
578
694
|
|
|
579
695
|
// src/components/BettingInsightList.tsx
|
|
580
696
|
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
@@ -647,38 +763,88 @@ function BettingInsightList({ insights, ui, slip }) {
|
|
|
647
763
|
return /* @__PURE__ */ jsx9("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ jsx9(InsightCard, { it, ui, slip }, it.id)) });
|
|
648
764
|
}
|
|
649
765
|
|
|
766
|
+
// src/components/MarketOddsCardList.tsx
|
|
767
|
+
import { useState as useState4 } from "react";
|
|
768
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
769
|
+
function OddsRow({ vm, row, ui, slip }) {
|
|
770
|
+
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
771
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-mo-row", children: [
|
|
772
|
+
/* @__PURE__ */ jsx10("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
773
|
+
/* @__PURE__ */ jsx10("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
774
|
+
/* @__PURE__ */ jsx10(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
775
|
+
] });
|
|
776
|
+
}
|
|
777
|
+
function formatUpdated(iso) {
|
|
778
|
+
if (!iso) return void 0;
|
|
779
|
+
const date = new Date(iso);
|
|
780
|
+
if (Number.isNaN(date.getTime())) return void 0;
|
|
781
|
+
return date.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
|
|
782
|
+
}
|
|
783
|
+
function MarketOddsCard({ vm, ui, slip }) {
|
|
784
|
+
const [open, setOpen] = useState4(false);
|
|
785
|
+
const updated = formatUpdated(vm.updatedAt);
|
|
786
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-mocard", children: [
|
|
787
|
+
/* @__PURE__ */ jsxs7("div", { className: "ss-w-mo-head", children: [
|
|
788
|
+
/* @__PURE__ */ jsx10("span", { className: "ss-w-mo-market", children: vm.market }),
|
|
789
|
+
/* @__PURE__ */ jsx10("span", { className: "ss-w-mo-tag", children: ui?.marketPrices ?? "Market prices" })
|
|
790
|
+
] }),
|
|
791
|
+
vm.fixture || vm.competition ? /* @__PURE__ */ jsxs7("div", { className: "ss-w-mo-fixture", children: [
|
|
792
|
+
vm.fixture ? /* @__PURE__ */ jsx10("span", { children: vm.fixture }) : null,
|
|
793
|
+
vm.competition ? /* @__PURE__ */ jsx10("span", { className: "ss-w-mo-comp", children: vm.competition }) : null
|
|
794
|
+
] }) : null,
|
|
795
|
+
/* @__PURE__ */ jsxs7("div", { className: "ss-w-mo-rows", children: [
|
|
796
|
+
vm.mainRows.map((row) => /* @__PURE__ */ jsx10(OddsRow, { vm, row, ui, slip }, row.key)),
|
|
797
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx10(OddsRow, { vm, row, ui, slip }, row.key)) : null
|
|
798
|
+
] }),
|
|
799
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs7("button", { type: "button", className: "ss-w-bi-toggle", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
800
|
+
/* @__PURE__ */ jsx10("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
801
|
+
/* @__PURE__ */ jsx10("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
802
|
+
] }) : null,
|
|
803
|
+
vm.bookmaker || updated ? /* @__PURE__ */ jsxs7("div", { className: "ss-w-mo-foot", children: [
|
|
804
|
+
vm.bookmaker ? /* @__PURE__ */ jsx10("span", { children: vm.bookmaker }) : null,
|
|
805
|
+
updated ? /* @__PURE__ */ jsx10("span", { children: `${ui?.updatedLabel ?? "updated"} ${updated}` }) : null
|
|
806
|
+
] }) : null,
|
|
807
|
+
vm.disclaimer ? /* @__PURE__ */ jsx10("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
808
|
+
] });
|
|
809
|
+
}
|
|
810
|
+
function MarketOddsCardList({ cards, ui, slip }) {
|
|
811
|
+
if (!cards || cards.length === 0) return null;
|
|
812
|
+
return /* @__PURE__ */ jsx10("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx10(MarketOddsCard, { vm, ui, slip }, vm.id)) });
|
|
813
|
+
}
|
|
814
|
+
|
|
650
815
|
// src/components/ActionButtons.tsx
|
|
651
|
-
import { Fragment, jsx as
|
|
816
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
652
817
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
653
818
|
if (actions.length === 0 && !loading) return null;
|
|
654
|
-
return /* @__PURE__ */
|
|
655
|
-
actions.map((a, i) => /* @__PURE__ */
|
|
656
|
-
actions.length === 0 && loading ? /* @__PURE__ */
|
|
657
|
-
/* @__PURE__ */
|
|
658
|
-
/* @__PURE__ */
|
|
819
|
+
return /* @__PURE__ */ jsxs8("div", { className: "ss-w-actions", children: [
|
|
820
|
+
actions.map((a, i) => /* @__PURE__ */ jsx11("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
821
|
+
actions.length === 0 && loading ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
822
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-abtn-shimmer" }),
|
|
823
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-abtn-shimmer" })
|
|
659
824
|
] }) : null
|
|
660
825
|
] });
|
|
661
826
|
}
|
|
662
827
|
|
|
663
828
|
// src/components/ChatMessage.tsx
|
|
664
|
-
import { jsx as
|
|
829
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
665
830
|
function ChatMessage({ message, disabled, onAct, ui, slip }) {
|
|
666
831
|
if (message.role === "user") {
|
|
667
|
-
return /* @__PURE__ */
|
|
832
|
+
return /* @__PURE__ */ jsx12("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx12("div", { className: "ss-w-bubble", children: message.text }) });
|
|
668
833
|
}
|
|
669
|
-
return /* @__PURE__ */
|
|
670
|
-
message.text ? /* @__PURE__ */
|
|
671
|
-
/* @__PURE__ */
|
|
672
|
-
/* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
834
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
835
|
+
message.text ? /* @__PURE__ */ jsx12(Markdown, { text: message.text }) : null,
|
|
836
|
+
/* @__PURE__ */ jsx12(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
837
|
+
/* @__PURE__ */ jsx12(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
838
|
+
/* @__PURE__ */ jsx12(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
839
|
+
/* @__PURE__ */ jsx12(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
674
840
|
] });
|
|
675
841
|
}
|
|
676
842
|
|
|
677
843
|
// src/components/IntentChips.tsx
|
|
678
|
-
import { jsx as
|
|
844
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
679
845
|
function IntentChips({ chips, onPick }) {
|
|
680
846
|
if (chips.length === 0) return null;
|
|
681
|
-
return /* @__PURE__ */
|
|
847
|
+
return /* @__PURE__ */ jsx13("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx13("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
682
848
|
}
|
|
683
849
|
|
|
684
850
|
// src/scroll.ts
|
|
@@ -688,7 +854,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
688
854
|
}
|
|
689
855
|
|
|
690
856
|
// src/components/MessageList.tsx
|
|
691
|
-
import { jsx as
|
|
857
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
692
858
|
function MessageList({ controller, ui, slip }) {
|
|
693
859
|
const { state, send } = controller;
|
|
694
860
|
const listRef = useRef2(null);
|
|
@@ -698,7 +864,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
698
864
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
699
865
|
}, [state.messages, state.status]);
|
|
700
866
|
const empty = state.messages.length === 0;
|
|
701
|
-
return /* @__PURE__ */
|
|
867
|
+
return /* @__PURE__ */ jsxs10(
|
|
702
868
|
"div",
|
|
703
869
|
{
|
|
704
870
|
className: "ss-w-list",
|
|
@@ -708,7 +874,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
708
874
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
709
875
|
},
|
|
710
876
|
children: [
|
|
711
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
877
|
+
state.messages.map((m) => /* @__PURE__ */ jsx14(
|
|
712
878
|
ChatMessage,
|
|
713
879
|
{
|
|
714
880
|
message: m,
|
|
@@ -719,25 +885,25 @@ function MessageList({ controller, ui, slip }) {
|
|
|
719
885
|
},
|
|
720
886
|
m.id
|
|
721
887
|
)),
|
|
722
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
888
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx14(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
723
889
|
} }) : null,
|
|
724
|
-
state.status ? /* @__PURE__ */
|
|
725
|
-
state.error ? /* @__PURE__ */
|
|
726
|
-
/* @__PURE__ */
|
|
727
|
-
/* @__PURE__ */
|
|
890
|
+
state.status ? /* @__PURE__ */ jsx14("div", { className: "ss-w-status", children: state.status }) : null,
|
|
891
|
+
state.error ? /* @__PURE__ */ jsxs10("div", { className: "ss-w-error", role: "alert", children: [
|
|
892
|
+
/* @__PURE__ */ jsx14("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
893
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
728
894
|
] }) : null,
|
|
729
|
-
empty ? /* @__PURE__ */
|
|
730
|
-
/* @__PURE__ */
|
|
895
|
+
empty ? /* @__PURE__ */ jsx14(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
896
|
+
/* @__PURE__ */ jsx14("div", { ref: endRef })
|
|
731
897
|
]
|
|
732
898
|
}
|
|
733
899
|
);
|
|
734
900
|
}
|
|
735
901
|
|
|
736
902
|
// src/components/ChatInput.tsx
|
|
737
|
-
import { useState as
|
|
738
|
-
import { jsx as
|
|
903
|
+
import { useState as useState5 } from "react";
|
|
904
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
739
905
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
740
|
-
const [value, setValue] =
|
|
906
|
+
const [value, setValue] = useState5("");
|
|
741
907
|
const submit = () => {
|
|
742
908
|
const t = value.trim();
|
|
743
909
|
if (!t) return;
|
|
@@ -750,17 +916,17 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
750
916
|
submit();
|
|
751
917
|
}
|
|
752
918
|
};
|
|
753
|
-
return /* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
755
|
-
streaming ? /* @__PURE__ */
|
|
919
|
+
return /* @__PURE__ */ jsxs11("div", { className: "ss-w-input", children: [
|
|
920
|
+
/* @__PURE__ */ jsx15("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
921
|
+
streaming ? /* @__PURE__ */ jsx15("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx15("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx15("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx15(SendIcon, {}) })
|
|
756
922
|
] });
|
|
757
923
|
}
|
|
758
924
|
|
|
759
925
|
// src/components/ChatPanel.tsx
|
|
760
|
-
import { jsx as
|
|
926
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
761
927
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
762
928
|
function useIsModal() {
|
|
763
|
-
const [modal, setModal] =
|
|
929
|
+
const [modal, setModal] = useState6(false);
|
|
764
930
|
useEffect4(() => {
|
|
765
931
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
766
932
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
@@ -781,10 +947,10 @@ function ChatPanel({ controller, ui, slip }) {
|
|
|
781
947
|
window.addEventListener("keydown", onKey);
|
|
782
948
|
return () => window.removeEventListener("keydown", onKey);
|
|
783
949
|
}, [close]);
|
|
784
|
-
return /* @__PURE__ */
|
|
785
|
-
/* @__PURE__ */
|
|
786
|
-
/* @__PURE__ */
|
|
787
|
-
/* @__PURE__ */
|
|
950
|
+
return /* @__PURE__ */ jsxs12("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
951
|
+
/* @__PURE__ */ jsx16(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
952
|
+
/* @__PURE__ */ jsx16(MessageList, { controller, ui, slip }),
|
|
953
|
+
/* @__PURE__ */ jsx16(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
788
954
|
] });
|
|
789
955
|
}
|
|
790
956
|
|
|
@@ -872,7 +1038,8 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
872
1038
|
|
|
873
1039
|
/* entity cards */
|
|
874
1040
|
.ss-w-cards { display: flex; flex-direction: column; gap: 7px; }
|
|
875
|
-
.ss-w-ecard { display: flex; align-items:
|
|
1041
|
+
.ss-w-ecard { display: flex; flex-direction: column; align-items: stretch; gap: 8px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; }
|
|
1042
|
+
.ss-w-ecard-head { display: flex; align-items: center; gap: 11px; }
|
|
876
1043
|
.ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }
|
|
877
1044
|
.ss-w-thumb.ss-w-team { border-radius: 10px; }
|
|
878
1045
|
.ss-w-ecard[data-kind="player"] .ss-w-thumb { background-color: var(--ss-w-accent); }
|
|
@@ -880,7 +1047,14 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
880
1047
|
.ss-w-kind { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }
|
|
881
1048
|
.ss-w-nm { font-weight: 660; }
|
|
882
1049
|
.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }
|
|
883
|
-
.ss-w-
|
|
1050
|
+
.ss-w-season { color: var(--ss-w-accent); font-weight: 660; }
|
|
1051
|
+
.ss-w-ecard-scopes { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }
|
|
1052
|
+
.ss-w-ecard-chip { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 8px; color: var(--ss-w-faint); background: none; cursor: pointer; }
|
|
1053
|
+
.ss-w-ecard-chip[aria-pressed="true"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
|
|
1054
|
+
.ss-w-ecard-crest { width: 16px; height: 16px; display: block; border-radius: 4px; background-size: cover; background-position: center; }
|
|
1055
|
+
.ss-w-ecard-tag { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
|
|
1056
|
+
.ss-w-ecard-stats { display: flex; gap: 16px; }
|
|
1057
|
+
.ss-w-stat { text-align: center; }
|
|
884
1058
|
.ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }
|
|
885
1059
|
.ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
886
1060
|
.ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }
|
|
@@ -920,6 +1094,22 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
920
1094
|
.ss-w-bi-chip { font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 10px; color: var(--ss-w-faint); background: none; cursor: pointer; }
|
|
921
1095
|
.ss-w-bi-chip[aria-pressed="true"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
|
|
922
1096
|
|
|
1097
|
+
/* market odds card */
|
|
1098
|
+
.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }
|
|
1099
|
+
.ss-w-mocard { 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; }
|
|
1100
|
+
.ss-w-mo-head { display: flex; align-items: center; gap: 8px; }
|
|
1101
|
+
.ss-w-mo-market { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
|
|
1102
|
+
.ss-w-mo-tag { margin-left: auto; flex: none; font-size: 9px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); border-radius: 8px; padding: 2px 7px; }
|
|
1103
|
+
.ss-w-mo-fixture { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }
|
|
1104
|
+
.ss-w-mo-comp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1105
|
+
.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
1106
|
+
.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
|
|
1107
|
+
.ss-w-mo-row:last-child { border-bottom: none; }
|
|
1108
|
+
.ss-w-mo-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
|
|
1109
|
+
.ss-w-mo-price { margin-left: auto; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; color: var(--ss-w-accent); }
|
|
1110
|
+
.ss-w-mo-row .ss-w-slip { margin: 0; }
|
|
1111
|
+
.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
1112
|
+
|
|
923
1113
|
/* action buttons */
|
|
924
1114
|
.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
925
1115
|
.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; }
|
|
@@ -957,7 +1147,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
957
1147
|
`;
|
|
958
1148
|
|
|
959
1149
|
// src/StatsWidget.tsx
|
|
960
|
-
import { jsx as
|
|
1150
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
961
1151
|
function buildClient(props) {
|
|
962
1152
|
try {
|
|
963
1153
|
if ("client" in props && props.client) {
|
|
@@ -1006,7 +1196,7 @@ function StatsWidget(props) {
|
|
|
1006
1196
|
}, [built, ui.injectStyles]);
|
|
1007
1197
|
if (!built) return null;
|
|
1008
1198
|
const attrs = themeAttrs(ui);
|
|
1009
|
-
return /* @__PURE__ */
|
|
1199
|
+
return /* @__PURE__ */ jsx17("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__ */ jsx17(ChatPanel, { controller, ui, slip }) : /* @__PURE__ */ jsx17(
|
|
1010
1200
|
ChatFab,
|
|
1011
1201
|
{
|
|
1012
1202
|
label: ui.launcherLabel,
|