@sensiblestats/widget-react 0.35.0 → 0.37.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 +23 -0
- package/README.md +112 -0
- package/dist/index.cjs +413 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +404 -186
- package/dist/index.js.map +1 -1
- package/dist/styles.css +46 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/StatsWidget.tsx
|
|
39
|
-
var
|
|
39
|
+
var import_react23 = require("react");
|
|
40
40
|
var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/kickoff.ts
|
|
@@ -120,7 +120,10 @@ var STRINGS = {
|
|
|
120
120
|
fullTimeLabel: "Full time",
|
|
121
121
|
inSlipLabel: "In slip",
|
|
122
122
|
oddsUnavailable: "Odds unavailable right now",
|
|
123
|
-
momentumLabel: "Momentum"
|
|
123
|
+
momentumLabel: "Momentum",
|
|
124
|
+
accordionValueLabel: "Value",
|
|
125
|
+
accordionRetry: "Couldn't load odds \u2014 tap to retry",
|
|
126
|
+
accordionSuspended: "Suspended"
|
|
124
127
|
},
|
|
125
128
|
tr: {
|
|
126
129
|
launcherLabel: "SensibleStats ile sohbet et",
|
|
@@ -189,7 +192,10 @@ var STRINGS = {
|
|
|
189
192
|
fullTimeLabel: "Ma\xE7 sonu",
|
|
190
193
|
inSlipLabel: "Kuponda",
|
|
191
194
|
oddsUnavailable: "Oranlar \u015Fu anda kullan\u0131lam\u0131yor",
|
|
192
|
-
momentumLabel: "Momentum"
|
|
195
|
+
momentumLabel: "Momentum",
|
|
196
|
+
accordionValueLabel: "De\u011Fer",
|
|
197
|
+
accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
|
|
198
|
+
accordionSuspended: "Ask\u0131da"
|
|
193
199
|
}
|
|
194
200
|
};
|
|
195
201
|
function resolveLocaleStrings(locale) {
|
|
@@ -207,6 +213,7 @@ function normalizeUi(cfg) {
|
|
|
207
213
|
cta: cfg.cta,
|
|
208
214
|
surface: cfg.surface,
|
|
209
215
|
ink: cfg.ink,
|
|
216
|
+
pinIcon: cfg.pinIcon ?? "pin",
|
|
210
217
|
position: cfg.position ?? "right",
|
|
211
218
|
offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },
|
|
212
219
|
radius: cfg.radius ?? 16,
|
|
@@ -276,7 +283,10 @@ function normalizeUi(cfg) {
|
|
|
276
283
|
fullTimeLabel: strings.fullTimeLabel,
|
|
277
284
|
inSlipLabel: strings.inSlipLabel,
|
|
278
285
|
oddsUnavailable: strings.oddsUnavailable,
|
|
279
|
-
momentumLabel: strings.momentumLabel
|
|
286
|
+
momentumLabel: strings.momentumLabel,
|
|
287
|
+
accordionValueLabel: strings.accordionValueLabel,
|
|
288
|
+
accordionRetry: strings.accordionRetry,
|
|
289
|
+
accordionSuspended: strings.accordionSuspended
|
|
280
290
|
};
|
|
281
291
|
}
|
|
282
292
|
function toClientOptions(cfg) {
|
|
@@ -1030,6 +1040,8 @@ function useLiveMonitor(opts) {
|
|
|
1030
1040
|
const [oddsDot, setOddsDot] = (0, import_react3.useState)(false);
|
|
1031
1041
|
const [lastViewedPrices, setLastViewedPrices] = (0, import_react3.useState)({});
|
|
1032
1042
|
const [inSlip, setInSlip] = (0, import_react3.useState)({});
|
|
1043
|
+
const [openMarket, setOpenMarket] = (0, import_react3.useState)({});
|
|
1044
|
+
const [marketOdds, setMarketOdds] = (0, import_react3.useState)({});
|
|
1033
1045
|
const pinsRef = (0, import_react3.useRef)(pins);
|
|
1034
1046
|
pinsRef.current = pins;
|
|
1035
1047
|
const activeTabRef = (0, import_react3.useRef)(activeTab);
|
|
@@ -1038,6 +1050,46 @@ function useLiveMonitor(opts) {
|
|
|
1038
1050
|
snapshotRef.current = snapshot;
|
|
1039
1051
|
const lastViewedPricesRef = (0, import_react3.useRef)(lastViewedPrices);
|
|
1040
1052
|
lastViewedPricesRef.current = lastViewedPrices;
|
|
1053
|
+
const openMarketRef = (0, import_react3.useRef)(openMarket);
|
|
1054
|
+
openMarketRef.current = openMarket;
|
|
1055
|
+
const marketOddsRef = (0, import_react3.useRef)(marketOdds);
|
|
1056
|
+
marketOddsRef.current = marketOdds;
|
|
1057
|
+
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
1058
|
+
const getMarketOddsRef = (0, import_react3.useRef)(opts.getMarketOdds);
|
|
1059
|
+
getMarketOddsRef.current = opts.getMarketOdds;
|
|
1060
|
+
const fetchMarket = (0, import_react3.useCallback)((matchId, dev) => {
|
|
1061
|
+
const key = marketKey(matchId, dev);
|
|
1062
|
+
const existing = marketOddsRef.current[key];
|
|
1063
|
+
if (existing?.loading) return;
|
|
1064
|
+
const loadingEntry = { ...existing, loading: true, error: false };
|
|
1065
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry };
|
|
1066
|
+
setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }));
|
|
1067
|
+
const fn = getMarketOddsRef.current;
|
|
1068
|
+
if (!fn) return;
|
|
1069
|
+
void fn(matchId, dev).then((block) => {
|
|
1070
|
+
const entry = { block: block ?? void 0, loading: false, error: false };
|
|
1071
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
|
|
1072
|
+
setMarketOdds((prev) => ({ ...prev, [key]: entry }));
|
|
1073
|
+
}).catch(() => {
|
|
1074
|
+
const entry = { ...marketOddsRef.current[key], loading: false, error: true };
|
|
1075
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
|
|
1076
|
+
setMarketOdds((prev) => ({ ...prev, [key]: entry }));
|
|
1077
|
+
});
|
|
1078
|
+
}, []);
|
|
1079
|
+
const toggleMarket = (0, import_react3.useCallback)((matchId, dev) => {
|
|
1080
|
+
const key = marketKey(matchId, dev);
|
|
1081
|
+
const wasOpen = openMarketRef.current[matchId] === dev;
|
|
1082
|
+
const nextValue = wasOpen ? null : dev;
|
|
1083
|
+
openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue };
|
|
1084
|
+
setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }));
|
|
1085
|
+
const existing = marketOddsRef.current[key];
|
|
1086
|
+
if (!wasOpen && !(existing?.loading || existing?.block)) {
|
|
1087
|
+
fetchMarket(matchId, dev);
|
|
1088
|
+
}
|
|
1089
|
+
}, [fetchMarket]);
|
|
1090
|
+
const retryMarket = (0, import_react3.useCallback)((matchId, dev) => {
|
|
1091
|
+
fetchMarket(matchId, dev);
|
|
1092
|
+
}, [fetchMarket]);
|
|
1041
1093
|
const applySnapshot = (0, import_react3.useCallback)((next) => {
|
|
1042
1094
|
if (next === null) {
|
|
1043
1095
|
setEnabled(false);
|
|
@@ -1057,6 +1109,16 @@ function useLiveMonitor(opts) {
|
|
|
1057
1109
|
}
|
|
1058
1110
|
}
|
|
1059
1111
|
if (sawNewGoalOrRed && activeTabRef.current !== "matches") setMatchesDot(true);
|
|
1112
|
+
for (const m of next.matches) {
|
|
1113
|
+
if (!pinnedMatchIds.has(m.matchId)) continue;
|
|
1114
|
+
const first = m.availableMarkets?.[0];
|
|
1115
|
+
if (!first) continue;
|
|
1116
|
+
if (m.matchId in openMarketRef.current) continue;
|
|
1117
|
+
const dev = first.marketDeveloperName;
|
|
1118
|
+
openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev };
|
|
1119
|
+
setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }));
|
|
1120
|
+
fetchMarket(m.matchId, dev);
|
|
1121
|
+
}
|
|
1060
1122
|
const marketPins = currentPins.filter((p) => p.kind !== "match");
|
|
1061
1123
|
if (activeTabRef.current === "odds") {
|
|
1062
1124
|
setLastViewedPrices((prevMap) => {
|
|
@@ -1107,12 +1169,17 @@ function useLiveMonitor(opts) {
|
|
|
1107
1169
|
return;
|
|
1108
1170
|
}
|
|
1109
1171
|
applySnapshot(snap);
|
|
1172
|
+
for (const m of snap.matches) {
|
|
1173
|
+
if (m.phase !== "live") continue;
|
|
1174
|
+
const dev = openMarketRef.current[m.matchId];
|
|
1175
|
+
if (dev) fetchMarket(m.matchId, dev);
|
|
1176
|
+
}
|
|
1110
1177
|
} catch {
|
|
1111
1178
|
} finally {
|
|
1112
1179
|
inFlightRef.current = false;
|
|
1113
1180
|
scheduleRef.current();
|
|
1114
1181
|
}
|
|
1115
|
-
}, [applySnapshot]);
|
|
1182
|
+
}, [applySnapshot, fetchMarket]);
|
|
1116
1183
|
const scheduleRef = (0, import_react3.useRef)(() => {
|
|
1117
1184
|
});
|
|
1118
1185
|
scheduleRef.current = () => {
|
|
@@ -1190,10 +1257,17 @@ function useLiveMonitor(opts) {
|
|
|
1190
1257
|
lastViewedPrices,
|
|
1191
1258
|
inSlip,
|
|
1192
1259
|
markInSlip,
|
|
1260
|
+
openMarket,
|
|
1261
|
+
marketOdds,
|
|
1262
|
+
toggleMarket,
|
|
1263
|
+
retryMarket,
|
|
1193
1264
|
_setSnapshot: applySnapshot
|
|
1194
1265
|
};
|
|
1195
1266
|
}
|
|
1196
1267
|
|
|
1268
|
+
// src/components/ChatFab.tsx
|
|
1269
|
+
var import_react5 = require("react");
|
|
1270
|
+
|
|
1197
1271
|
// src/components/BrandMark.tsx
|
|
1198
1272
|
var import_react4 = require("react");
|
|
1199
1273
|
|
|
@@ -1246,23 +1320,39 @@ function BrandMark({ logoUrl, className }) {
|
|
|
1246
1320
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1247
1321
|
function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
|
|
1248
1322
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ss-w-greeting", role: "note", children: [
|
|
1249
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1323
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {}),
|
|
1326
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {}),
|
|
1327
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {})
|
|
1328
|
+
] }),
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ss-w-greeting-text", children: text })
|
|
1330
|
+
] }),
|
|
1250
1331
|
onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null
|
|
1251
1332
|
] });
|
|
1252
1333
|
}
|
|
1253
1334
|
|
|
1254
1335
|
// src/components/ChatFab.tsx
|
|
1255
1336
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1256
|
-
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss" }) {
|
|
1337
|
+
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
|
|
1257
1338
|
const bubble = popupText ?? greeting;
|
|
1258
|
-
|
|
1339
|
+
const [intro, setIntro] = (0, import_react5.useState)(false);
|
|
1340
|
+
const armedRef = (0, import_react5.useRef)(introAllowed);
|
|
1341
|
+
(0, import_react5.useEffect)(() => {
|
|
1342
|
+
if (armedRef.current && bubble) {
|
|
1343
|
+
armedRef.current = false;
|
|
1344
|
+
setIntro(true);
|
|
1345
|
+
onIntroStart?.();
|
|
1346
|
+
}
|
|
1347
|
+
}, [bubble, onIntroStart]);
|
|
1348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
|
|
1259
1349
|
bubble ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel }) : null,
|
|
1260
1350
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
|
|
1261
1351
|
] });
|
|
1262
1352
|
}
|
|
1263
1353
|
|
|
1264
1354
|
// src/components/ChatPanel.tsx
|
|
1265
|
-
var
|
|
1355
|
+
var import_react22 = require("react");
|
|
1266
1356
|
|
|
1267
1357
|
// src/components/ChatHeader.tsx
|
|
1268
1358
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -1275,7 +1365,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat", logoUrl, headerTitle }
|
|
|
1275
1365
|
}
|
|
1276
1366
|
|
|
1277
1367
|
// src/components/MessageList.tsx
|
|
1278
|
-
var
|
|
1368
|
+
var import_react20 = require("react");
|
|
1279
1369
|
|
|
1280
1370
|
// src/components/Markdown.tsx
|
|
1281
1371
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -1293,7 +1383,7 @@ function Markdown({ text }) {
|
|
|
1293
1383
|
}
|
|
1294
1384
|
|
|
1295
1385
|
// src/components/EntityCardList.tsx
|
|
1296
|
-
var
|
|
1386
|
+
var import_react6 = require("react");
|
|
1297
1387
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1298
1388
|
var MAX_VISIBLE = 3;
|
|
1299
1389
|
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
@@ -1377,7 +1467,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
|
|
|
1377
1467
|
)) });
|
|
1378
1468
|
}
|
|
1379
1469
|
function EntityCardItem({ c }) {
|
|
1380
|
-
const [active, setActive] = (0,
|
|
1470
|
+
const [active, setActive] = (0, import_react6.useState)(0);
|
|
1381
1471
|
const hasBody = c.scopes.length > 0;
|
|
1382
1472
|
if (!hasBody) {
|
|
1383
1473
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardHeader, { c, showScopeCrest: false }) });
|
|
@@ -1391,7 +1481,7 @@ function EntityCardItem({ c }) {
|
|
|
1391
1481
|
] });
|
|
1392
1482
|
}
|
|
1393
1483
|
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1394
|
-
const [expanded, setExpanded] = (0,
|
|
1484
|
+
const [expanded, setExpanded] = (0, import_react6.useState)(false);
|
|
1395
1485
|
if (cards.length === 0) return null;
|
|
1396
1486
|
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1397
1487
|
const overflow = cards.length - MAX_VISIBLE;
|
|
@@ -1402,18 +1492,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
1402
1492
|
}
|
|
1403
1493
|
|
|
1404
1494
|
// src/components/BettingInsightList.tsx
|
|
1405
|
-
var
|
|
1495
|
+
var import_react11 = require("react");
|
|
1406
1496
|
|
|
1407
1497
|
// src/components/AddToSlipButton.tsx
|
|
1408
|
-
var
|
|
1498
|
+
var import_react8 = require("react");
|
|
1409
1499
|
var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
|
|
1410
1500
|
|
|
1411
1501
|
// src/components/Toast.tsx
|
|
1412
|
-
var
|
|
1502
|
+
var import_react7 = require("react");
|
|
1413
1503
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1414
1504
|
var DISMISS_MS = 4e3;
|
|
1415
1505
|
function Toast({ toast, onDismiss }) {
|
|
1416
|
-
(0,
|
|
1506
|
+
(0, import_react7.useEffect)(() => {
|
|
1417
1507
|
if (!toast) return;
|
|
1418
1508
|
const timer = setTimeout(onDismiss, DISMISS_MS);
|
|
1419
1509
|
return () => clearTimeout(timer);
|
|
@@ -1431,10 +1521,10 @@ function withTimeout(value) {
|
|
|
1431
1521
|
]);
|
|
1432
1522
|
}
|
|
1433
1523
|
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
1434
|
-
const [pending, setPending] = (0,
|
|
1435
|
-
const [settled, setSettled] = (0,
|
|
1436
|
-
const [toast, setToast] = (0,
|
|
1437
|
-
const dismiss = (0,
|
|
1524
|
+
const [pending, setPending] = (0, import_react8.useState)(false);
|
|
1525
|
+
const [settled, setSettled] = (0, import_react8.useState)(false);
|
|
1526
|
+
const [toast, setToast] = (0, import_react8.useState)(null);
|
|
1527
|
+
const dismiss = (0, import_react8.useCallback)(() => setToast(null), []);
|
|
1438
1528
|
const handler = slip.onAddToSlip;
|
|
1439
1529
|
if (!ui || !handler || !selection) return null;
|
|
1440
1530
|
const onClick = async () => {
|
|
@@ -1498,14 +1588,14 @@ function OddsMovementBadge({
|
|
|
1498
1588
|
}
|
|
1499
1589
|
|
|
1500
1590
|
// src/components/Crest.tsx
|
|
1501
|
-
var
|
|
1591
|
+
var import_react9 = require("react");
|
|
1502
1592
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1503
1593
|
function initials2(name) {
|
|
1504
1594
|
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1505
1595
|
}
|
|
1506
1596
|
function Crest2({ url, name, kind }) {
|
|
1507
1597
|
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1508
|
-
const [failed, setFailed] = (0,
|
|
1598
|
+
const [failed, setFailed] = (0, import_react9.useState)(false);
|
|
1509
1599
|
if (url && !failed) {
|
|
1510
1600
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1511
1601
|
}
|
|
@@ -1513,11 +1603,16 @@ function Crest2({ url, name, kind }) {
|
|
|
1513
1603
|
}
|
|
1514
1604
|
|
|
1515
1605
|
// src/components/PinToggle.tsx
|
|
1516
|
-
var
|
|
1606
|
+
var import_react10 = require("react");
|
|
1517
1607
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1608
|
+
var PIN_GLYPHS = {
|
|
1609
|
+
pin: { viewBox: "0 0 24 24", strokeWidth: 1.4, transform: "scale(1.5)", d: "M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z" },
|
|
1610
|
+
star: { viewBox: "0 0 24 24", strokeWidth: 2, d: "M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.35 6.1 20.4l1.1-6.47L2.5 9.35l6.5-.95z" },
|
|
1611
|
+
bookmark: { viewBox: "0 0 24 24", strokeWidth: 2, d: "M7 3h10a1.5 1.5 0 0 1 1.5 1.5V21l-6.5-3.6L5.5 21V4.5A1.5 1.5 0 0 1 7 3z" }
|
|
1612
|
+
};
|
|
1518
1613
|
function PinToggle({ pin, monitor, ui }) {
|
|
1519
|
-
const [toast, setToast] = (0,
|
|
1520
|
-
const dismiss = (0,
|
|
1614
|
+
const [toast, setToast] = (0, import_react10.useState)(null);
|
|
1615
|
+
const dismiss = (0, import_react10.useCallback)(() => setToast(null), []);
|
|
1521
1616
|
if (!monitor || !monitor.enabled) return null;
|
|
1522
1617
|
const key = pinKey(pin);
|
|
1523
1618
|
const pinned = monitor.isPinned(key);
|
|
@@ -1530,6 +1625,7 @@ function PinToggle({ pin, monitor, ui }) {
|
|
|
1530
1625
|
setToast({ kind: "error", text: ui.marketLimitToast });
|
|
1531
1626
|
}
|
|
1532
1627
|
};
|
|
1628
|
+
const glyph = PIN_GLYPHS[ui.pinIcon];
|
|
1533
1629
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-pin-wrap", children: [
|
|
1534
1630
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1535
1631
|
"button",
|
|
@@ -1537,10 +1633,22 @@ function PinToggle({ pin, monitor, ui }) {
|
|
|
1537
1633
|
type: "button",
|
|
1538
1634
|
className: "ss-w-pin",
|
|
1539
1635
|
"data-on": pinned || void 0,
|
|
1636
|
+
"data-icon": ui.pinIcon,
|
|
1540
1637
|
"aria-pressed": pinned,
|
|
1541
1638
|
"aria-label": pinned ? labels.unpin : labels.pin,
|
|
1542
1639
|
onClick,
|
|
1543
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { viewBox:
|
|
1640
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { viewBox: glyph.viewBox, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1641
|
+
"path",
|
|
1642
|
+
{
|
|
1643
|
+
transform: glyph.transform,
|
|
1644
|
+
d: glyph.d,
|
|
1645
|
+
fill: pinned ? "currentColor" : "none",
|
|
1646
|
+
stroke: pinned ? "none" : "currentColor",
|
|
1647
|
+
strokeWidth: glyph.strokeWidth,
|
|
1648
|
+
strokeLinejoin: "round",
|
|
1649
|
+
strokeLinecap: "round"
|
|
1650
|
+
}
|
|
1651
|
+
) })
|
|
1544
1652
|
}
|
|
1545
1653
|
),
|
|
1546
1654
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Toast, { toast, onDismiss: dismiss })
|
|
@@ -1556,7 +1664,7 @@ function StatRows({ stats }) {
|
|
|
1556
1664
|
] }, `${s.label}:${s.value}`)) });
|
|
1557
1665
|
}
|
|
1558
1666
|
function ScopedStats({ scopes }) {
|
|
1559
|
-
const [active, setActive] = (0,
|
|
1667
|
+
const [active, setActive] = (0, import_react11.useState)(0);
|
|
1560
1668
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1561
1669
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-scoped", children: [
|
|
1562
1670
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
@@ -1567,7 +1675,7 @@ function hasStatsContent(it) {
|
|
|
1567
1675
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1568
1676
|
}
|
|
1569
1677
|
function ReasonStrip({ it, ui }) {
|
|
1570
|
-
const [open, setOpen] = (0,
|
|
1678
|
+
const [open, setOpen] = (0, import_react11.useState)(false);
|
|
1571
1679
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1572
1680
|
const hasStats = hasStatsContent(it);
|
|
1573
1681
|
const hasText = !!it.text;
|
|
@@ -1677,7 +1785,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
1677
1785
|
}
|
|
1678
1786
|
|
|
1679
1787
|
// src/components/MarketOddsCardList.tsx
|
|
1680
|
-
var
|
|
1788
|
+
var import_react12 = require("react");
|
|
1681
1789
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1682
1790
|
function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
1683
1791
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
@@ -1693,48 +1801,50 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
1693
1801
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
1694
1802
|
] });
|
|
1695
1803
|
}
|
|
1696
|
-
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
|
|
1697
|
-
const [open, setOpen] = (0,
|
|
1804
|
+
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader }) {
|
|
1805
|
+
const [open, setOpen] = (0, import_react12.useState)(false);
|
|
1698
1806
|
const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
1699
1807
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
1700
1808
|
const showPin = !!monitor && vm.pinEnabled;
|
|
1701
1809
|
const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
|
|
1702
1810
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mocard", children: [
|
|
1703
|
-
|
|
1704
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.
|
|
1705
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
kickoff.
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-
|
|
1730
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1811
|
+
!hideHeader && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1812
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-header", children: [
|
|
1813
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1814
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
|
|
1815
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-comp", children: vm.competition })
|
|
1816
|
+
] }) : null }),
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-header-right", children: [
|
|
1818
|
+
vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-live", children: [
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1820
|
+
ui?.liveLabel ?? "Live"
|
|
1821
|
+
] }) : null,
|
|
1822
|
+
kickoff ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-kick", children: [
|
|
1823
|
+
kickoff.dayLabel,
|
|
1824
|
+
" ",
|
|
1825
|
+
kickoff.time
|
|
1826
|
+
] }) : null,
|
|
1827
|
+
showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1828
|
+
PinToggle,
|
|
1829
|
+
{
|
|
1830
|
+
ui,
|
|
1831
|
+
monitor,
|
|
1832
|
+
pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
|
|
1833
|
+
}
|
|
1834
|
+
) : null
|
|
1835
|
+
] })
|
|
1836
|
+
] }) : null,
|
|
1837
|
+
hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mo-sub", children: [
|
|
1838
|
+
hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-fixture", children: [
|
|
1839
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
|
|
1840
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1842
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
|
|
1844
|
+
] }) : vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
|
|
1845
|
+
vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-market", children: vm.market }) : null
|
|
1846
|
+
] }) : null
|
|
1847
|
+
] }),
|
|
1738
1848
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mo-rows", children: [
|
|
1739
1849
|
vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)),
|
|
1740
1850
|
open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)) : null
|
|
@@ -1747,9 +1857,9 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
|
|
|
1747
1857
|
vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
1748
1858
|
] });
|
|
1749
1859
|
}
|
|
1750
|
-
function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds }) {
|
|
1860
|
+
function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader }) {
|
|
1751
1861
|
if (!cards || cards.length === 0) return null;
|
|
1752
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds }, vm.id)) });
|
|
1862
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds, hideHeader }, vm.id)) });
|
|
1753
1863
|
}
|
|
1754
1864
|
|
|
1755
1865
|
// src/components/OddsMovementCard.tsx
|
|
@@ -1987,7 +2097,7 @@ function FixtureCard({ card }) {
|
|
|
1987
2097
|
}
|
|
1988
2098
|
|
|
1989
2099
|
// src/components/dashboard/CountdownCard.tsx
|
|
1990
|
-
var
|
|
2100
|
+
var import_react13 = require("react");
|
|
1991
2101
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1992
2102
|
var DAY_MS = 864e5;
|
|
1993
2103
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -2006,12 +2116,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
|
2006
2116
|
function CountdownCard({ card }) {
|
|
2007
2117
|
const { data } = card;
|
|
2008
2118
|
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
2009
|
-
const [nowMs, setNowMs] = (0,
|
|
2010
|
-
const [reduced] = (0,
|
|
2119
|
+
const [nowMs, setNowMs] = (0, import_react13.useState)(() => Date.now());
|
|
2120
|
+
const [reduced] = (0, import_react13.useState)(
|
|
2011
2121
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
2012
2122
|
);
|
|
2013
2123
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
2014
|
-
(0,
|
|
2124
|
+
(0, import_react13.useEffect)(() => {
|
|
2015
2125
|
if (reduced) return;
|
|
2016
2126
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
2017
2127
|
return () => window.clearInterval(id);
|
|
@@ -2019,7 +2129,7 @@ function CountdownCard({ card }) {
|
|
|
2019
2129
|
const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
|
|
2020
2130
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-fandash-countdown-top", children: [
|
|
2021
2131
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
|
|
2022
|
-
segments ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
2132
|
+
segments ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react13.Fragment, { children: [
|
|
2023
2133
|
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
|
|
2024
2134
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
|
|
2025
2135
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
|
|
@@ -2030,7 +2140,7 @@ function CountdownCard({ card }) {
|
|
|
2030
2140
|
}
|
|
2031
2141
|
|
|
2032
2142
|
// src/components/dashboard/InjuriesCard.tsx
|
|
2033
|
-
var
|
|
2143
|
+
var import_react14 = require("react");
|
|
2034
2144
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2035
2145
|
var SHOWN = 3;
|
|
2036
2146
|
function ColHead({ name, crestUrl }) {
|
|
@@ -2053,7 +2163,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
|
|
|
2053
2163
|
}
|
|
2054
2164
|
function InjuriesCard({ card, ui }) {
|
|
2055
2165
|
const { data } = card;
|
|
2056
|
-
const [expanded, setExpanded] = (0,
|
|
2166
|
+
const [expanded, setExpanded] = (0, import_react14.useState)(false);
|
|
2057
2167
|
const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
|
|
2058
2168
|
const limit = expanded ? void 0 : SHOWN;
|
|
2059
2169
|
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
@@ -2157,7 +2267,7 @@ function LinksCard({ card }) {
|
|
|
2157
2267
|
}
|
|
2158
2268
|
|
|
2159
2269
|
// src/components/dashboard/PostMatchResultCard.tsx
|
|
2160
|
-
var
|
|
2270
|
+
var import_react15 = require("react");
|
|
2161
2271
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2162
2272
|
function initials3(name) {
|
|
2163
2273
|
return name.trim().slice(0, 3).toUpperCase();
|
|
@@ -2167,7 +2277,7 @@ function PostMatchCrest({
|
|
|
2167
2277
|
name,
|
|
2168
2278
|
side
|
|
2169
2279
|
}) {
|
|
2170
|
-
const [failed, setFailed] = (0,
|
|
2280
|
+
const [failed, setFailed] = (0, import_react15.useState)(false);
|
|
2171
2281
|
const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
|
|
2172
2282
|
if (url && !failed) {
|
|
2173
2283
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2366,10 +2476,10 @@ function RestingFormCard({ card }) {
|
|
|
2366
2476
|
}
|
|
2367
2477
|
|
|
2368
2478
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
2369
|
-
var
|
|
2479
|
+
var import_react17 = require("react");
|
|
2370
2480
|
|
|
2371
2481
|
// src/useLiveClock.ts
|
|
2372
|
-
var
|
|
2482
|
+
var import_react16 = require("react");
|
|
2373
2483
|
var TICK_MS = 6e4;
|
|
2374
2484
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2375
2485
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2378,10 +2488,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2378
2488
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2379
2489
|
}
|
|
2380
2490
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2381
|
-
const [displayMinute, setDisplayMinute] = (0,
|
|
2491
|
+
const [displayMinute, setDisplayMinute] = (0, import_react16.useState)(
|
|
2382
2492
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2383
2493
|
);
|
|
2384
|
-
(0,
|
|
2494
|
+
(0, import_react16.useEffect)(() => {
|
|
2385
2495
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2386
2496
|
if (!clockRunning) return;
|
|
2387
2497
|
const id = window.setInterval(() => {
|
|
@@ -2398,7 +2508,7 @@ function initials5(name) {
|
|
|
2398
2508
|
return name.trim().slice(0, 3).toUpperCase();
|
|
2399
2509
|
}
|
|
2400
2510
|
function LiveCrest({ url, name, side }) {
|
|
2401
|
-
const [failed, setFailed] = (0,
|
|
2511
|
+
const [failed, setFailed] = (0, import_react17.useState)(false);
|
|
2402
2512
|
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
2403
2513
|
if (url && !failed) {
|
|
2404
2514
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2417,7 +2527,7 @@ function LiveScoreCard({
|
|
|
2417
2527
|
}) {
|
|
2418
2528
|
const { data } = card;
|
|
2419
2529
|
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
2420
|
-
const seedRef = (0,
|
|
2530
|
+
const seedRef = (0, import_react17.useRef)(null);
|
|
2421
2531
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
2422
2532
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
2423
2533
|
}
|
|
@@ -2457,7 +2567,7 @@ function LiveScoreCard({
|
|
|
2457
2567
|
}
|
|
2458
2568
|
|
|
2459
2569
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
2460
|
-
var
|
|
2570
|
+
var import_react18 = require("react");
|
|
2461
2571
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2462
2572
|
var SHOWN2 = 3;
|
|
2463
2573
|
function EventIcon({ type }) {
|
|
@@ -2499,7 +2609,7 @@ function EventRow({ e }) {
|
|
|
2499
2609
|
] });
|
|
2500
2610
|
}
|
|
2501
2611
|
function LiveTimelineCard({ card, ui }) {
|
|
2502
|
-
const [expanded, setExpanded] = (0,
|
|
2612
|
+
const [expanded, setExpanded] = (0, import_react18.useState)(false);
|
|
2503
2613
|
const events = card.data.events;
|
|
2504
2614
|
if (!events || events.length === 0) return null;
|
|
2505
2615
|
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
@@ -2524,7 +2634,7 @@ function LiveTimelineCard({ card, ui }) {
|
|
|
2524
2634
|
}
|
|
2525
2635
|
|
|
2526
2636
|
// src/components/dashboard/MomentumWave.tsx
|
|
2527
|
-
var
|
|
2637
|
+
var import_react19 = require("react");
|
|
2528
2638
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2529
2639
|
var WIDTH = 270;
|
|
2530
2640
|
var HEIGHT = 56;
|
|
@@ -2548,7 +2658,7 @@ function MomentumWave({
|
|
|
2548
2658
|
}) {
|
|
2549
2659
|
if (points.length === 0) return null;
|
|
2550
2660
|
const { area, line, lastLeftPct, lastTopPx } = buildPaths(points);
|
|
2551
|
-
const clipId = (0,
|
|
2661
|
+
const clipId = (0, import_react19.useId)();
|
|
2552
2662
|
const topClipId = `${clipId}-top`;
|
|
2553
2663
|
const bottomClipId = `${clipId}-bottom`;
|
|
2554
2664
|
const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
|
|
@@ -2739,11 +2849,11 @@ function turnAnchor(messages) {
|
|
|
2739
2849
|
}
|
|
2740
2850
|
function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
2741
2851
|
const { state, send } = controller;
|
|
2742
|
-
const listRef = (0,
|
|
2743
|
-
const endRef = (0,
|
|
2744
|
-
const pinnedRef = (0,
|
|
2745
|
-
const anchoredTurnRef = (0,
|
|
2746
|
-
(0,
|
|
2852
|
+
const listRef = (0, import_react20.useRef)(null);
|
|
2853
|
+
const endRef = (0, import_react20.useRef)(null);
|
|
2854
|
+
const pinnedRef = (0, import_react20.useRef)(true);
|
|
2855
|
+
const anchoredTurnRef = (0, import_react20.useRef)(null);
|
|
2856
|
+
(0, import_react20.useEffect)(() => {
|
|
2747
2857
|
const anchor = turnAnchor(state.messages);
|
|
2748
2858
|
const list = listRef.current;
|
|
2749
2859
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -2799,10 +2909,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
2799
2909
|
}
|
|
2800
2910
|
|
|
2801
2911
|
// src/components/ChatInput.tsx
|
|
2802
|
-
var
|
|
2912
|
+
var import_react21 = require("react");
|
|
2803
2913
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2804
2914
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
2805
|
-
const [value, setValue] = (0,
|
|
2915
|
+
const [value, setValue] = (0, import_react21.useState)("");
|
|
2806
2916
|
const submit = () => {
|
|
2807
2917
|
const t = value.trim();
|
|
2808
2918
|
if (!t) return;
|
|
@@ -2859,8 +2969,63 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
|
|
|
2859
2969
|
}) });
|
|
2860
2970
|
}
|
|
2861
2971
|
|
|
2862
|
-
// src/components/
|
|
2972
|
+
// src/components/MarketAccordion.tsx
|
|
2863
2973
|
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2974
|
+
function MarketAccordion({ match, monitor, ui, slip }) {
|
|
2975
|
+
const markets = match.availableMarkets ?? [];
|
|
2976
|
+
if (markets.length === 0) return null;
|
|
2977
|
+
const open = monitor.openMarket[match.matchId] ?? null;
|
|
2978
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-acc", children: markets.map((m) => {
|
|
2979
|
+
const isOpen = open === m.marketDeveloperName;
|
|
2980
|
+
const key = `${match.matchId}:${m.marketDeveloperName}`;
|
|
2981
|
+
const entry = monitor.marketOdds[key];
|
|
2982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: isOpen ? "ss-w-acc-row ss-w-acc-row-open" : "ss-w-acc-row", children: [
|
|
2983
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
2984
|
+
"button",
|
|
2985
|
+
{
|
|
2986
|
+
type: "button",
|
|
2987
|
+
className: "ss-w-acc-head",
|
|
2988
|
+
onClick: () => monitor.toggleMarket(match.matchId, m.marketDeveloperName),
|
|
2989
|
+
children: [
|
|
2990
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-chevron", children: isOpen ? "\u25BE" : "\u25B8" }),
|
|
2991
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-label", children: m.marketLabel }),
|
|
2992
|
+
m.hasInsight && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-badge", children: "\u2605" }),
|
|
2993
|
+
m.suspended && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-susp", children: ui.accordionSuspended })
|
|
2994
|
+
]
|
|
2995
|
+
}
|
|
2996
|
+
),
|
|
2997
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-acc-panel", children: [
|
|
2998
|
+
entry?.error && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2999
|
+
"div",
|
|
3000
|
+
{
|
|
3001
|
+
className: "ss-w-acc-retry",
|
|
3002
|
+
onClick: () => monitor.retryMarket(match.matchId, m.marketDeveloperName),
|
|
3003
|
+
children: ui.accordionRetry
|
|
3004
|
+
}
|
|
3005
|
+
),
|
|
3006
|
+
entry?.block?.insight?.text && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-acc-insight", children: [
|
|
3007
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-badge", children: ui.accordionValueLabel }),
|
|
3008
|
+
" ",
|
|
3009
|
+
entry.block.insight.text
|
|
3010
|
+
] }),
|
|
3011
|
+
entry?.block?.card && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3012
|
+
MarketOddsCardList,
|
|
3013
|
+
{
|
|
3014
|
+
cards: [toMarketOddsVM(entry.block.card)],
|
|
3015
|
+
ui,
|
|
3016
|
+
slip,
|
|
3017
|
+
monitor,
|
|
3018
|
+
inSlipIds: monitor.inSlip,
|
|
3019
|
+
hideHeader: true
|
|
3020
|
+
}
|
|
3021
|
+
)
|
|
3022
|
+
] })
|
|
3023
|
+
] }, m.marketDeveloperName);
|
|
3024
|
+
}) });
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
// src/components/MonitorMatchCard.tsx
|
|
3028
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2864
3029
|
function chipSelection(row, matchId, conversationId) {
|
|
2865
3030
|
const chip = row.market;
|
|
2866
3031
|
if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== "number" || typeof chip.price !== "number") return null;
|
|
@@ -2883,63 +3048,63 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
2883
3048
|
const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins));
|
|
2884
3049
|
const orderedRows = [...promotedRows, ...otherRows];
|
|
2885
3050
|
const kickoff = match.phase === "preMatch" && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : void 0;
|
|
2886
|
-
return /* @__PURE__ */ (0,
|
|
2887
|
-
/* @__PURE__ */ (0,
|
|
2888
|
-
live && /* @__PURE__ */ (0,
|
|
2889
|
-
/* @__PURE__ */ (0,
|
|
3051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon", children: [
|
|
3052
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-top", children: [
|
|
3053
|
+
live && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-fandash-live-pill", children: [
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
|
|
2890
3055
|
ui.liveLabel
|
|
2891
3056
|
] }),
|
|
2892
|
-
match.phase === "fullTime" && /* @__PURE__ */ (0,
|
|
2893
|
-
kickoff && /* @__PURE__ */ (0,
|
|
3057
|
+
match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
|
|
3058
|
+
kickoff && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-pill", children: [
|
|
2894
3059
|
kickoff.dayLabel,
|
|
2895
3060
|
" \xB7 ",
|
|
2896
3061
|
kickoff.time
|
|
2897
3062
|
] }),
|
|
2898
|
-
live && match.minuteLabel && /* @__PURE__ */ (0,
|
|
2899
|
-
match.competitionName && /* @__PURE__ */ (0,
|
|
2900
|
-
/* @__PURE__ */ (0,
|
|
3063
|
+
live && match.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
|
|
3064
|
+
match.competitionName && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-comp", children: match.competitionName }),
|
|
3065
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
|
|
2901
3066
|
] }),
|
|
2902
|
-
/* @__PURE__ */ (0,
|
|
2903
|
-
/* @__PURE__ */ (0,
|
|
2904
|
-
/* @__PURE__ */ (0,
|
|
2905
|
-
/* @__PURE__ */ (0,
|
|
3067
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-main", children: [
|
|
3068
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-side", children: [
|
|
3069
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
|
|
3070
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: match.homeTeamName })
|
|
2906
3071
|
] }),
|
|
2907
|
-
match.phase === "preMatch" ? /* @__PURE__ */ (0,
|
|
3072
|
+
match.phase === "preMatch" ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-score", children: [
|
|
2908
3073
|
match.homeScore,
|
|
2909
|
-
/* @__PURE__ */ (0,
|
|
3074
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("i", { children: "\u2013" }),
|
|
2910
3075
|
match.awayScore
|
|
2911
3076
|
] }),
|
|
2912
|
-
/* @__PURE__ */ (0,
|
|
2913
|
-
/* @__PURE__ */ (0,
|
|
2914
|
-
/* @__PURE__ */ (0,
|
|
3077
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
|
|
3078
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
|
|
3079
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: match.awayTeamName })
|
|
2915
3080
|
] })
|
|
2916
3081
|
] }),
|
|
2917
|
-
scorers.length > 0 && /* @__PURE__ */ (0,
|
|
2918
|
-
/* @__PURE__ */ (0,
|
|
3082
|
+
scorers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
|
|
3083
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
|
|
2919
3084
|
const total = row.homeNum + row.awayNum;
|
|
2920
3085
|
const homePct = total > 0 ? row.homeNum / total * 75 : 0;
|
|
2921
3086
|
const awayPct = total > 0 ? row.awayNum / total * 75 : 0;
|
|
2922
3087
|
const promoted = isPromoted(row, promotedPins);
|
|
2923
3088
|
const selection = chipSelection(row, match.matchId, slip.conversationId);
|
|
2924
|
-
return /* @__PURE__ */ (0,
|
|
2925
|
-
/* @__PURE__ */ (0,
|
|
2926
|
-
/* @__PURE__ */ (0,
|
|
2927
|
-
/* @__PURE__ */ (0,
|
|
2928
|
-
/* @__PURE__ */ (0,
|
|
3089
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
|
|
3090
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
|
|
3091
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
|
|
3092
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-l", children: row.label }),
|
|
3093
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
|
|
2929
3094
|
] }),
|
|
2930
|
-
/* @__PURE__ */ (0,
|
|
2931
|
-
/* @__PURE__ */ (0,
|
|
2932
|
-
/* @__PURE__ */ (0,
|
|
3095
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-bar", children: [
|
|
3096
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
|
|
3097
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
|
|
2933
3098
|
] }),
|
|
2934
|
-
row.market && /* @__PURE__ */ (0,
|
|
2935
|
-
/* @__PURE__ */ (0,
|
|
3099
|
+
row.market && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { children: [
|
|
2936
3101
|
row.market.marketLabel,
|
|
2937
3102
|
" \xB7 ",
|
|
2938
3103
|
row.market.selectionLabel
|
|
2939
3104
|
] }),
|
|
2940
|
-
/* @__PURE__ */ (0,
|
|
2941
|
-
row.market.isSuspended ? /* @__PURE__ */ (0,
|
|
2942
|
-
/* @__PURE__ */ (0,
|
|
3105
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-stat-mkt-right", children: [
|
|
3106
|
+
row.market.isSuspended ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
|
|
3107
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2943
3108
|
SlipButton,
|
|
2944
3109
|
{
|
|
2945
3110
|
selection,
|
|
@@ -2953,68 +3118,69 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
2953
3118
|
] })
|
|
2954
3119
|
] }, row.label);
|
|
2955
3120
|
}) }),
|
|
2956
|
-
match.status === "stale" && /* @__PURE__ */ (0,
|
|
2957
|
-
match.momentum.length > 0 && /* @__PURE__ */ (0,
|
|
2958
|
-
/* @__PURE__ */ (0,
|
|
2959
|
-
/* @__PURE__ */ (0,
|
|
2960
|
-
/* @__PURE__ */ (0,
|
|
2961
|
-
/* @__PURE__ */ (0,
|
|
3121
|
+
match.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
|
|
3122
|
+
match.momentum.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-mom", children: [
|
|
3123
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
|
|
3124
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
|
|
3125
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
|
|
3126
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
|
|
2962
3127
|
] }),
|
|
2963
|
-
/* @__PURE__ */ (0,
|
|
3128
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(MomentumWave, { points: match.momentum, clubIsHome: true })
|
|
2964
3129
|
] }),
|
|
2965
|
-
match.
|
|
2966
|
-
match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-mon-grace", children: ui.graceNote })
|
|
3130
|
+
match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-grace", children: ui.graceNote })
|
|
2967
3131
|
] });
|
|
2968
3132
|
}
|
|
2969
3133
|
|
|
2970
3134
|
// src/components/MonitorTabs.tsx
|
|
2971
|
-
var
|
|
3135
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
2972
3136
|
function ContextLine({ m, monitor, ui }) {
|
|
2973
3137
|
const kick = m.kickoffUtc ? ui.bettingKickoff(m.kickoffUtc) : void 0;
|
|
2974
|
-
return /* @__PURE__ */ (0,
|
|
2975
|
-
/* @__PURE__ */ (0,
|
|
2976
|
-
/* @__PURE__ */ (0,
|
|
2977
|
-
/* @__PURE__ */ (0,
|
|
3138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mk-ctx", children: [
|
|
3139
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
|
|
3140
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
|
|
3141
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-name", children: m.homeTeamName })
|
|
2978
3142
|
] }),
|
|
2979
|
-
m.phase === "preMatch" ? kick && /* @__PURE__ */ (0,
|
|
3143
|
+
m.phase === "preMatch" ? kick && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mon-pill", children: [
|
|
2980
3144
|
kick.dayLabel,
|
|
2981
3145
|
" ",
|
|
2982
3146
|
kick.time
|
|
2983
|
-
] }) : typeof m.homeScore === "number" && /* @__PURE__ */ (0,
|
|
3147
|
+
] }) : typeof m.homeScore === "number" && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("b", { children: [
|
|
2984
3148
|
m.homeScore,
|
|
2985
3149
|
"\u2013",
|
|
2986
3150
|
m.awayScore
|
|
2987
3151
|
] }),
|
|
2988
|
-
/* @__PURE__ */ (0,
|
|
2989
|
-
/* @__PURE__ */ (0,
|
|
2990
|
-
/* @__PURE__ */ (0,
|
|
3152
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
|
|
3153
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
|
|
3154
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
|
|
2991
3155
|
] }),
|
|
2992
|
-
m.minuteLabel && /* @__PURE__ */ (0,
|
|
2993
|
-
/* @__PURE__ */ (0,
|
|
2994
|
-
m.isSuspended && !m.isSettled && /* @__PURE__ */ (0,
|
|
2995
|
-
m.isSettled && /* @__PURE__ */ (0,
|
|
2996
|
-
m.status === "stale" && /* @__PURE__ */ (0,
|
|
3156
|
+
m.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
|
|
3157
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-right", children: [
|
|
3158
|
+
m.isSuspended && !m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
|
|
3159
|
+
m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
|
|
3160
|
+
m.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
|
|
2997
3161
|
(() => {
|
|
2998
3162
|
const pin = monitor.pins.find((p) => p.key === m.key);
|
|
2999
|
-
return pin ? /* @__PURE__ */ (0,
|
|
3163
|
+
return pin ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PinToggle, { ui, monitor, pin }) : null;
|
|
3000
3164
|
})()
|
|
3001
3165
|
] })
|
|
3002
3166
|
] });
|
|
3003
3167
|
}
|
|
3004
3168
|
function MatchesPanel({ monitor, ui, slip }) {
|
|
3005
3169
|
const matches = (monitor.snapshot?.matches ?? []).filter((m) => monitor.pins.some((p) => p.kind === "match" && p.matchId === m.matchId));
|
|
3006
|
-
if (matches.length === 0) return /* @__PURE__ */ (0,
|
|
3007
|
-
return /* @__PURE__ */ (0,
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3170
|
+
if (matches.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
|
|
3171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mon-item", children: [
|
|
3172
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3173
|
+
MonitorMatchCard,
|
|
3174
|
+
{
|
|
3175
|
+
match: m,
|
|
3176
|
+
promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
|
|
3177
|
+
monitor,
|
|
3178
|
+
ui,
|
|
3179
|
+
slip
|
|
3180
|
+
}
|
|
3181
|
+
),
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(MarketAccordion, { match: m, monitor, ui, slip })
|
|
3183
|
+
] }, m.matchId)) });
|
|
3018
3184
|
}
|
|
3019
3185
|
function withSinceViewMovement(vm, prev) {
|
|
3020
3186
|
const primary = vm.mainRows[0];
|
|
@@ -3028,10 +3194,10 @@ function withSinceViewMovement(vm, prev) {
|
|
|
3028
3194
|
}
|
|
3029
3195
|
function OddsPanel({ monitor, ui, slip }) {
|
|
3030
3196
|
const markets = (monitor.snapshot?.markets ?? []).filter((m) => monitor.pins.some((p) => p.key === m.key));
|
|
3031
|
-
if (markets.length === 0) return /* @__PURE__ */ (0,
|
|
3032
|
-
return /* @__PURE__ */ (0,
|
|
3033
|
-
/* @__PURE__ */ (0,
|
|
3034
|
-
m.card && /* @__PURE__ */ (0,
|
|
3197
|
+
if (markets.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
|
|
3198
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
|
|
3199
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ContextLine, { m, monitor, ui }),
|
|
3200
|
+
m.card && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3035
3201
|
MarketOddsCardList,
|
|
3036
3202
|
{
|
|
3037
3203
|
cards: [withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])],
|
|
@@ -3040,17 +3206,17 @@ function OddsPanel({ monitor, ui, slip }) {
|
|
|
3040
3206
|
inSlipIds: monitor.inSlip
|
|
3041
3207
|
}
|
|
3042
3208
|
),
|
|
3043
|
-
m.history && /* @__PURE__ */ (0,
|
|
3044
|
-
!m.card && !m.history && /* @__PURE__ */ (0,
|
|
3209
|
+
m.history && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
|
|
3210
|
+
!m.card && !m.history && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
|
|
3045
3211
|
] }, m.key)) });
|
|
3046
3212
|
}
|
|
3047
3213
|
|
|
3048
3214
|
// src/components/ChatPanel.tsx
|
|
3049
|
-
var
|
|
3215
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3050
3216
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
3051
3217
|
function useIsModal() {
|
|
3052
|
-
const [modal, setModal] = (0,
|
|
3053
|
-
(0,
|
|
3218
|
+
const [modal, setModal] = (0, import_react22.useState)(false);
|
|
3219
|
+
(0, import_react22.useEffect)(() => {
|
|
3054
3220
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
3055
3221
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
3056
3222
|
const sync = () => setModal(mql.matches);
|
|
@@ -3063,7 +3229,7 @@ function useIsModal() {
|
|
|
3063
3229
|
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3064
3230
|
const { state, close, stop, send } = controller;
|
|
3065
3231
|
const isModal = useIsModal();
|
|
3066
|
-
(0,
|
|
3232
|
+
(0, import_react22.useEffect)(() => {
|
|
3067
3233
|
const onKey = (e) => {
|
|
3068
3234
|
if (e.key === "Escape") close();
|
|
3069
3235
|
};
|
|
@@ -3074,12 +3240,12 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3074
3240
|
monitor?.setActiveTab("chat");
|
|
3075
3241
|
send(text);
|
|
3076
3242
|
};
|
|
3077
|
-
(0,
|
|
3243
|
+
(0, import_react22.useEffect)(() => {
|
|
3078
3244
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
3079
3245
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
3080
|
-
return /* @__PURE__ */ (0,
|
|
3081
|
-
/* @__PURE__ */ (0,
|
|
3082
|
-
monitor && /* @__PURE__ */ (0,
|
|
3246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
3247
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
|
|
3248
|
+
monitor && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3083
3249
|
TabBar,
|
|
3084
3250
|
{
|
|
3085
3251
|
monitor,
|
|
@@ -3088,16 +3254,16 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3088
3254
|
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
|
|
3089
3255
|
}
|
|
3090
3256
|
),
|
|
3091
|
-
/* @__PURE__ */ (0,
|
|
3257
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3092
3258
|
"div",
|
|
3093
3259
|
{
|
|
3094
3260
|
style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
|
|
3095
|
-
children: /* @__PURE__ */ (0,
|
|
3261
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
|
|
3096
3262
|
}
|
|
3097
3263
|
),
|
|
3098
|
-
monitor && monitor.activeTab === "matches" && /* @__PURE__ */ (0,
|
|
3099
|
-
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0,
|
|
3100
|
-
/* @__PURE__ */ (0,
|
|
3264
|
+
monitor && monitor.activeTab === "matches" && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MatchesPanel, { monitor, ui, slip }),
|
|
3265
|
+
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(OddsPanel, { monitor, ui, slip }),
|
|
3266
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
3101
3267
|
] });
|
|
3102
3268
|
}
|
|
3103
3269
|
|
|
@@ -3145,8 +3311,40 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
3145
3311
|
.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }
|
|
3146
3312
|
.ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }
|
|
3147
3313
|
.ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }
|
|
3148
|
-
.ss-w-greeting-body { flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }
|
|
3314
|
+
.ss-w-greeting-body { position: relative; flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }
|
|
3149
3315
|
.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }
|
|
3316
|
+
.ss-w-greeting-text { display: block; }
|
|
3317
|
+
/* Typing indicator: overlays the text area so bubble height stays put; hidden at
|
|
3318
|
+
rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */
|
|
3319
|
+
.ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }
|
|
3320
|
+
.ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }
|
|
3321
|
+
/* One-shot launcher attention intro: FAB nudges, then the greeting types in.
|
|
3322
|
+
Gated behind no-preference so reduce-motion users get the greeting shown
|
|
3323
|
+
statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once
|
|
3324
|
+
per page load; every animation runs a single time and settles at rest. */
|
|
3325
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
3326
|
+
.ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }
|
|
3327
|
+
.ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }
|
|
3328
|
+
.ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }
|
|
3329
|
+
.ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }
|
|
3330
|
+
.ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }
|
|
3331
|
+
.ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }
|
|
3332
|
+
.ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }
|
|
3333
|
+
}
|
|
3334
|
+
@keyframes ss-w-nudge {
|
|
3335
|
+
0%, 100% { transform: none; }
|
|
3336
|
+
22% { transform: translateY(-9px) rotate(-9deg); }
|
|
3337
|
+
44% { transform: translateY(0) rotate(7deg); }
|
|
3338
|
+
64% { transform: translateY(-4px) rotate(-4deg); }
|
|
3339
|
+
82% { transform: rotate(2deg); }
|
|
3340
|
+
}
|
|
3341
|
+
@keyframes ss-w-greet-in {
|
|
3342
|
+
from { opacity: 0; transform: translateY(8px) scale(.92); }
|
|
3343
|
+
to { opacity: 1; transform: none; }
|
|
3344
|
+
}
|
|
3345
|
+
@keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }
|
|
3346
|
+
@keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
|
|
3347
|
+
@keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
|
|
3150
3348
|
|
|
3151
3349
|
/* panel */
|
|
3152
3350
|
.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(460px, calc(100vw - 40px)); height: min(640px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }
|
|
@@ -3850,10 +4048,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
3850
4048
|
.ss-w-mon-oddspin { display: flex; flex-direction: column; gap: 10px; padding: 12px; border: 1px solid var(--ss-w-line); border-radius: 12px; background: var(--ss-w-panel); }
|
|
3851
4049
|
.ss-w-mon-oddspin[data-settled] .ss-w-mo-price,
|
|
3852
4050
|
.ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }
|
|
4051
|
+
|
|
4052
|
+
/* market accordion (Task 9): one collapsed row per available market, expanding into a reused
|
|
4053
|
+
MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */
|
|
4054
|
+
.ss-w-acc { display: flex; flex-direction: column; gap: 6px; }
|
|
4055
|
+
.ss-w-acc-row { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); overflow: hidden; }
|
|
4056
|
+
.ss-w-acc-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 9px 11px; background: none; border: none; cursor: pointer; text-align: left; font: inherit; color: var(--ss-w-ink); }
|
|
4057
|
+
.ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; }
|
|
4058
|
+
.ss-w-acc-label { font-size: 12.5px; font-weight: 600; }
|
|
4059
|
+
.ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); }
|
|
4060
|
+
.ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
4061
|
+
.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
|
|
4062
|
+
.ss-w-acc-insight { font-size: 12px; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 7px 9px; }
|
|
4063
|
+
.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
|
|
3853
4064
|
`;
|
|
3854
4065
|
|
|
3855
4066
|
// src/StatsWidget.tsx
|
|
3856
|
-
var
|
|
4067
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3857
4068
|
function buildClient(props) {
|
|
3858
4069
|
try {
|
|
3859
4070
|
if ("client" in props && props.client) {
|
|
@@ -3878,16 +4089,21 @@ function injectStyles(root) {
|
|
|
3878
4089
|
function StatsWidget(props) {
|
|
3879
4090
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
3880
4091
|
const cfg = props.config;
|
|
3881
|
-
const built = (0,
|
|
3882
|
-
const ui = (0,
|
|
3883
|
-
const rootRef = (0,
|
|
4092
|
+
const built = (0, import_react23.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
4093
|
+
const ui = (0, import_react23.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
4094
|
+
const rootRef = (0, import_react23.useRef)(null);
|
|
4095
|
+
const introDoneRef = (0, import_react23.useRef)(false);
|
|
4096
|
+
const markIntroDone = (0, import_react23.useCallback)(() => {
|
|
4097
|
+
introDoneRef.current = true;
|
|
4098
|
+
}, []);
|
|
3884
4099
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
3885
4100
|
const monitor = useLiveMonitor({
|
|
3886
4101
|
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
4102
|
+
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
3887
4103
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
3888
4104
|
isOpen: controller.state.isOpen
|
|
3889
4105
|
});
|
|
3890
|
-
const slip = (0,
|
|
4106
|
+
const slip = (0, import_react23.useMemo)(
|
|
3891
4107
|
() => {
|
|
3892
4108
|
const handler = props.config?.onAddToSlip;
|
|
3893
4109
|
return {
|
|
@@ -3910,18 +4126,18 @@ function StatsWidget(props) {
|
|
|
3910
4126
|
},
|
|
3911
4127
|
[props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
|
|
3912
4128
|
);
|
|
3913
|
-
const onDashboardTap = (0,
|
|
4129
|
+
const onDashboardTap = (0, import_react23.useMemo)(
|
|
3914
4130
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
3915
4131
|
[built]
|
|
3916
4132
|
);
|
|
3917
|
-
(0,
|
|
4133
|
+
(0, import_react23.useEffect)(() => {
|
|
3918
4134
|
if (!built || !ui.injectStyles) return;
|
|
3919
4135
|
const node = rootRef.current?.getRootNode();
|
|
3920
4136
|
if (node) injectStyles(node);
|
|
3921
4137
|
}, [built, ui.injectStyles]);
|
|
3922
4138
|
if (!built) return null;
|
|
3923
4139
|
const attrs = themeAttrs(ui);
|
|
3924
|
-
return /* @__PURE__ */ (0,
|
|
4140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.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_runtime50.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3925
4141
|
ChatFab,
|
|
3926
4142
|
{
|
|
3927
4143
|
label: ui.launcherLabel,
|
|
@@ -3930,7 +4146,9 @@ function StatsWidget(props) {
|
|
|
3930
4146
|
logoUrl: ui.logoUrl,
|
|
3931
4147
|
onOpen: controller.open,
|
|
3932
4148
|
onDismissPopup: controller.dismissPopup,
|
|
3933
|
-
dismissLabel: ui.dismissGreeting
|
|
4149
|
+
dismissLabel: ui.dismissGreeting,
|
|
4150
|
+
introAllowed: !introDoneRef.current,
|
|
4151
|
+
onIntroStart: markIntroDone
|
|
3934
4152
|
}
|
|
3935
4153
|
) });
|
|
3936
4154
|
}
|