@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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/StatsWidget.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo2, useRef as useRef7 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -83,7 +83,10 @@ var STRINGS = {
|
|
|
83
83
|
fullTimeLabel: "Full time",
|
|
84
84
|
inSlipLabel: "In slip",
|
|
85
85
|
oddsUnavailable: "Odds unavailable right now",
|
|
86
|
-
momentumLabel: "Momentum"
|
|
86
|
+
momentumLabel: "Momentum",
|
|
87
|
+
accordionValueLabel: "Value",
|
|
88
|
+
accordionRetry: "Couldn't load odds \u2014 tap to retry",
|
|
89
|
+
accordionSuspended: "Suspended"
|
|
87
90
|
},
|
|
88
91
|
tr: {
|
|
89
92
|
launcherLabel: "SensibleStats ile sohbet et",
|
|
@@ -152,7 +155,10 @@ var STRINGS = {
|
|
|
152
155
|
fullTimeLabel: "Ma\xE7 sonu",
|
|
153
156
|
inSlipLabel: "Kuponda",
|
|
154
157
|
oddsUnavailable: "Oranlar \u015Fu anda kullan\u0131lam\u0131yor",
|
|
155
|
-
momentumLabel: "Momentum"
|
|
158
|
+
momentumLabel: "Momentum",
|
|
159
|
+
accordionValueLabel: "De\u011Fer",
|
|
160
|
+
accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
|
|
161
|
+
accordionSuspended: "Ask\u0131da"
|
|
156
162
|
}
|
|
157
163
|
};
|
|
158
164
|
function resolveLocaleStrings(locale) {
|
|
@@ -170,6 +176,7 @@ function normalizeUi(cfg) {
|
|
|
170
176
|
cta: cfg.cta,
|
|
171
177
|
surface: cfg.surface,
|
|
172
178
|
ink: cfg.ink,
|
|
179
|
+
pinIcon: cfg.pinIcon ?? "pin",
|
|
173
180
|
position: cfg.position ?? "right",
|
|
174
181
|
offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },
|
|
175
182
|
radius: cfg.radius ?? 16,
|
|
@@ -239,7 +246,10 @@ function normalizeUi(cfg) {
|
|
|
239
246
|
fullTimeLabel: strings.fullTimeLabel,
|
|
240
247
|
inSlipLabel: strings.inSlipLabel,
|
|
241
248
|
oddsUnavailable: strings.oddsUnavailable,
|
|
242
|
-
momentumLabel: strings.momentumLabel
|
|
249
|
+
momentumLabel: strings.momentumLabel,
|
|
250
|
+
accordionValueLabel: strings.accordionValueLabel,
|
|
251
|
+
accordionRetry: strings.accordionRetry,
|
|
252
|
+
accordionSuspended: strings.accordionSuspended
|
|
243
253
|
};
|
|
244
254
|
}
|
|
245
255
|
function toClientOptions(cfg) {
|
|
@@ -993,6 +1003,8 @@ function useLiveMonitor(opts) {
|
|
|
993
1003
|
const [oddsDot, setOddsDot] = useState(false);
|
|
994
1004
|
const [lastViewedPrices, setLastViewedPrices] = useState({});
|
|
995
1005
|
const [inSlip, setInSlip] = useState({});
|
|
1006
|
+
const [openMarket, setOpenMarket] = useState({});
|
|
1007
|
+
const [marketOdds, setMarketOdds] = useState({});
|
|
996
1008
|
const pinsRef = useRef3(pins);
|
|
997
1009
|
pinsRef.current = pins;
|
|
998
1010
|
const activeTabRef = useRef3(activeTab);
|
|
@@ -1001,6 +1013,46 @@ function useLiveMonitor(opts) {
|
|
|
1001
1013
|
snapshotRef.current = snapshot;
|
|
1002
1014
|
const lastViewedPricesRef = useRef3(lastViewedPrices);
|
|
1003
1015
|
lastViewedPricesRef.current = lastViewedPrices;
|
|
1016
|
+
const openMarketRef = useRef3(openMarket);
|
|
1017
|
+
openMarketRef.current = openMarket;
|
|
1018
|
+
const marketOddsRef = useRef3(marketOdds);
|
|
1019
|
+
marketOddsRef.current = marketOdds;
|
|
1020
|
+
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
1021
|
+
const getMarketOddsRef = useRef3(opts.getMarketOdds);
|
|
1022
|
+
getMarketOddsRef.current = opts.getMarketOdds;
|
|
1023
|
+
const fetchMarket = useCallback2((matchId, dev) => {
|
|
1024
|
+
const key = marketKey(matchId, dev);
|
|
1025
|
+
const existing = marketOddsRef.current[key];
|
|
1026
|
+
if (existing?.loading) return;
|
|
1027
|
+
const loadingEntry = { ...existing, loading: true, error: false };
|
|
1028
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry };
|
|
1029
|
+
setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }));
|
|
1030
|
+
const fn = getMarketOddsRef.current;
|
|
1031
|
+
if (!fn) return;
|
|
1032
|
+
void fn(matchId, dev).then((block) => {
|
|
1033
|
+
const entry = { block: block ?? void 0, loading: false, error: false };
|
|
1034
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
|
|
1035
|
+
setMarketOdds((prev) => ({ ...prev, [key]: entry }));
|
|
1036
|
+
}).catch(() => {
|
|
1037
|
+
const entry = { ...marketOddsRef.current[key], loading: false, error: true };
|
|
1038
|
+
marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
|
|
1039
|
+
setMarketOdds((prev) => ({ ...prev, [key]: entry }));
|
|
1040
|
+
});
|
|
1041
|
+
}, []);
|
|
1042
|
+
const toggleMarket = useCallback2((matchId, dev) => {
|
|
1043
|
+
const key = marketKey(matchId, dev);
|
|
1044
|
+
const wasOpen = openMarketRef.current[matchId] === dev;
|
|
1045
|
+
const nextValue = wasOpen ? null : dev;
|
|
1046
|
+
openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue };
|
|
1047
|
+
setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }));
|
|
1048
|
+
const existing = marketOddsRef.current[key];
|
|
1049
|
+
if (!wasOpen && !(existing?.loading || existing?.block)) {
|
|
1050
|
+
fetchMarket(matchId, dev);
|
|
1051
|
+
}
|
|
1052
|
+
}, [fetchMarket]);
|
|
1053
|
+
const retryMarket = useCallback2((matchId, dev) => {
|
|
1054
|
+
fetchMarket(matchId, dev);
|
|
1055
|
+
}, [fetchMarket]);
|
|
1004
1056
|
const applySnapshot = useCallback2((next) => {
|
|
1005
1057
|
if (next === null) {
|
|
1006
1058
|
setEnabled(false);
|
|
@@ -1020,6 +1072,16 @@ function useLiveMonitor(opts) {
|
|
|
1020
1072
|
}
|
|
1021
1073
|
}
|
|
1022
1074
|
if (sawNewGoalOrRed && activeTabRef.current !== "matches") setMatchesDot(true);
|
|
1075
|
+
for (const m of next.matches) {
|
|
1076
|
+
if (!pinnedMatchIds.has(m.matchId)) continue;
|
|
1077
|
+
const first = m.availableMarkets?.[0];
|
|
1078
|
+
if (!first) continue;
|
|
1079
|
+
if (m.matchId in openMarketRef.current) continue;
|
|
1080
|
+
const dev = first.marketDeveloperName;
|
|
1081
|
+
openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev };
|
|
1082
|
+
setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }));
|
|
1083
|
+
fetchMarket(m.matchId, dev);
|
|
1084
|
+
}
|
|
1023
1085
|
const marketPins = currentPins.filter((p) => p.kind !== "match");
|
|
1024
1086
|
if (activeTabRef.current === "odds") {
|
|
1025
1087
|
setLastViewedPrices((prevMap) => {
|
|
@@ -1070,12 +1132,17 @@ function useLiveMonitor(opts) {
|
|
|
1070
1132
|
return;
|
|
1071
1133
|
}
|
|
1072
1134
|
applySnapshot(snap);
|
|
1135
|
+
for (const m of snap.matches) {
|
|
1136
|
+
if (m.phase !== "live") continue;
|
|
1137
|
+
const dev = openMarketRef.current[m.matchId];
|
|
1138
|
+
if (dev) fetchMarket(m.matchId, dev);
|
|
1139
|
+
}
|
|
1073
1140
|
} catch {
|
|
1074
1141
|
} finally {
|
|
1075
1142
|
inFlightRef.current = false;
|
|
1076
1143
|
scheduleRef.current();
|
|
1077
1144
|
}
|
|
1078
|
-
}, [applySnapshot]);
|
|
1145
|
+
}, [applySnapshot, fetchMarket]);
|
|
1079
1146
|
const scheduleRef = useRef3(() => {
|
|
1080
1147
|
});
|
|
1081
1148
|
scheduleRef.current = () => {
|
|
@@ -1153,10 +1220,17 @@ function useLiveMonitor(opts) {
|
|
|
1153
1220
|
lastViewedPrices,
|
|
1154
1221
|
inSlip,
|
|
1155
1222
|
markInSlip,
|
|
1223
|
+
openMarket,
|
|
1224
|
+
marketOdds,
|
|
1225
|
+
toggleMarket,
|
|
1226
|
+
retryMarket,
|
|
1156
1227
|
_setSnapshot: applySnapshot
|
|
1157
1228
|
};
|
|
1158
1229
|
}
|
|
1159
1230
|
|
|
1231
|
+
// src/components/ChatFab.tsx
|
|
1232
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
|
|
1233
|
+
|
|
1160
1234
|
// src/components/BrandMark.tsx
|
|
1161
1235
|
import { useState as useState2 } from "react";
|
|
1162
1236
|
|
|
@@ -1209,23 +1283,39 @@ function BrandMark({ logoUrl, className }) {
|
|
|
1209
1283
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
1210
1284
|
function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
|
|
1211
1285
|
return /* @__PURE__ */ jsxs("div", { className: "ss-w-greeting", role: "note", children: [
|
|
1212
|
-
/* @__PURE__ */
|
|
1286
|
+
/* @__PURE__ */ jsxs("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
|
|
1287
|
+
/* @__PURE__ */ jsxs("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
|
|
1288
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
1289
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
1290
|
+
/* @__PURE__ */ jsx3("i", {})
|
|
1291
|
+
] }),
|
|
1292
|
+
/* @__PURE__ */ jsx3("span", { className: "ss-w-greeting-text", children: text })
|
|
1293
|
+
] }),
|
|
1213
1294
|
onDismiss ? /* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null
|
|
1214
1295
|
] });
|
|
1215
1296
|
}
|
|
1216
1297
|
|
|
1217
1298
|
// src/components/ChatFab.tsx
|
|
1218
1299
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1219
|
-
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss" }) {
|
|
1300
|
+
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
|
|
1220
1301
|
const bubble = popupText ?? greeting;
|
|
1221
|
-
|
|
1302
|
+
const [intro, setIntro] = useState3(false);
|
|
1303
|
+
const armedRef = useRef4(introAllowed);
|
|
1304
|
+
useEffect4(() => {
|
|
1305
|
+
if (armedRef.current && bubble) {
|
|
1306
|
+
armedRef.current = false;
|
|
1307
|
+
setIntro(true);
|
|
1308
|
+
onIntroStart?.();
|
|
1309
|
+
}
|
|
1310
|
+
}, [bubble, onIntroStart]);
|
|
1311
|
+
return /* @__PURE__ */ jsxs2("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
|
|
1222
1312
|
bubble ? /* @__PURE__ */ jsx4(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel }) : null,
|
|
1223
1313
|
/* @__PURE__ */ jsx4("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ jsx4(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
|
|
1224
1314
|
] });
|
|
1225
1315
|
}
|
|
1226
1316
|
|
|
1227
1317
|
// src/components/ChatPanel.tsx
|
|
1228
|
-
import { useEffect as
|
|
1318
|
+
import { useEffect as useEffect9, useState as useState17 } from "react";
|
|
1229
1319
|
|
|
1230
1320
|
// src/components/ChatHeader.tsx
|
|
1231
1321
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -1238,7 +1328,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat", logoUrl, headerTitle }
|
|
|
1238
1328
|
}
|
|
1239
1329
|
|
|
1240
1330
|
// src/components/MessageList.tsx
|
|
1241
|
-
import { useEffect as
|
|
1331
|
+
import { useEffect as useEffect8, useRef as useRef6 } from "react";
|
|
1242
1332
|
|
|
1243
1333
|
// src/components/Markdown.tsx
|
|
1244
1334
|
import ReactMarkdown from "react-markdown";
|
|
@@ -1256,7 +1346,7 @@ function Markdown({ text }) {
|
|
|
1256
1346
|
}
|
|
1257
1347
|
|
|
1258
1348
|
// src/components/EntityCardList.tsx
|
|
1259
|
-
import { useState as
|
|
1349
|
+
import { useState as useState4 } from "react";
|
|
1260
1350
|
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1261
1351
|
var MAX_VISIBLE = 3;
|
|
1262
1352
|
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
@@ -1340,7 +1430,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
|
|
|
1340
1430
|
)) });
|
|
1341
1431
|
}
|
|
1342
1432
|
function EntityCardItem({ c }) {
|
|
1343
|
-
const [active, setActive] =
|
|
1433
|
+
const [active, setActive] = useState4(0);
|
|
1344
1434
|
const hasBody = c.scopes.length > 0;
|
|
1345
1435
|
if (!hasBody) {
|
|
1346
1436
|
return /* @__PURE__ */ jsx7("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx7(CardHeader, { c, showScopeCrest: false }) });
|
|
@@ -1354,7 +1444,7 @@ function EntityCardItem({ c }) {
|
|
|
1354
1444
|
] });
|
|
1355
1445
|
}
|
|
1356
1446
|
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1357
|
-
const [expanded, setExpanded] =
|
|
1447
|
+
const [expanded, setExpanded] = useState4(false);
|
|
1358
1448
|
if (cards.length === 0) return null;
|
|
1359
1449
|
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1360
1450
|
const overflow = cards.length - MAX_VISIBLE;
|
|
@@ -1365,18 +1455,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
1365
1455
|
}
|
|
1366
1456
|
|
|
1367
1457
|
// src/components/BettingInsightList.tsx
|
|
1368
|
-
import { useState as
|
|
1458
|
+
import { useState as useState8 } from "react";
|
|
1369
1459
|
|
|
1370
1460
|
// src/components/AddToSlipButton.tsx
|
|
1371
|
-
import { useCallback as useCallback3, useState as
|
|
1461
|
+
import { useCallback as useCallback3, useState as useState5 } from "react";
|
|
1372
1462
|
import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
|
|
1373
1463
|
|
|
1374
1464
|
// src/components/Toast.tsx
|
|
1375
|
-
import { useEffect as
|
|
1465
|
+
import { useEffect as useEffect5 } from "react";
|
|
1376
1466
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1377
1467
|
var DISMISS_MS = 4e3;
|
|
1378
1468
|
function Toast({ toast, onDismiss }) {
|
|
1379
|
-
|
|
1469
|
+
useEffect5(() => {
|
|
1380
1470
|
if (!toast) return;
|
|
1381
1471
|
const timer = setTimeout(onDismiss, DISMISS_MS);
|
|
1382
1472
|
return () => clearTimeout(timer);
|
|
@@ -1394,9 +1484,9 @@ function withTimeout(value) {
|
|
|
1394
1484
|
]);
|
|
1395
1485
|
}
|
|
1396
1486
|
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
1397
|
-
const [pending, setPending] =
|
|
1398
|
-
const [settled, setSettled] =
|
|
1399
|
-
const [toast, setToast] =
|
|
1487
|
+
const [pending, setPending] = useState5(false);
|
|
1488
|
+
const [settled, setSettled] = useState5(false);
|
|
1489
|
+
const [toast, setToast] = useState5(null);
|
|
1400
1490
|
const dismiss = useCallback3(() => setToast(null), []);
|
|
1401
1491
|
const handler = slip.onAddToSlip;
|
|
1402
1492
|
if (!ui || !handler || !selection) return null;
|
|
@@ -1461,14 +1551,14 @@ function OddsMovementBadge({
|
|
|
1461
1551
|
}
|
|
1462
1552
|
|
|
1463
1553
|
// src/components/Crest.tsx
|
|
1464
|
-
import { useState as
|
|
1554
|
+
import { useState as useState6 } from "react";
|
|
1465
1555
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1466
1556
|
function initials2(name) {
|
|
1467
1557
|
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1468
1558
|
}
|
|
1469
1559
|
function Crest2({ url, name, kind }) {
|
|
1470
1560
|
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1471
|
-
const [failed, setFailed] =
|
|
1561
|
+
const [failed, setFailed] = useState6(false);
|
|
1472
1562
|
if (url && !failed) {
|
|
1473
1563
|
return /* @__PURE__ */ jsx11("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1474
1564
|
}
|
|
@@ -1476,10 +1566,15 @@ function Crest2({ url, name, kind }) {
|
|
|
1476
1566
|
}
|
|
1477
1567
|
|
|
1478
1568
|
// src/components/PinToggle.tsx
|
|
1479
|
-
import { useCallback as useCallback4, useState as
|
|
1569
|
+
import { useCallback as useCallback4, useState as useState7 } from "react";
|
|
1480
1570
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1571
|
+
var PIN_GLYPHS = {
|
|
1572
|
+
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" },
|
|
1573
|
+
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" },
|
|
1574
|
+
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" }
|
|
1575
|
+
};
|
|
1481
1576
|
function PinToggle({ pin, monitor, ui }) {
|
|
1482
|
-
const [toast, setToast] =
|
|
1577
|
+
const [toast, setToast] = useState7(null);
|
|
1483
1578
|
const dismiss = useCallback4(() => setToast(null), []);
|
|
1484
1579
|
if (!monitor || !monitor.enabled) return null;
|
|
1485
1580
|
const key = pinKey(pin);
|
|
@@ -1493,6 +1588,7 @@ function PinToggle({ pin, monitor, ui }) {
|
|
|
1493
1588
|
setToast({ kind: "error", text: ui.marketLimitToast });
|
|
1494
1589
|
}
|
|
1495
1590
|
};
|
|
1591
|
+
const glyph = PIN_GLYPHS[ui.pinIcon];
|
|
1496
1592
|
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-pin-wrap", children: [
|
|
1497
1593
|
/* @__PURE__ */ jsx12(
|
|
1498
1594
|
"button",
|
|
@@ -1500,10 +1596,22 @@ function PinToggle({ pin, monitor, ui }) {
|
|
|
1500
1596
|
type: "button",
|
|
1501
1597
|
className: "ss-w-pin",
|
|
1502
1598
|
"data-on": pinned || void 0,
|
|
1599
|
+
"data-icon": ui.pinIcon,
|
|
1503
1600
|
"aria-pressed": pinned,
|
|
1504
1601
|
"aria-label": pinned ? labels.unpin : labels.pin,
|
|
1505
1602
|
onClick,
|
|
1506
|
-
children: /* @__PURE__ */ jsx12("svg", { viewBox:
|
|
1603
|
+
children: /* @__PURE__ */ jsx12("svg", { viewBox: glyph.viewBox, "aria-hidden": "true", children: /* @__PURE__ */ jsx12(
|
|
1604
|
+
"path",
|
|
1605
|
+
{
|
|
1606
|
+
transform: glyph.transform,
|
|
1607
|
+
d: glyph.d,
|
|
1608
|
+
fill: pinned ? "currentColor" : "none",
|
|
1609
|
+
stroke: pinned ? "none" : "currentColor",
|
|
1610
|
+
strokeWidth: glyph.strokeWidth,
|
|
1611
|
+
strokeLinejoin: "round",
|
|
1612
|
+
strokeLinecap: "round"
|
|
1613
|
+
}
|
|
1614
|
+
) })
|
|
1507
1615
|
}
|
|
1508
1616
|
),
|
|
1509
1617
|
/* @__PURE__ */ jsx12(Toast, { toast, onDismiss: dismiss })
|
|
@@ -1519,7 +1627,7 @@ function StatRows({ stats }) {
|
|
|
1519
1627
|
] }, `${s.label}:${s.value}`)) });
|
|
1520
1628
|
}
|
|
1521
1629
|
function ScopedStats({ scopes }) {
|
|
1522
|
-
const [active, setActive] =
|
|
1630
|
+
const [active, setActive] = useState8(0);
|
|
1523
1631
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1524
1632
|
return /* @__PURE__ */ jsxs8("div", { className: "ss-w-bi-scoped", children: [
|
|
1525
1633
|
/* @__PURE__ */ jsx13("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx13("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
@@ -1530,7 +1638,7 @@ function hasStatsContent(it) {
|
|
|
1530
1638
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1531
1639
|
}
|
|
1532
1640
|
function ReasonStrip({ it, ui }) {
|
|
1533
|
-
const [open, setOpen] =
|
|
1641
|
+
const [open, setOpen] = useState8(false);
|
|
1534
1642
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1535
1643
|
const hasStats = hasStatsContent(it);
|
|
1536
1644
|
const hasText = !!it.text;
|
|
@@ -1640,7 +1748,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
1640
1748
|
}
|
|
1641
1749
|
|
|
1642
1750
|
// src/components/MarketOddsCardList.tsx
|
|
1643
|
-
import { useState as
|
|
1751
|
+
import { useState as useState9 } from "react";
|
|
1644
1752
|
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1645
1753
|
function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
1646
1754
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
@@ -1656,48 +1764,50 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
1656
1764
|
/* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
1657
1765
|
] });
|
|
1658
1766
|
}
|
|
1659
|
-
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
|
|
1660
|
-
const [open, setOpen] =
|
|
1767
|
+
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader }) {
|
|
1768
|
+
const [open, setOpen] = useState9(false);
|
|
1661
1769
|
const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
1662
1770
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
1663
1771
|
const showPin = !!monitor && vm.pinEnabled;
|
|
1664
1772
|
const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
|
|
1665
1773
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-mocard", children: [
|
|
1666
|
-
|
|
1667
|
-
/* @__PURE__ */
|
|
1668
|
-
/* @__PURE__ */ jsx14(
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
/* @__PURE__ */
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
kickoff
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
hasNamedTeams ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-
|
|
1693
|
-
/* @__PURE__ */
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1774
|
+
!hideHeader && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1775
|
+
showHeader ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-header", children: [
|
|
1776
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1777
|
+
/* @__PURE__ */ jsx14(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
|
|
1778
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-comp", children: vm.competition })
|
|
1779
|
+
] }) : null }),
|
|
1780
|
+
/* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-header-right", children: [
|
|
1781
|
+
vm.isLive ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-live", children: [
|
|
1782
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1783
|
+
ui?.liveLabel ?? "Live"
|
|
1784
|
+
] }) : null,
|
|
1785
|
+
kickoff ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-kick", children: [
|
|
1786
|
+
kickoff.dayLabel,
|
|
1787
|
+
" ",
|
|
1788
|
+
kickoff.time
|
|
1789
|
+
] }) : null,
|
|
1790
|
+
showPin && ui ? /* @__PURE__ */ jsx14(
|
|
1791
|
+
PinToggle,
|
|
1792
|
+
{
|
|
1793
|
+
ui,
|
|
1794
|
+
monitor,
|
|
1795
|
+
pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
|
|
1796
|
+
}
|
|
1797
|
+
) : null
|
|
1798
|
+
] })
|
|
1799
|
+
] }) : null,
|
|
1800
|
+
hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-mo-sub", children: [
|
|
1801
|
+
hasNamedTeams ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-fixture", children: [
|
|
1802
|
+
/* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
|
|
1803
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
|
|
1804
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1805
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
|
|
1806
|
+
/* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
|
|
1807
|
+
] }) : vm.fixture ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
|
|
1808
|
+
vm.market ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-market", children: vm.market }) : null
|
|
1809
|
+
] }) : null
|
|
1810
|
+
] }),
|
|
1701
1811
|
/* @__PURE__ */ jsxs9("div", { className: "ss-w-mo-rows", children: [
|
|
1702
1812
|
vm.mainRows.map((row) => /* @__PURE__ */ jsx14(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)),
|
|
1703
1813
|
open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx14(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)) : null
|
|
@@ -1710,9 +1820,9 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
|
|
|
1710
1820
|
vm.disclaimer ? /* @__PURE__ */ jsx14("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
1711
1821
|
] });
|
|
1712
1822
|
}
|
|
1713
|
-
function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds }) {
|
|
1823
|
+
function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader }) {
|
|
1714
1824
|
if (!cards || cards.length === 0) return null;
|
|
1715
|
-
return /* @__PURE__ */ jsx14("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx14(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds }, vm.id)) });
|
|
1825
|
+
return /* @__PURE__ */ jsx14("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx14(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds, hideHeader }, vm.id)) });
|
|
1716
1826
|
}
|
|
1717
1827
|
|
|
1718
1828
|
// src/components/OddsMovementCard.tsx
|
|
@@ -1950,7 +2060,7 @@ function FixtureCard({ card }) {
|
|
|
1950
2060
|
}
|
|
1951
2061
|
|
|
1952
2062
|
// src/components/dashboard/CountdownCard.tsx
|
|
1953
|
-
import { Fragment as Fragment6, useEffect as
|
|
2063
|
+
import { Fragment as Fragment6, useEffect as useEffect6, useState as useState10 } from "react";
|
|
1954
2064
|
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1955
2065
|
var DAY_MS = 864e5;
|
|
1956
2066
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -1969,12 +2079,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
|
1969
2079
|
function CountdownCard({ card }) {
|
|
1970
2080
|
const { data } = card;
|
|
1971
2081
|
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
1972
|
-
const [nowMs, setNowMs] =
|
|
1973
|
-
const [reduced] =
|
|
2082
|
+
const [nowMs, setNowMs] = useState10(() => Date.now());
|
|
2083
|
+
const [reduced] = useState10(
|
|
1974
2084
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
1975
2085
|
);
|
|
1976
2086
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
1977
|
-
|
|
2087
|
+
useEffect6(() => {
|
|
1978
2088
|
if (reduced) return;
|
|
1979
2089
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
1980
2090
|
return () => window.clearInterval(id);
|
|
@@ -1993,7 +2103,7 @@ function CountdownCard({ card }) {
|
|
|
1993
2103
|
}
|
|
1994
2104
|
|
|
1995
2105
|
// src/components/dashboard/InjuriesCard.tsx
|
|
1996
|
-
import { useState as
|
|
2106
|
+
import { useState as useState11 } from "react";
|
|
1997
2107
|
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1998
2108
|
var SHOWN = 3;
|
|
1999
2109
|
function ColHead({ name, crestUrl }) {
|
|
@@ -2016,7 +2126,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
|
|
|
2016
2126
|
}
|
|
2017
2127
|
function InjuriesCard({ card, ui }) {
|
|
2018
2128
|
const { data } = card;
|
|
2019
|
-
const [expanded, setExpanded] =
|
|
2129
|
+
const [expanded, setExpanded] = useState11(false);
|
|
2020
2130
|
const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
|
|
2021
2131
|
const limit = expanded ? void 0 : SHOWN;
|
|
2022
2132
|
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
@@ -2120,7 +2230,7 @@ function LinksCard({ card }) {
|
|
|
2120
2230
|
}
|
|
2121
2231
|
|
|
2122
2232
|
// src/components/dashboard/PostMatchResultCard.tsx
|
|
2123
|
-
import { useState as
|
|
2233
|
+
import { useState as useState12 } from "react";
|
|
2124
2234
|
import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2125
2235
|
function initials3(name) {
|
|
2126
2236
|
return name.trim().slice(0, 3).toUpperCase();
|
|
@@ -2130,7 +2240,7 @@ function PostMatchCrest({
|
|
|
2130
2240
|
name,
|
|
2131
2241
|
side
|
|
2132
2242
|
}) {
|
|
2133
|
-
const [failed, setFailed] =
|
|
2243
|
+
const [failed, setFailed] = useState12(false);
|
|
2134
2244
|
const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
|
|
2135
2245
|
if (url && !failed) {
|
|
2136
2246
|
return /* @__PURE__ */ jsx27("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2329,10 +2439,10 @@ function RestingFormCard({ card }) {
|
|
|
2329
2439
|
}
|
|
2330
2440
|
|
|
2331
2441
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
2332
|
-
import { useRef as
|
|
2442
|
+
import { useRef as useRef5, useState as useState14 } from "react";
|
|
2333
2443
|
|
|
2334
2444
|
// src/useLiveClock.ts
|
|
2335
|
-
import { useEffect as
|
|
2445
|
+
import { useEffect as useEffect7, useState as useState13 } from "react";
|
|
2336
2446
|
var TICK_MS = 6e4;
|
|
2337
2447
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2338
2448
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2341,10 +2451,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2341
2451
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2342
2452
|
}
|
|
2343
2453
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2344
|
-
const [displayMinute, setDisplayMinute] =
|
|
2454
|
+
const [displayMinute, setDisplayMinute] = useState13(
|
|
2345
2455
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2346
2456
|
);
|
|
2347
|
-
|
|
2457
|
+
useEffect7(() => {
|
|
2348
2458
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2349
2459
|
if (!clockRunning) return;
|
|
2350
2460
|
const id = window.setInterval(() => {
|
|
@@ -2361,7 +2471,7 @@ function initials5(name) {
|
|
|
2361
2471
|
return name.trim().slice(0, 3).toUpperCase();
|
|
2362
2472
|
}
|
|
2363
2473
|
function LiveCrest({ url, name, side }) {
|
|
2364
|
-
const [failed, setFailed] =
|
|
2474
|
+
const [failed, setFailed] = useState14(false);
|
|
2365
2475
|
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
2366
2476
|
if (url && !failed) {
|
|
2367
2477
|
return /* @__PURE__ */ jsx36("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2380,7 +2490,7 @@ function LiveScoreCard({
|
|
|
2380
2490
|
}) {
|
|
2381
2491
|
const { data } = card;
|
|
2382
2492
|
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
2383
|
-
const seedRef =
|
|
2493
|
+
const seedRef = useRef5(null);
|
|
2384
2494
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
2385
2495
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
2386
2496
|
}
|
|
@@ -2420,7 +2530,7 @@ function LiveScoreCard({
|
|
|
2420
2530
|
}
|
|
2421
2531
|
|
|
2422
2532
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
2423
|
-
import { useState as
|
|
2533
|
+
import { useState as useState15 } from "react";
|
|
2424
2534
|
import { jsx as jsx37, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2425
2535
|
var SHOWN2 = 3;
|
|
2426
2536
|
function EventIcon({ type }) {
|
|
@@ -2462,7 +2572,7 @@ function EventRow({ e }) {
|
|
|
2462
2572
|
] });
|
|
2463
2573
|
}
|
|
2464
2574
|
function LiveTimelineCard({ card, ui }) {
|
|
2465
|
-
const [expanded, setExpanded] =
|
|
2575
|
+
const [expanded, setExpanded] = useState15(false);
|
|
2466
2576
|
const events = card.data.events;
|
|
2467
2577
|
if (!events || events.length === 0) return null;
|
|
2468
2578
|
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
@@ -2702,11 +2812,11 @@ function turnAnchor(messages) {
|
|
|
2702
2812
|
}
|
|
2703
2813
|
function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
2704
2814
|
const { state, send } = controller;
|
|
2705
|
-
const listRef =
|
|
2706
|
-
const endRef =
|
|
2707
|
-
const pinnedRef =
|
|
2708
|
-
const anchoredTurnRef =
|
|
2709
|
-
|
|
2815
|
+
const listRef = useRef6(null);
|
|
2816
|
+
const endRef = useRef6(null);
|
|
2817
|
+
const pinnedRef = useRef6(true);
|
|
2818
|
+
const anchoredTurnRef = useRef6(null);
|
|
2819
|
+
useEffect8(() => {
|
|
2710
2820
|
const anchor = turnAnchor(state.messages);
|
|
2711
2821
|
const list = listRef.current;
|
|
2712
2822
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -2762,10 +2872,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
2762
2872
|
}
|
|
2763
2873
|
|
|
2764
2874
|
// src/components/ChatInput.tsx
|
|
2765
|
-
import { useState as
|
|
2875
|
+
import { useState as useState16 } from "react";
|
|
2766
2876
|
import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2767
2877
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
2768
|
-
const [value, setValue] =
|
|
2878
|
+
const [value, setValue] = useState16("");
|
|
2769
2879
|
const submit = () => {
|
|
2770
2880
|
const t = value.trim();
|
|
2771
2881
|
if (!t) return;
|
|
@@ -2822,8 +2932,63 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
|
|
|
2822
2932
|
}) });
|
|
2823
2933
|
}
|
|
2824
2934
|
|
|
2825
|
-
// src/components/
|
|
2935
|
+
// src/components/MarketAccordion.tsx
|
|
2826
2936
|
import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
2937
|
+
function MarketAccordion({ match, monitor, ui, slip }) {
|
|
2938
|
+
const markets = match.availableMarkets ?? [];
|
|
2939
|
+
if (markets.length === 0) return null;
|
|
2940
|
+
const open = monitor.openMarket[match.matchId] ?? null;
|
|
2941
|
+
return /* @__PURE__ */ jsx46("div", { className: "ss-w-acc", children: markets.map((m) => {
|
|
2942
|
+
const isOpen = open === m.marketDeveloperName;
|
|
2943
|
+
const key = `${match.matchId}:${m.marketDeveloperName}`;
|
|
2944
|
+
const entry = monitor.marketOdds[key];
|
|
2945
|
+
return /* @__PURE__ */ jsxs40("div", { className: isOpen ? "ss-w-acc-row ss-w-acc-row-open" : "ss-w-acc-row", children: [
|
|
2946
|
+
/* @__PURE__ */ jsxs40(
|
|
2947
|
+
"button",
|
|
2948
|
+
{
|
|
2949
|
+
type: "button",
|
|
2950
|
+
className: "ss-w-acc-head",
|
|
2951
|
+
onClick: () => monitor.toggleMarket(match.matchId, m.marketDeveloperName),
|
|
2952
|
+
children: [
|
|
2953
|
+
/* @__PURE__ */ jsx46("span", { className: "ss-w-acc-chevron", children: isOpen ? "\u25BE" : "\u25B8" }),
|
|
2954
|
+
/* @__PURE__ */ jsx46("span", { className: "ss-w-acc-label", children: m.marketLabel }),
|
|
2955
|
+
m.hasInsight && /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-badge", children: "\u2605" }),
|
|
2956
|
+
m.suspended && /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-susp", children: ui.accordionSuspended })
|
|
2957
|
+
]
|
|
2958
|
+
}
|
|
2959
|
+
),
|
|
2960
|
+
isOpen && /* @__PURE__ */ jsxs40("div", { className: "ss-w-acc-panel", children: [
|
|
2961
|
+
entry?.error && /* @__PURE__ */ jsx46(
|
|
2962
|
+
"div",
|
|
2963
|
+
{
|
|
2964
|
+
className: "ss-w-acc-retry",
|
|
2965
|
+
onClick: () => monitor.retryMarket(match.matchId, m.marketDeveloperName),
|
|
2966
|
+
children: ui.accordionRetry
|
|
2967
|
+
}
|
|
2968
|
+
),
|
|
2969
|
+
entry?.block?.insight?.text && /* @__PURE__ */ jsxs40("div", { className: "ss-w-acc-insight", children: [
|
|
2970
|
+
/* @__PURE__ */ jsx46("span", { className: "ss-w-acc-badge", children: ui.accordionValueLabel }),
|
|
2971
|
+
" ",
|
|
2972
|
+
entry.block.insight.text
|
|
2973
|
+
] }),
|
|
2974
|
+
entry?.block?.card && /* @__PURE__ */ jsx46(
|
|
2975
|
+
MarketOddsCardList,
|
|
2976
|
+
{
|
|
2977
|
+
cards: [toMarketOddsVM(entry.block.card)],
|
|
2978
|
+
ui,
|
|
2979
|
+
slip,
|
|
2980
|
+
monitor,
|
|
2981
|
+
inSlipIds: monitor.inSlip,
|
|
2982
|
+
hideHeader: true
|
|
2983
|
+
}
|
|
2984
|
+
)
|
|
2985
|
+
] })
|
|
2986
|
+
] }, m.marketDeveloperName);
|
|
2987
|
+
}) });
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
// src/components/MonitorMatchCard.tsx
|
|
2991
|
+
import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
2827
2992
|
function chipSelection(row, matchId, conversationId) {
|
|
2828
2993
|
const chip = row.market;
|
|
2829
2994
|
if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== "number" || typeof chip.price !== "number") return null;
|
|
@@ -2846,63 +3011,63 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
2846
3011
|
const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins));
|
|
2847
3012
|
const orderedRows = [...promotedRows, ...otherRows];
|
|
2848
3013
|
const kickoff = match.phase === "preMatch" && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : void 0;
|
|
2849
|
-
return /* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
2851
|
-
live && /* @__PURE__ */
|
|
2852
|
-
/* @__PURE__ */
|
|
3014
|
+
return /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon", children: [
|
|
3015
|
+
/* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-top", children: [
|
|
3016
|
+
live && /* @__PURE__ */ jsxs41("span", { className: "ss-w-fandash-live-pill", children: [
|
|
3017
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
|
|
2853
3018
|
ui.liveLabel
|
|
2854
3019
|
] }),
|
|
2855
|
-
match.phase === "fullTime" && /* @__PURE__ */
|
|
2856
|
-
kickoff && /* @__PURE__ */
|
|
3020
|
+
match.phase === "fullTime" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
|
|
3021
|
+
kickoff && /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-pill", children: [
|
|
2857
3022
|
kickoff.dayLabel,
|
|
2858
3023
|
" \xB7 ",
|
|
2859
3024
|
kickoff.time
|
|
2860
3025
|
] }),
|
|
2861
|
-
live && match.minuteLabel && /* @__PURE__ */
|
|
2862
|
-
match.competitionName && /* @__PURE__ */
|
|
2863
|
-
/* @__PURE__ */
|
|
3026
|
+
live && match.minuteLabel && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
|
|
3027
|
+
match.competitionName && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-comp", children: match.competitionName }),
|
|
3028
|
+
/* @__PURE__ */ jsx47(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
|
|
2864
3029
|
] }),
|
|
2865
|
-
/* @__PURE__ */
|
|
2866
|
-
/* @__PURE__ */
|
|
2867
|
-
/* @__PURE__ */
|
|
2868
|
-
/* @__PURE__ */
|
|
3030
|
+
/* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-main", children: [
|
|
3031
|
+
/* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-side", children: [
|
|
3032
|
+
/* @__PURE__ */ jsx47(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
|
|
3033
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: match.homeTeamName })
|
|
2869
3034
|
] }),
|
|
2870
|
-
match.phase === "preMatch" ? /* @__PURE__ */
|
|
3035
|
+
match.phase === "preMatch" ? /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-score", children: [
|
|
2871
3036
|
match.homeScore,
|
|
2872
|
-
/* @__PURE__ */
|
|
3037
|
+
/* @__PURE__ */ jsx47("i", { children: "\u2013" }),
|
|
2873
3038
|
match.awayScore
|
|
2874
3039
|
] }),
|
|
2875
|
-
/* @__PURE__ */
|
|
2876
|
-
/* @__PURE__ */
|
|
2877
|
-
/* @__PURE__ */
|
|
3040
|
+
/* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
|
|
3041
|
+
/* @__PURE__ */ jsx47(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
|
|
3042
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: match.awayTeamName })
|
|
2878
3043
|
] })
|
|
2879
3044
|
] }),
|
|
2880
|
-
scorers.length > 0 && /* @__PURE__ */
|
|
2881
|
-
/* @__PURE__ */
|
|
3045
|
+
scorers.length > 0 && /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
|
|
3046
|
+
/* @__PURE__ */ jsx47("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
|
|
2882
3047
|
const total = row.homeNum + row.awayNum;
|
|
2883
3048
|
const homePct = total > 0 ? row.homeNum / total * 75 : 0;
|
|
2884
3049
|
const awayPct = total > 0 ? row.awayNum / total * 75 : 0;
|
|
2885
3050
|
const promoted = isPromoted(row, promotedPins);
|
|
2886
3051
|
const selection = chipSelection(row, match.matchId, slip.conversationId);
|
|
2887
|
-
return /* @__PURE__ */
|
|
2888
|
-
/* @__PURE__ */
|
|
2889
|
-
/* @__PURE__ */
|
|
2890
|
-
/* @__PURE__ */
|
|
2891
|
-
/* @__PURE__ */
|
|
3052
|
+
return /* @__PURE__ */ jsxs41("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
|
|
3053
|
+
/* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-stat-row", children: [
|
|
3054
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
|
|
3055
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-l", children: row.label }),
|
|
3056
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
|
|
2892
3057
|
] }),
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
/* @__PURE__ */
|
|
3058
|
+
/* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-bar", children: [
|
|
3059
|
+
/* @__PURE__ */ jsx47("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
|
|
3060
|
+
/* @__PURE__ */ jsx47("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
|
|
2896
3061
|
] }),
|
|
2897
|
-
row.market && /* @__PURE__ */
|
|
2898
|
-
/* @__PURE__ */
|
|
3062
|
+
row.market && /* @__PURE__ */ jsxs41("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
|
|
3063
|
+
/* @__PURE__ */ jsxs41("span", { children: [
|
|
2899
3064
|
row.market.marketLabel,
|
|
2900
3065
|
" \xB7 ",
|
|
2901
3066
|
row.market.selectionLabel
|
|
2902
3067
|
] }),
|
|
2903
|
-
/* @__PURE__ */
|
|
2904
|
-
row.market.isSuspended ? /* @__PURE__ */
|
|
2905
|
-
/* @__PURE__ */
|
|
3068
|
+
/* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-stat-mkt-right", children: [
|
|
3069
|
+
row.market.isSuspended ? /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
|
|
3070
|
+
/* @__PURE__ */ jsx47(
|
|
2906
3071
|
SlipButton,
|
|
2907
3072
|
{
|
|
2908
3073
|
selection,
|
|
@@ -2916,68 +3081,69 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
|
|
|
2916
3081
|
] })
|
|
2917
3082
|
] }, row.label);
|
|
2918
3083
|
}) }),
|
|
2919
|
-
match.status === "stale" && /* @__PURE__ */
|
|
2920
|
-
match.momentum.length > 0 && /* @__PURE__ */
|
|
2921
|
-
/* @__PURE__ */
|
|
2922
|
-
/* @__PURE__ */
|
|
2923
|
-
/* @__PURE__ */
|
|
2924
|
-
/* @__PURE__ */
|
|
3084
|
+
match.status === "stale" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
|
|
3085
|
+
match.momentum.length > 0 && /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-mom", children: [
|
|
3086
|
+
/* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-stat-row", children: [
|
|
3087
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
|
|
3088
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
|
|
3089
|
+
/* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
|
|
2925
3090
|
] }),
|
|
2926
|
-
/* @__PURE__ */
|
|
3091
|
+
/* @__PURE__ */ jsx47(MomentumWave, { points: match.momentum, clubIsHome: true })
|
|
2927
3092
|
] }),
|
|
2928
|
-
match.
|
|
2929
|
-
match.phase === "fullTime" && /* @__PURE__ */ jsx46("div", { className: "ss-w-mon-grace", children: ui.graceNote })
|
|
3093
|
+
match.phase === "fullTime" && /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-grace", children: ui.graceNote })
|
|
2930
3094
|
] });
|
|
2931
3095
|
}
|
|
2932
3096
|
|
|
2933
3097
|
// src/components/MonitorTabs.tsx
|
|
2934
|
-
import { jsx as
|
|
3098
|
+
import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
2935
3099
|
function ContextLine({ m, monitor, ui }) {
|
|
2936
3100
|
const kick = m.kickoffUtc ? ui.bettingKickoff(m.kickoffUtc) : void 0;
|
|
2937
|
-
return /* @__PURE__ */
|
|
2938
|
-
/* @__PURE__ */
|
|
2939
|
-
/* @__PURE__ */
|
|
2940
|
-
/* @__PURE__ */
|
|
3101
|
+
return /* @__PURE__ */ jsxs42("div", { className: "ss-w-mk-ctx", children: [
|
|
3102
|
+
/* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-side", children: [
|
|
3103
|
+
/* @__PURE__ */ jsx48(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
|
|
3104
|
+
/* @__PURE__ */ jsx48("span", { className: "ss-w-mon-name", children: m.homeTeamName })
|
|
2941
3105
|
] }),
|
|
2942
|
-
m.phase === "preMatch" ? kick && /* @__PURE__ */
|
|
3106
|
+
m.phase === "preMatch" ? kick && /* @__PURE__ */ jsxs42("span", { className: "ss-w-mon-pill", children: [
|
|
2943
3107
|
kick.dayLabel,
|
|
2944
3108
|
" ",
|
|
2945
3109
|
kick.time
|
|
2946
|
-
] }) : typeof m.homeScore === "number" && /* @__PURE__ */
|
|
3110
|
+
] }) : typeof m.homeScore === "number" && /* @__PURE__ */ jsxs42("b", { children: [
|
|
2947
3111
|
m.homeScore,
|
|
2948
3112
|
"\u2013",
|
|
2949
3113
|
m.awayScore
|
|
2950
3114
|
] }),
|
|
2951
|
-
/* @__PURE__ */
|
|
2952
|
-
/* @__PURE__ */
|
|
2953
|
-
/* @__PURE__ */
|
|
3115
|
+
/* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-side", children: [
|
|
3116
|
+
/* @__PURE__ */ jsx48("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
|
|
3117
|
+
/* @__PURE__ */ jsx48(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
|
|
2954
3118
|
] }),
|
|
2955
|
-
m.minuteLabel && /* @__PURE__ */
|
|
2956
|
-
/* @__PURE__ */
|
|
2957
|
-
m.isSuspended && !m.isSettled && /* @__PURE__ */
|
|
2958
|
-
m.isSettled && /* @__PURE__ */
|
|
2959
|
-
m.status === "stale" && /* @__PURE__ */
|
|
3119
|
+
m.minuteLabel && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
|
|
3120
|
+
/* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-right", children: [
|
|
3121
|
+
m.isSuspended && !m.isSettled && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
|
|
3122
|
+
m.isSettled && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
|
|
3123
|
+
m.status === "stale" && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
|
|
2960
3124
|
(() => {
|
|
2961
3125
|
const pin = monitor.pins.find((p) => p.key === m.key);
|
|
2962
|
-
return pin ? /* @__PURE__ */
|
|
3126
|
+
return pin ? /* @__PURE__ */ jsx48(PinToggle, { ui, monitor, pin }) : null;
|
|
2963
3127
|
})()
|
|
2964
3128
|
] })
|
|
2965
3129
|
] });
|
|
2966
3130
|
}
|
|
2967
3131
|
function MatchesPanel({ monitor, ui, slip }) {
|
|
2968
3132
|
const matches = (monitor.snapshot?.matches ?? []).filter((m) => monitor.pins.some((p) => p.kind === "match" && p.matchId === m.matchId));
|
|
2969
|
-
if (matches.length === 0) return /* @__PURE__ */
|
|
2970
|
-
return /* @__PURE__ */
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
3133
|
+
if (matches.length === 0) return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
|
|
3134
|
+
return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ jsxs42("div", { className: "ss-w-mon-item", children: [
|
|
3135
|
+
/* @__PURE__ */ jsx48(
|
|
3136
|
+
MonitorMatchCard,
|
|
3137
|
+
{
|
|
3138
|
+
match: m,
|
|
3139
|
+
promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
|
|
3140
|
+
monitor,
|
|
3141
|
+
ui,
|
|
3142
|
+
slip
|
|
3143
|
+
}
|
|
3144
|
+
),
|
|
3145
|
+
/* @__PURE__ */ jsx48(MarketAccordion, { match: m, monitor, ui, slip })
|
|
3146
|
+
] }, m.matchId)) });
|
|
2981
3147
|
}
|
|
2982
3148
|
function withSinceViewMovement(vm, prev) {
|
|
2983
3149
|
const primary = vm.mainRows[0];
|
|
@@ -2991,10 +3157,10 @@ function withSinceViewMovement(vm, prev) {
|
|
|
2991
3157
|
}
|
|
2992
3158
|
function OddsPanel({ monitor, ui, slip }) {
|
|
2993
3159
|
const markets = (monitor.snapshot?.markets ?? []).filter((m) => monitor.pins.some((p) => p.key === m.key));
|
|
2994
|
-
if (markets.length === 0) return /* @__PURE__ */
|
|
2995
|
-
return /* @__PURE__ */
|
|
2996
|
-
/* @__PURE__ */
|
|
2997
|
-
m.card && /* @__PURE__ */
|
|
3160
|
+
if (markets.length === 0) return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
|
|
3161
|
+
return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ jsxs42("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
|
|
3162
|
+
/* @__PURE__ */ jsx48(ContextLine, { m, monitor, ui }),
|
|
3163
|
+
m.card && /* @__PURE__ */ jsx48(
|
|
2998
3164
|
MarketOddsCardList,
|
|
2999
3165
|
{
|
|
3000
3166
|
cards: [withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])],
|
|
@@ -3003,17 +3169,17 @@ function OddsPanel({ monitor, ui, slip }) {
|
|
|
3003
3169
|
inSlipIds: monitor.inSlip
|
|
3004
3170
|
}
|
|
3005
3171
|
),
|
|
3006
|
-
m.history && /* @__PURE__ */
|
|
3007
|
-
!m.card && !m.history && /* @__PURE__ */
|
|
3172
|
+
m.history && /* @__PURE__ */ jsx48(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
|
|
3173
|
+
!m.card && !m.history && /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
|
|
3008
3174
|
] }, m.key)) });
|
|
3009
3175
|
}
|
|
3010
3176
|
|
|
3011
3177
|
// src/components/ChatPanel.tsx
|
|
3012
|
-
import { jsx as
|
|
3178
|
+
import { jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3013
3179
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
3014
3180
|
function useIsModal() {
|
|
3015
|
-
const [modal, setModal] =
|
|
3016
|
-
|
|
3181
|
+
const [modal, setModal] = useState17(false);
|
|
3182
|
+
useEffect9(() => {
|
|
3017
3183
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
3018
3184
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
3019
3185
|
const sync = () => setModal(mql.matches);
|
|
@@ -3026,7 +3192,7 @@ function useIsModal() {
|
|
|
3026
3192
|
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3027
3193
|
const { state, close, stop, send } = controller;
|
|
3028
3194
|
const isModal = useIsModal();
|
|
3029
|
-
|
|
3195
|
+
useEffect9(() => {
|
|
3030
3196
|
const onKey = (e) => {
|
|
3031
3197
|
if (e.key === "Escape") close();
|
|
3032
3198
|
};
|
|
@@ -3037,12 +3203,12 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3037
3203
|
monitor?.setActiveTab("chat");
|
|
3038
3204
|
send(text);
|
|
3039
3205
|
};
|
|
3040
|
-
|
|
3206
|
+
useEffect9(() => {
|
|
3041
3207
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
3042
3208
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
3043
|
-
return /* @__PURE__ */
|
|
3044
|
-
/* @__PURE__ */
|
|
3045
|
-
monitor && /* @__PURE__ */
|
|
3209
|
+
return /* @__PURE__ */ jsxs43("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
3210
|
+
/* @__PURE__ */ jsx49(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
|
|
3211
|
+
monitor && /* @__PURE__ */ jsx49(
|
|
3046
3212
|
TabBar,
|
|
3047
3213
|
{
|
|
3048
3214
|
monitor,
|
|
@@ -3051,16 +3217,16 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3051
3217
|
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
|
|
3052
3218
|
}
|
|
3053
3219
|
),
|
|
3054
|
-
/* @__PURE__ */
|
|
3220
|
+
/* @__PURE__ */ jsx49(
|
|
3055
3221
|
"div",
|
|
3056
3222
|
{
|
|
3057
3223
|
style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
|
|
3058
|
-
children: /* @__PURE__ */
|
|
3224
|
+
children: /* @__PURE__ */ jsx49(MessageList, { controller, ui, slip, onDashboardTap, monitor })
|
|
3059
3225
|
}
|
|
3060
3226
|
),
|
|
3061
|
-
monitor && monitor.activeTab === "matches" && /* @__PURE__ */
|
|
3062
|
-
monitor && monitor.activeTab === "odds" && /* @__PURE__ */
|
|
3063
|
-
/* @__PURE__ */
|
|
3227
|
+
monitor && monitor.activeTab === "matches" && /* @__PURE__ */ jsx49(MatchesPanel, { monitor, ui, slip }),
|
|
3228
|
+
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ jsx49(OddsPanel, { monitor, ui, slip }),
|
|
3229
|
+
/* @__PURE__ */ jsx49(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
3064
3230
|
] });
|
|
3065
3231
|
}
|
|
3066
3232
|
|
|
@@ -3108,8 +3274,40 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
3108
3274
|
.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); }
|
|
3109
3275
|
.ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }
|
|
3110
3276
|
.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); }
|
|
3111
|
-
.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; }
|
|
3277
|
+
.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; }
|
|
3112
3278
|
.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; }
|
|
3279
|
+
.ss-w-greeting-text { display: block; }
|
|
3280
|
+
/* Typing indicator: overlays the text area so bubble height stays put; hidden at
|
|
3281
|
+
rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */
|
|
3282
|
+
.ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }
|
|
3283
|
+
.ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }
|
|
3284
|
+
/* One-shot launcher attention intro: FAB nudges, then the greeting types in.
|
|
3285
|
+
Gated behind no-preference so reduce-motion users get the greeting shown
|
|
3286
|
+
statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once
|
|
3287
|
+
per page load; every animation runs a single time and settles at rest. */
|
|
3288
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
3289
|
+
.ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }
|
|
3290
|
+
.ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }
|
|
3291
|
+
.ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }
|
|
3292
|
+
.ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }
|
|
3293
|
+
.ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }
|
|
3294
|
+
.ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }
|
|
3295
|
+
.ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }
|
|
3296
|
+
}
|
|
3297
|
+
@keyframes ss-w-nudge {
|
|
3298
|
+
0%, 100% { transform: none; }
|
|
3299
|
+
22% { transform: translateY(-9px) rotate(-9deg); }
|
|
3300
|
+
44% { transform: translateY(0) rotate(7deg); }
|
|
3301
|
+
64% { transform: translateY(-4px) rotate(-4deg); }
|
|
3302
|
+
82% { transform: rotate(2deg); }
|
|
3303
|
+
}
|
|
3304
|
+
@keyframes ss-w-greet-in {
|
|
3305
|
+
from { opacity: 0; transform: translateY(8px) scale(.92); }
|
|
3306
|
+
to { opacity: 1; transform: none; }
|
|
3307
|
+
}
|
|
3308
|
+
@keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }
|
|
3309
|
+
@keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
|
|
3310
|
+
@keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
|
|
3113
3311
|
|
|
3114
3312
|
/* panel */
|
|
3115
3313
|
.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); }
|
|
@@ -3813,10 +4011,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
3813
4011
|
.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); }
|
|
3814
4012
|
.ss-w-mon-oddspin[data-settled] .ss-w-mo-price,
|
|
3815
4013
|
.ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }
|
|
4014
|
+
|
|
4015
|
+
/* market accordion (Task 9): one collapsed row per available market, expanding into a reused
|
|
4016
|
+
MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */
|
|
4017
|
+
.ss-w-acc { display: flex; flex-direction: column; gap: 6px; }
|
|
4018
|
+
.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; }
|
|
4019
|
+
.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); }
|
|
4020
|
+
.ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; }
|
|
4021
|
+
.ss-w-acc-label { font-size: 12.5px; font-weight: 600; }
|
|
4022
|
+
.ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); }
|
|
4023
|
+
.ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
4024
|
+
.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
|
|
4025
|
+
.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; }
|
|
4026
|
+
.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
|
|
3816
4027
|
`;
|
|
3817
4028
|
|
|
3818
4029
|
// src/StatsWidget.tsx
|
|
3819
|
-
import { jsx as
|
|
4030
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
3820
4031
|
function buildClient(props) {
|
|
3821
4032
|
try {
|
|
3822
4033
|
if ("client" in props && props.client) {
|
|
@@ -3843,10 +4054,15 @@ function StatsWidget(props) {
|
|
|
3843
4054
|
const cfg = props.config;
|
|
3844
4055
|
const built = useMemo2(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
3845
4056
|
const ui = useMemo2(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
3846
|
-
const rootRef =
|
|
4057
|
+
const rootRef = useRef7(null);
|
|
4058
|
+
const introDoneRef = useRef7(false);
|
|
4059
|
+
const markIntroDone = useCallback5(() => {
|
|
4060
|
+
introDoneRef.current = true;
|
|
4061
|
+
}, []);
|
|
3847
4062
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
3848
4063
|
const monitor = useLiveMonitor({
|
|
3849
4064
|
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
4065
|
+
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
3850
4066
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
3851
4067
|
isOpen: controller.state.isOpen
|
|
3852
4068
|
});
|
|
@@ -3877,14 +4093,14 @@ function StatsWidget(props) {
|
|
|
3877
4093
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
3878
4094
|
[built]
|
|
3879
4095
|
);
|
|
3880
|
-
|
|
4096
|
+
useEffect10(() => {
|
|
3881
4097
|
if (!built || !ui.injectStyles) return;
|
|
3882
4098
|
const node = rootRef.current?.getRootNode();
|
|
3883
4099
|
if (node) injectStyles(node);
|
|
3884
4100
|
}, [built, ui.injectStyles]);
|
|
3885
4101
|
if (!built) return null;
|
|
3886
4102
|
const attrs = themeAttrs(ui);
|
|
3887
|
-
return /* @__PURE__ */
|
|
4103
|
+
return /* @__PURE__ */ jsx50("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__ */ jsx50(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ jsx50(
|
|
3888
4104
|
ChatFab,
|
|
3889
4105
|
{
|
|
3890
4106
|
label: ui.launcherLabel,
|
|
@@ -3893,7 +4109,9 @@ function StatsWidget(props) {
|
|
|
3893
4109
|
logoUrl: ui.logoUrl,
|
|
3894
4110
|
onOpen: controller.open,
|
|
3895
4111
|
onDismissPopup: controller.dismissPopup,
|
|
3896
|
-
dismissLabel: ui.dismissGreeting
|
|
4112
|
+
dismissLabel: ui.dismissGreeting,
|
|
4113
|
+
introAllowed: !introDoneRef.current,
|
|
4114
|
+
onIntroStart: markIntroDone
|
|
3897
4115
|
}
|
|
3898
4116
|
) });
|
|
3899
4117
|
}
|