@sensiblestats/widget-react 0.44.0 → 0.45.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 +13 -0
- package/dist/index.cjs +469 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +463 -115
- package/dist/index.js.map +1 -1
- package/dist/styles.css +34 -2
- 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_react26 = require("react");
|
|
40
40
|
var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/kickoff.ts
|
|
@@ -106,7 +106,7 @@ var STRINGS = {
|
|
|
106
106
|
tomorrow: "Tomorrow",
|
|
107
107
|
bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.en, "en", now),
|
|
108
108
|
tabChat: "Chat",
|
|
109
|
-
|
|
109
|
+
tabFollowing: "Following",
|
|
110
110
|
tabOdds: "Odds",
|
|
111
111
|
pinLabel: "Track odds",
|
|
112
112
|
unpinLabel: "Stop tracking odds",
|
|
@@ -125,7 +125,10 @@ var STRINGS = {
|
|
|
125
125
|
momentumLabel: "Momentum",
|
|
126
126
|
accordionValueLabel: "Value",
|
|
127
127
|
accordionRetry: "Couldn't load odds \u2014 tap to retry",
|
|
128
|
-
accordionSuspended: "Suspended"
|
|
128
|
+
accordionSuspended: "Suspended",
|
|
129
|
+
tabToday: "Today",
|
|
130
|
+
sectionLive: "Live",
|
|
131
|
+
staleStates: "Live scores can't be updated \u2014 showing the last known state."
|
|
129
132
|
},
|
|
130
133
|
tr: {
|
|
131
134
|
launcherLabel: "SensibleStats ile sohbet et",
|
|
@@ -180,7 +183,7 @@ var STRINGS = {
|
|
|
180
183
|
tomorrow: "Yar\u0131n",
|
|
181
184
|
bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.tr, "tr", now),
|
|
182
185
|
tabChat: "Sohbet",
|
|
183
|
-
|
|
186
|
+
tabFollowing: "Takip",
|
|
184
187
|
tabOdds: "Oranlar",
|
|
185
188
|
pinLabel: "Oran\u0131 takip et",
|
|
186
189
|
unpinLabel: "Oran takibini b\u0131rak",
|
|
@@ -199,7 +202,10 @@ var STRINGS = {
|
|
|
199
202
|
momentumLabel: "Momentum",
|
|
200
203
|
accordionValueLabel: "De\u011Fer",
|
|
201
204
|
accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
|
|
202
|
-
accordionSuspended: "Ask\u0131da"
|
|
205
|
+
accordionSuspended: "Ask\u0131da",
|
|
206
|
+
tabToday: "Bug\xFCn",
|
|
207
|
+
sectionLive: "Canl\u0131",
|
|
208
|
+
staleStates: "Canl\u0131 skorlar g\xFCncellenemiyor \u2014 son bilinen durum g\xF6steriliyor."
|
|
203
209
|
}
|
|
204
210
|
};
|
|
205
211
|
function resolveLocaleStrings(locale) {
|
|
@@ -273,8 +279,11 @@ function normalizeUi(cfg) {
|
|
|
273
279
|
tomorrow: strings.tomorrow,
|
|
274
280
|
bettingKickoff: strings.bettingKickoff,
|
|
275
281
|
tabChat: strings.tabChat,
|
|
276
|
-
|
|
282
|
+
tabFollowing: strings.tabFollowing,
|
|
277
283
|
tabOdds: strings.tabOdds,
|
|
284
|
+
tabToday: strings.tabToday,
|
|
285
|
+
sectionLive: strings.sectionLive,
|
|
286
|
+
staleStates: strings.staleStates,
|
|
278
287
|
pinLabel: strings.pinLabel,
|
|
279
288
|
unpinLabel: strings.unpinLabel,
|
|
280
289
|
matchPinLabel: strings.matchPinLabel,
|
|
@@ -1215,6 +1224,7 @@ function useLiveMonitor(opts) {
|
|
|
1215
1224
|
const [chatDot, setChatDot] = (0, import_react3.useState)(false);
|
|
1216
1225
|
const [matchesDot, setMatchesDot] = (0, import_react3.useState)(false);
|
|
1217
1226
|
const [oddsDot, setOddsDot] = (0, import_react3.useState)(false);
|
|
1227
|
+
const [todayDot, setTodayDot] = (0, import_react3.useState)(false);
|
|
1218
1228
|
const [lastViewedPrices, setLastViewedPrices] = (0, import_react3.useState)({});
|
|
1219
1229
|
const [inSlip, setInSlip] = (0, import_react3.useState)({});
|
|
1220
1230
|
const [openMarket, setOpenMarket] = (0, import_react3.useState)({});
|
|
@@ -1231,6 +1241,7 @@ function useLiveMonitor(opts) {
|
|
|
1231
1241
|
openMarketRef.current = openMarket;
|
|
1232
1242
|
const marketOddsRef = (0, import_react3.useRef)(marketOdds);
|
|
1233
1243
|
marketOddsRef.current = marketOdds;
|
|
1244
|
+
const hasToday = opts.hasToday ?? false;
|
|
1234
1245
|
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
1235
1246
|
const getMarketOddsRef = (0, import_react3.useRef)(opts.getMarketOdds);
|
|
1236
1247
|
getMarketOddsRef.current = opts.getMarketOdds;
|
|
@@ -1285,7 +1296,7 @@ function useLiveMonitor(opts) {
|
|
|
1285
1296
|
break;
|
|
1286
1297
|
}
|
|
1287
1298
|
}
|
|
1288
|
-
if (sawNewGoalOrRed && activeTabRef.current !== "
|
|
1299
|
+
if (sawNewGoalOrRed && activeTabRef.current !== "following") setMatchesDot(true);
|
|
1289
1300
|
for (const m of next.matches) {
|
|
1290
1301
|
if (!pinnedMatchIds.has(m.matchId)) continue;
|
|
1291
1302
|
const first = m.availableMarkets?.[0];
|
|
@@ -1371,11 +1382,17 @@ function useLiveMonitor(opts) {
|
|
|
1371
1382
|
prevPinsLengthRef.current = pins.length;
|
|
1372
1383
|
if (pins.length === 0) {
|
|
1373
1384
|
window.clearTimeout(timerRef.current);
|
|
1374
|
-
setActiveTabState("chat");
|
|
1375
1385
|
return;
|
|
1376
1386
|
}
|
|
1377
1387
|
if (wasEmpty) void tick();
|
|
1378
1388
|
}, [pins.length, tick]);
|
|
1389
|
+
(0, import_react3.useEffect)(() => {
|
|
1390
|
+
const matchPins = pins.filter((p) => p.kind === "match").length;
|
|
1391
|
+
const marketPins = pins.length - matchPins;
|
|
1392
|
+
if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
1393
|
+
if (activeTab === "odds" && marketPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
1394
|
+
if (activeTab === "today" && !hasToday) setActiveTabState("chat");
|
|
1395
|
+
}, [pins, activeTab, hasToday]);
|
|
1379
1396
|
const prevIsOpenRef = (0, import_react3.useRef)(false);
|
|
1380
1397
|
(0, import_react3.useEffect)(() => {
|
|
1381
1398
|
const wasClosed = !prevIsOpenRef.current;
|
|
@@ -1396,7 +1413,8 @@ function useLiveMonitor(opts) {
|
|
|
1396
1413
|
const setActiveTab = (0, import_react3.useCallback)((tab) => {
|
|
1397
1414
|
setActiveTabState(tab);
|
|
1398
1415
|
if (tab === "chat") setChatDot(false);
|
|
1399
|
-
if (tab === "
|
|
1416
|
+
if (tab === "today") setTodayDot(false);
|
|
1417
|
+
if (tab === "following") {
|
|
1400
1418
|
setMatchesDot(false);
|
|
1401
1419
|
void tick();
|
|
1402
1420
|
}
|
|
@@ -1416,6 +1434,9 @@ function useLiveMonitor(opts) {
|
|
|
1416
1434
|
const togglePin = (0, import_react3.useCallback)((pin) => store.toggle(pin), [store]);
|
|
1417
1435
|
const isPinned = (0, import_react3.useCallback)((key) => pinsRef.current.some((p) => p.key === key), []);
|
|
1418
1436
|
const markChatActivity = (0, import_react3.useCallback)(() => setChatDot(true), []);
|
|
1437
|
+
const markTodayActivity = (0, import_react3.useCallback)(() => {
|
|
1438
|
+
if (activeTabRef.current !== "today") setTodayDot(true);
|
|
1439
|
+
}, []);
|
|
1419
1440
|
const markInSlip = (0, import_react3.useCallback)((matchOddsId) => {
|
|
1420
1441
|
setInSlip((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
|
|
1421
1442
|
}, []);
|
|
@@ -1431,6 +1452,8 @@ function useLiveMonitor(opts) {
|
|
|
1431
1452
|
markChatActivity,
|
|
1432
1453
|
matchesDot,
|
|
1433
1454
|
oddsDot,
|
|
1455
|
+
todayDot,
|
|
1456
|
+
markTodayActivity,
|
|
1434
1457
|
lastViewedPrices,
|
|
1435
1458
|
inSlip,
|
|
1436
1459
|
markInSlip,
|
|
@@ -1442,18 +1465,198 @@ function useLiveMonitor(opts) {
|
|
|
1442
1465
|
};
|
|
1443
1466
|
}
|
|
1444
1467
|
|
|
1445
|
-
// src/
|
|
1468
|
+
// src/useMatchDiscovery.ts
|
|
1446
1469
|
var import_react4 = require("react");
|
|
1447
|
-
|
|
1470
|
+
|
|
1471
|
+
// src/scheduleCache.ts
|
|
1472
|
+
var PREFIX = "ss-w-schedule:";
|
|
1473
|
+
var SCHEMA_VERSION = 1;
|
|
1474
|
+
var TTL_MS2 = 6 * 36e5;
|
|
1475
|
+
function scheduleCacheKey(operatorId, localDate) {
|
|
1476
|
+
return `${PREFIX}${operatorId}:${localDate}`;
|
|
1477
|
+
}
|
|
1478
|
+
function read(operatorId, localDate) {
|
|
1479
|
+
try {
|
|
1480
|
+
const raw = localStorage.getItem(scheduleCacheKey(operatorId, localDate));
|
|
1481
|
+
if (!raw) return null;
|
|
1482
|
+
const entry = JSON.parse(raw);
|
|
1483
|
+
if (entry.v !== SCHEMA_VERSION || !entry.payload) return null;
|
|
1484
|
+
return entry;
|
|
1485
|
+
} catch {
|
|
1486
|
+
return null;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
function readSchedule(operatorId, localDate, nowMs) {
|
|
1490
|
+
const entry = read(operatorId, localDate);
|
|
1491
|
+
if (!entry) return null;
|
|
1492
|
+
return nowMs - entry.at > TTL_MS2 ? null : entry.payload;
|
|
1493
|
+
}
|
|
1494
|
+
function readScheduleIgnoringTtl(operatorId, localDate) {
|
|
1495
|
+
return read(operatorId, localDate)?.payload ?? null;
|
|
1496
|
+
}
|
|
1497
|
+
function skeletonOnly(payload) {
|
|
1498
|
+
return {
|
|
1499
|
+
localDate: payload.localDate,
|
|
1500
|
+
groups: payload.groups.map((g) => ({
|
|
1501
|
+
competitionId: g.competitionId,
|
|
1502
|
+
competitionName: g.competitionName,
|
|
1503
|
+
competitionImagePath: g.competitionImagePath ?? null,
|
|
1504
|
+
rank: g.rank,
|
|
1505
|
+
expandedByDefault: g.expandedByDefault,
|
|
1506
|
+
matches: g.matches.map((m) => ({
|
|
1507
|
+
matchId: m.matchId,
|
|
1508
|
+
homeTeamName: m.homeTeamName,
|
|
1509
|
+
awayTeamName: m.awayTeamName,
|
|
1510
|
+
homeTeamImagePath: m.homeTeamImagePath ?? null,
|
|
1511
|
+
awayTeamImagePath: m.awayTeamImagePath ?? null,
|
|
1512
|
+
kickoffUnix: m.kickoffUnix
|
|
1513
|
+
}))
|
|
1514
|
+
}))
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
function writeSchedule(operatorId, localDate, payload, nowMs) {
|
|
1518
|
+
const keep = scheduleCacheKey(operatorId, localDate);
|
|
1519
|
+
const mine = `${PREFIX}${operatorId}:`;
|
|
1520
|
+
try {
|
|
1521
|
+
for (let i = localStorage.length - 1; i >= 0; i--) {
|
|
1522
|
+
const key = localStorage.key(i);
|
|
1523
|
+
if (key && key.startsWith(mine) && key !== keep) localStorage.removeItem(key);
|
|
1524
|
+
}
|
|
1525
|
+
const entry = { v: SCHEMA_VERSION, at: nowMs, payload: skeletonOnly(payload) };
|
|
1526
|
+
localStorage.setItem(keep, JSON.stringify(entry));
|
|
1527
|
+
} catch {
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
// src/dueSet.ts
|
|
1532
|
+
var WINDOW_MS = 3.5 * 36e5;
|
|
1533
|
+
function dueMatchIds(groups, states, nowMs) {
|
|
1534
|
+
const due = /* @__PURE__ */ new Set();
|
|
1535
|
+
for (const group of groups) {
|
|
1536
|
+
for (const match of group.matches) {
|
|
1537
|
+
const sinceKickoff = nowMs - match.kickoffUnix * 1e3;
|
|
1538
|
+
if (sinceKickoff >= 0 && sinceKickoff <= WINDOW_MS) due.add(match.matchId);
|
|
1539
|
+
if (states[match.matchId]?.phase === "live") due.add(match.matchId);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
return [...due];
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// src/useMatchDiscovery.ts
|
|
1546
|
+
var POLL_MS = 6e4;
|
|
1547
|
+
var ROLLOVER_CHECK_MS = 6e4;
|
|
1548
|
+
var STALE_AFTER_FAILURES = 2;
|
|
1549
|
+
function localDateOf(now) {
|
|
1550
|
+
const y = now.getFullYear();
|
|
1551
|
+
const m = `${now.getMonth() + 1}`.padStart(2, "0");
|
|
1552
|
+
const d = `${now.getDate()}`.padStart(2, "0");
|
|
1553
|
+
return `${y}-${m}-${d}`;
|
|
1554
|
+
}
|
|
1555
|
+
function useMatchDiscovery(opts) {
|
|
1556
|
+
const [groups, setGroups] = (0, import_react4.useState)([]);
|
|
1557
|
+
const [states, setStates] = (0, import_react4.useState)({});
|
|
1558
|
+
const [failures, setFailures] = (0, import_react4.useState)(0);
|
|
1559
|
+
const [expanded, setExpanded] = (0, import_react4.useState)({});
|
|
1560
|
+
const [touched, setTouched] = (0, import_react4.useState)({});
|
|
1561
|
+
const groupsRef = (0, import_react4.useRef)(groups);
|
|
1562
|
+
groupsRef.current = groups;
|
|
1563
|
+
const statesRef = (0, import_react4.useRef)(states);
|
|
1564
|
+
statesRef.current = states;
|
|
1565
|
+
const getStatesRef = (0, import_react4.useRef)(opts.getStates);
|
|
1566
|
+
getStatesRef.current = opts.getStates;
|
|
1567
|
+
const pinnedKey = opts.pinnedMatchIds.join(",");
|
|
1568
|
+
const [localDate, setLocalDate] = (0, import_react4.useState)(() => localDateOf(/* @__PURE__ */ new Date()));
|
|
1569
|
+
(0, import_react4.useEffect)(() => {
|
|
1570
|
+
const id = setInterval(() => {
|
|
1571
|
+
const next = localDateOf(/* @__PURE__ */ new Date());
|
|
1572
|
+
setLocalDate((prev) => prev === next ? prev : next);
|
|
1573
|
+
}, ROLLOVER_CHECK_MS);
|
|
1574
|
+
return () => clearInterval(id);
|
|
1575
|
+
}, []);
|
|
1576
|
+
(0, import_react4.useEffect)(() => {
|
|
1577
|
+
let cancelled = false;
|
|
1578
|
+
const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
1579
|
+
const cached = readSchedule(opts.operatorId, localDate, Date.now());
|
|
1580
|
+
if (cached) {
|
|
1581
|
+
if (!cancelled) setGroups(cached.groups);
|
|
1582
|
+
return () => {
|
|
1583
|
+
cancelled = true;
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
void (async () => {
|
|
1587
|
+
try {
|
|
1588
|
+
const payload = await opts.getSchedule(localDate, utcOffsetMinutes);
|
|
1589
|
+
if (cancelled || !payload) return;
|
|
1590
|
+
writeSchedule(opts.operatorId, localDate, payload, Date.now());
|
|
1591
|
+
setGroups(payload.groups);
|
|
1592
|
+
} catch {
|
|
1593
|
+
const fallback = readScheduleIgnoringTtl(opts.operatorId, localDate);
|
|
1594
|
+
if (!cancelled && fallback) setGroups(fallback.groups);
|
|
1595
|
+
}
|
|
1596
|
+
})();
|
|
1597
|
+
return () => {
|
|
1598
|
+
cancelled = true;
|
|
1599
|
+
};
|
|
1600
|
+
}, [opts.operatorId, localDate]);
|
|
1601
|
+
(0, import_react4.useEffect)(() => {
|
|
1602
|
+
setExpanded((prev) => {
|
|
1603
|
+
const next = {};
|
|
1604
|
+
for (const group of groups) {
|
|
1605
|
+
const hasPin = group.matches.some((m) => opts.pinnedMatchIds.includes(m.matchId));
|
|
1606
|
+
const seeded = group.expandedByDefault || hasPin;
|
|
1607
|
+
next[group.competitionId] = touched[group.competitionId] ? prev[group.competitionId] ?? seeded : seeded;
|
|
1608
|
+
}
|
|
1609
|
+
return next;
|
|
1610
|
+
});
|
|
1611
|
+
}, [groups, pinnedKey, touched]);
|
|
1612
|
+
const tick = (0, import_react4.useCallback)(async () => {
|
|
1613
|
+
const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now());
|
|
1614
|
+
if (ids.length === 0) return;
|
|
1615
|
+
try {
|
|
1616
|
+
const payload = await getStatesRef.current(ids);
|
|
1617
|
+
if (!payload) return;
|
|
1618
|
+
setStates((prev) => {
|
|
1619
|
+
const next = { ...prev };
|
|
1620
|
+
for (const state of payload.states) next[state.matchId] = state;
|
|
1621
|
+
return next;
|
|
1622
|
+
});
|
|
1623
|
+
setFailures(0);
|
|
1624
|
+
} catch {
|
|
1625
|
+
setFailures((n) => n + 1);
|
|
1626
|
+
}
|
|
1627
|
+
}, []);
|
|
1628
|
+
(0, import_react4.useEffect)(() => {
|
|
1629
|
+
if (!opts.isOpen) return;
|
|
1630
|
+
void tick();
|
|
1631
|
+
const id = setInterval(() => {
|
|
1632
|
+
void tick();
|
|
1633
|
+
}, POLL_MS);
|
|
1634
|
+
return () => clearInterval(id);
|
|
1635
|
+
}, [opts.isOpen, tick, groups]);
|
|
1636
|
+
const stale = failures >= STALE_AFTER_FAILURES;
|
|
1637
|
+
const liveCount = (0, import_react4.useMemo)(
|
|
1638
|
+
() => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
|
|
1639
|
+
[states, stale]
|
|
1640
|
+
);
|
|
1641
|
+
const toggleGroup = (0, import_react4.useCallback)((competitionId) => {
|
|
1642
|
+
setTouched((prev) => ({ ...prev, [competitionId]: true }));
|
|
1643
|
+
setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
|
|
1644
|
+
}, []);
|
|
1645
|
+
return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick };
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// src/eventLogContext.ts
|
|
1649
|
+
var import_react5 = require("react");
|
|
1650
|
+
var EventLogContext = (0, import_react5.createContext)(null);
|
|
1448
1651
|
function useEventLog() {
|
|
1449
|
-
return (0,
|
|
1652
|
+
return (0, import_react5.useContext)(EventLogContext);
|
|
1450
1653
|
}
|
|
1451
1654
|
|
|
1452
1655
|
// src/components/ChatFab.tsx
|
|
1453
|
-
var
|
|
1656
|
+
var import_react7 = require("react");
|
|
1454
1657
|
|
|
1455
1658
|
// src/components/BrandMark.tsx
|
|
1456
|
-
var
|
|
1659
|
+
var import_react6 = require("react");
|
|
1457
1660
|
|
|
1458
1661
|
// src/assets/logo.ts
|
|
1459
1662
|
var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
|
|
@@ -1502,7 +1705,7 @@ function DashboardIcon({ name }) {
|
|
|
1502
1705
|
// src/components/BrandMark.tsx
|
|
1503
1706
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1504
1707
|
function BrandMark({ logoUrl, className }) {
|
|
1505
|
-
const [failed, setFailed] = (0,
|
|
1708
|
+
const [failed, setFailed] = (0, import_react6.useState)(false);
|
|
1506
1709
|
if (!logoUrl || failed) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SsMark, { className });
|
|
1507
1710
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1508
1711
|
}
|
|
@@ -1527,9 +1730,9 @@ function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
|
|
|
1527
1730
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1528
1731
|
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
|
|
1529
1732
|
const bubble = popupText ?? greeting;
|
|
1530
|
-
const [intro, setIntro] = (0,
|
|
1531
|
-
const armedRef = (0,
|
|
1532
|
-
(0,
|
|
1733
|
+
const [intro, setIntro] = (0, import_react7.useState)(false);
|
|
1734
|
+
const armedRef = (0, import_react7.useRef)(introAllowed);
|
|
1735
|
+
(0, import_react7.useEffect)(() => {
|
|
1533
1736
|
if (armedRef.current && bubble) {
|
|
1534
1737
|
armedRef.current = false;
|
|
1535
1738
|
setIntro(true);
|
|
@@ -1543,10 +1746,10 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
|
|
|
1543
1746
|
}
|
|
1544
1747
|
|
|
1545
1748
|
// src/components/ChatPanel.tsx
|
|
1546
|
-
var
|
|
1749
|
+
var import_react25 = require("react");
|
|
1547
1750
|
|
|
1548
1751
|
// src/components/ChatHeader.tsx
|
|
1549
|
-
var
|
|
1752
|
+
var import_react8 = require("react");
|
|
1550
1753
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1551
1754
|
function ChatHeader({
|
|
1552
1755
|
onClose,
|
|
@@ -1558,15 +1761,15 @@ function ChatHeader({
|
|
|
1558
1761
|
newConversationLabel = "New conversation",
|
|
1559
1762
|
moreOptionsLabel = "More options"
|
|
1560
1763
|
}) {
|
|
1561
|
-
const [menuOpen, setMenuOpen] = (0,
|
|
1562
|
-
const wrapRef = (0,
|
|
1563
|
-
const kebabRef = (0,
|
|
1564
|
-
const firstItemRef = (0,
|
|
1764
|
+
const [menuOpen, setMenuOpen] = (0, import_react8.useState)(false);
|
|
1765
|
+
const wrapRef = (0, import_react8.useRef)(null);
|
|
1766
|
+
const kebabRef = (0, import_react8.useRef)(null);
|
|
1767
|
+
const firstItemRef = (0, import_react8.useRef)(null);
|
|
1565
1768
|
const hasMenu = !!(canReset && onNewConversation);
|
|
1566
|
-
(0,
|
|
1769
|
+
(0, import_react8.useEffect)(() => {
|
|
1567
1770
|
if (menuOpen) firstItemRef.current?.focus();
|
|
1568
1771
|
}, [menuOpen]);
|
|
1569
|
-
(0,
|
|
1772
|
+
(0, import_react8.useEffect)(() => {
|
|
1570
1773
|
if (!menuOpen) return;
|
|
1571
1774
|
const onPointer = (e) => {
|
|
1572
1775
|
if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
|
|
@@ -1622,7 +1825,7 @@ function ChatHeader({
|
|
|
1622
1825
|
}
|
|
1623
1826
|
|
|
1624
1827
|
// src/components/MessageList.tsx
|
|
1625
|
-
var
|
|
1828
|
+
var import_react23 = require("react");
|
|
1626
1829
|
|
|
1627
1830
|
// src/components/Markdown.tsx
|
|
1628
1831
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -1640,7 +1843,7 @@ function Markdown({ text }) {
|
|
|
1640
1843
|
}
|
|
1641
1844
|
|
|
1642
1845
|
// src/components/EntityCardList.tsx
|
|
1643
|
-
var
|
|
1846
|
+
var import_react9 = require("react");
|
|
1644
1847
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1645
1848
|
var MAX_VISIBLE = 3;
|
|
1646
1849
|
var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
|
|
@@ -1724,7 +1927,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
|
|
|
1724
1927
|
)) });
|
|
1725
1928
|
}
|
|
1726
1929
|
function EntityCardItem({ c }) {
|
|
1727
|
-
const [active, setActive] = (0,
|
|
1930
|
+
const [active, setActive] = (0, import_react9.useState)(0);
|
|
1728
1931
|
const hasBody = c.scopes.length > 0;
|
|
1729
1932
|
if (!hasBody) {
|
|
1730
1933
|
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 }) });
|
|
@@ -1738,7 +1941,7 @@ function EntityCardItem({ c }) {
|
|
|
1738
1941
|
] });
|
|
1739
1942
|
}
|
|
1740
1943
|
function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
|
|
1741
|
-
const [expanded, setExpanded] = (0,
|
|
1944
|
+
const [expanded, setExpanded] = (0, import_react9.useState)(false);
|
|
1742
1945
|
if (cards.length === 0) return null;
|
|
1743
1946
|
const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
|
|
1744
1947
|
const overflow = cards.length - MAX_VISIBLE;
|
|
@@ -1749,18 +1952,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
1749
1952
|
}
|
|
1750
1953
|
|
|
1751
1954
|
// src/components/BettingInsightList.tsx
|
|
1752
|
-
var
|
|
1955
|
+
var import_react14 = require("react");
|
|
1753
1956
|
|
|
1754
1957
|
// src/components/AddToSlipButton.tsx
|
|
1755
|
-
var
|
|
1958
|
+
var import_react11 = require("react");
|
|
1756
1959
|
var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
|
|
1757
1960
|
|
|
1758
1961
|
// src/components/Toast.tsx
|
|
1759
|
-
var
|
|
1962
|
+
var import_react10 = require("react");
|
|
1760
1963
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1761
1964
|
var DISMISS_MS = 4e3;
|
|
1762
1965
|
function Toast({ toast, onDismiss }) {
|
|
1763
|
-
(0,
|
|
1966
|
+
(0, import_react10.useEffect)(() => {
|
|
1764
1967
|
if (!toast) return;
|
|
1765
1968
|
const timer = setTimeout(onDismiss, DISMISS_MS);
|
|
1766
1969
|
return () => clearTimeout(timer);
|
|
@@ -1778,10 +1981,10 @@ function withTimeout(value) {
|
|
|
1778
1981
|
]);
|
|
1779
1982
|
}
|
|
1780
1983
|
function SlipButton({ selection, shownOdds, marketName, marketDeveloperName, slip, ui }) {
|
|
1781
|
-
const [pending, setPending] = (0,
|
|
1782
|
-
const [settled, setSettled] = (0,
|
|
1783
|
-
const [toast, setToast] = (0,
|
|
1784
|
-
const dismiss = (0,
|
|
1984
|
+
const [pending, setPending] = (0, import_react11.useState)(false);
|
|
1985
|
+
const [settled, setSettled] = (0, import_react11.useState)(false);
|
|
1986
|
+
const [toast, setToast] = (0, import_react11.useState)(null);
|
|
1987
|
+
const dismiss = (0, import_react11.useCallback)(() => setToast(null), []);
|
|
1785
1988
|
const log = useEventLog();
|
|
1786
1989
|
const handler = slip.onAddToSlip;
|
|
1787
1990
|
if (!ui || !handler || !selection) return null;
|
|
@@ -1871,14 +2074,14 @@ function OddsMovementBadge({
|
|
|
1871
2074
|
}
|
|
1872
2075
|
|
|
1873
2076
|
// src/components/Crest.tsx
|
|
1874
|
-
var
|
|
2077
|
+
var import_react12 = require("react");
|
|
1875
2078
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1876
2079
|
function initials2(name) {
|
|
1877
2080
|
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1878
2081
|
}
|
|
1879
2082
|
function Crest2({ url, name, kind }) {
|
|
1880
2083
|
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1881
|
-
const [failed, setFailed] = (0,
|
|
2084
|
+
const [failed, setFailed] = (0, import_react12.useState)(false);
|
|
1882
2085
|
if (url && !failed) {
|
|
1883
2086
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1884
2087
|
}
|
|
@@ -1886,7 +2089,7 @@ function Crest2({ url, name, kind }) {
|
|
|
1886
2089
|
}
|
|
1887
2090
|
|
|
1888
2091
|
// src/components/PinToggle.tsx
|
|
1889
|
-
var
|
|
2092
|
+
var import_react13 = require("react");
|
|
1890
2093
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1891
2094
|
var PIN_GLYPHS = {
|
|
1892
2095
|
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" },
|
|
@@ -1894,8 +2097,8 @@ var PIN_GLYPHS = {
|
|
|
1894
2097
|
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" }
|
|
1895
2098
|
};
|
|
1896
2099
|
function PinToggle({ pin, monitor, ui }) {
|
|
1897
|
-
const [toast, setToast] = (0,
|
|
1898
|
-
const dismiss = (0,
|
|
2100
|
+
const [toast, setToast] = (0, import_react13.useState)(null);
|
|
2101
|
+
const dismiss = (0, import_react13.useCallback)(() => setToast(null), []);
|
|
1899
2102
|
const log = useEventLog();
|
|
1900
2103
|
if (!monitor || !monitor.enabled) return null;
|
|
1901
2104
|
const key = pinKey(pin);
|
|
@@ -1955,7 +2158,7 @@ function StatRows({ stats }) {
|
|
|
1955
2158
|
] }, `${s.label}:${s.value}`)) });
|
|
1956
2159
|
}
|
|
1957
2160
|
function ScopedStats({ scopes }) {
|
|
1958
|
-
const [active, setActive] = (0,
|
|
2161
|
+
const [active, setActive] = (0, import_react14.useState)(0);
|
|
1959
2162
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1960
2163
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-scoped", children: [
|
|
1961
2164
|
/* @__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)) }),
|
|
@@ -1966,7 +2169,7 @@ function hasStatsContent(it) {
|
|
|
1966
2169
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1967
2170
|
}
|
|
1968
2171
|
function ReasonStrip({ it, ui }) {
|
|
1969
|
-
const [open, setOpen] = (0,
|
|
2172
|
+
const [open, setOpen] = (0, import_react14.useState)(false);
|
|
1970
2173
|
const log = useEventLog();
|
|
1971
2174
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1972
2175
|
const hasStats = hasStatsContent(it);
|
|
@@ -2086,7 +2289,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
2086
2289
|
}
|
|
2087
2290
|
|
|
2088
2291
|
// src/components/MarketOddsCardList.tsx
|
|
2089
|
-
var
|
|
2292
|
+
var import_react15 = require("react");
|
|
2090
2293
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2091
2294
|
function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
2092
2295
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
@@ -2103,7 +2306,7 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
|
|
|
2103
2306
|
] });
|
|
2104
2307
|
}
|
|
2105
2308
|
function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
|
|
2106
|
-
const [open, setOpen] = (0,
|
|
2309
|
+
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
2107
2310
|
const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
2108
2311
|
const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
|
|
2109
2312
|
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
@@ -2406,7 +2609,7 @@ function FixtureCard({ card }) {
|
|
|
2406
2609
|
}
|
|
2407
2610
|
|
|
2408
2611
|
// src/components/dashboard/CountdownCard.tsx
|
|
2409
|
-
var
|
|
2612
|
+
var import_react16 = require("react");
|
|
2410
2613
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2411
2614
|
var DAY_MS = 864e5;
|
|
2412
2615
|
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
@@ -2425,12 +2628,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
|
2425
2628
|
function CountdownCard({ card }) {
|
|
2426
2629
|
const { data } = card;
|
|
2427
2630
|
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
2428
|
-
const [nowMs, setNowMs] = (0,
|
|
2429
|
-
const [reduced] = (0,
|
|
2631
|
+
const [nowMs, setNowMs] = (0, import_react16.useState)(() => Date.now());
|
|
2632
|
+
const [reduced] = (0, import_react16.useState)(
|
|
2430
2633
|
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
2431
2634
|
);
|
|
2432
2635
|
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
2433
|
-
(0,
|
|
2636
|
+
(0, import_react16.useEffect)(() => {
|
|
2434
2637
|
if (reduced) return;
|
|
2435
2638
|
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
2436
2639
|
return () => window.clearInterval(id);
|
|
@@ -2438,7 +2641,7 @@ function CountdownCard({ card }) {
|
|
|
2438
2641
|
const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
|
|
2439
2642
|
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: [
|
|
2440
2643
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
|
|
2441
|
-
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)(
|
|
2644
|
+
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_react16.Fragment, { children: [
|
|
2442
2645
|
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
|
|
2443
2646
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
|
|
2444
2647
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
|
|
@@ -2449,7 +2652,7 @@ function CountdownCard({ card }) {
|
|
|
2449
2652
|
}
|
|
2450
2653
|
|
|
2451
2654
|
// src/components/dashboard/InjuriesCard.tsx
|
|
2452
|
-
var
|
|
2655
|
+
var import_react17 = require("react");
|
|
2453
2656
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2454
2657
|
var SHOWN = 3;
|
|
2455
2658
|
function ColHead({ name, crestUrl }) {
|
|
@@ -2472,7 +2675,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
|
|
|
2472
2675
|
}
|
|
2473
2676
|
function InjuriesCard({ card, ui }) {
|
|
2474
2677
|
const { data } = card;
|
|
2475
|
-
const [expanded, setExpanded] = (0,
|
|
2678
|
+
const [expanded, setExpanded] = (0, import_react17.useState)(false);
|
|
2476
2679
|
const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
|
|
2477
2680
|
const limit = expanded ? void 0 : SHOWN;
|
|
2478
2681
|
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
@@ -2576,7 +2779,7 @@ function LinksCard({ card }) {
|
|
|
2576
2779
|
}
|
|
2577
2780
|
|
|
2578
2781
|
// src/components/dashboard/PostMatchResultCard.tsx
|
|
2579
|
-
var
|
|
2782
|
+
var import_react18 = require("react");
|
|
2580
2783
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2581
2784
|
function initials3(name) {
|
|
2582
2785
|
return name.trim().slice(0, 3).toUpperCase();
|
|
@@ -2586,7 +2789,7 @@ function PostMatchCrest({
|
|
|
2586
2789
|
name,
|
|
2587
2790
|
side
|
|
2588
2791
|
}) {
|
|
2589
|
-
const [failed, setFailed] = (0,
|
|
2792
|
+
const [failed, setFailed] = (0, import_react18.useState)(false);
|
|
2590
2793
|
const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
|
|
2591
2794
|
if (url && !failed) {
|
|
2592
2795
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2785,10 +2988,10 @@ function RestingFormCard({ card }) {
|
|
|
2785
2988
|
}
|
|
2786
2989
|
|
|
2787
2990
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
2788
|
-
var
|
|
2991
|
+
var import_react20 = require("react");
|
|
2789
2992
|
|
|
2790
2993
|
// src/useLiveClock.ts
|
|
2791
|
-
var
|
|
2994
|
+
var import_react19 = require("react");
|
|
2792
2995
|
var TICK_MS = 6e4;
|
|
2793
2996
|
var MAX_LIVE_TICK_MINUTES = 15;
|
|
2794
2997
|
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
@@ -2797,10 +3000,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2797
3000
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2798
3001
|
}
|
|
2799
3002
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2800
|
-
const [displayMinute, setDisplayMinute] = (0,
|
|
3003
|
+
const [displayMinute, setDisplayMinute] = (0, import_react19.useState)(
|
|
2801
3004
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2802
3005
|
);
|
|
2803
|
-
(0,
|
|
3006
|
+
(0, import_react19.useEffect)(() => {
|
|
2804
3007
|
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
2805
3008
|
if (!clockRunning) return;
|
|
2806
3009
|
const id = window.setInterval(() => {
|
|
@@ -2817,7 +3020,7 @@ function initials5(name) {
|
|
|
2817
3020
|
return name.trim().slice(0, 3).toUpperCase();
|
|
2818
3021
|
}
|
|
2819
3022
|
function LiveCrest({ url, name, side }) {
|
|
2820
|
-
const [failed, setFailed] = (0,
|
|
3023
|
+
const [failed, setFailed] = (0, import_react20.useState)(false);
|
|
2821
3024
|
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
2822
3025
|
if (url && !failed) {
|
|
2823
3026
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
@@ -2836,7 +3039,7 @@ function LiveScoreCard({
|
|
|
2836
3039
|
}) {
|
|
2837
3040
|
const { data } = card;
|
|
2838
3041
|
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
2839
|
-
const seedRef = (0,
|
|
3042
|
+
const seedRef = (0, import_react20.useRef)(null);
|
|
2840
3043
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
2841
3044
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
2842
3045
|
}
|
|
@@ -2876,7 +3079,7 @@ function LiveScoreCard({
|
|
|
2876
3079
|
}
|
|
2877
3080
|
|
|
2878
3081
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
2879
|
-
var
|
|
3082
|
+
var import_react21 = require("react");
|
|
2880
3083
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2881
3084
|
var SHOWN2 = 3;
|
|
2882
3085
|
function EventIcon({ type }) {
|
|
@@ -2918,7 +3121,7 @@ function EventRow({ e }) {
|
|
|
2918
3121
|
] });
|
|
2919
3122
|
}
|
|
2920
3123
|
function LiveTimelineCard({ card, ui }) {
|
|
2921
|
-
const [expanded, setExpanded] = (0,
|
|
3124
|
+
const [expanded, setExpanded] = (0, import_react21.useState)(false);
|
|
2922
3125
|
const events = card.data.events;
|
|
2923
3126
|
if (!events || events.length === 0) return null;
|
|
2924
3127
|
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
@@ -2943,7 +3146,7 @@ function LiveTimelineCard({ card, ui }) {
|
|
|
2943
3146
|
}
|
|
2944
3147
|
|
|
2945
3148
|
// src/components/dashboard/MomentumWave.tsx
|
|
2946
|
-
var
|
|
3149
|
+
var import_react22 = require("react");
|
|
2947
3150
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2948
3151
|
var WIDTH = 270;
|
|
2949
3152
|
var HEIGHT = 56;
|
|
@@ -2967,7 +3170,7 @@ function MomentumWave({
|
|
|
2967
3170
|
}) {
|
|
2968
3171
|
if (points.length === 0) return null;
|
|
2969
3172
|
const { area, line, lastLeftPct, lastTopPx } = buildPaths(points);
|
|
2970
|
-
const clipId = (0,
|
|
3173
|
+
const clipId = (0, import_react22.useId)();
|
|
2971
3174
|
const topClipId = `${clipId}-top`;
|
|
2972
3175
|
const bottomClipId = `${clipId}-bottom`;
|
|
2973
3176
|
const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
|
|
@@ -3158,11 +3361,11 @@ function turnAnchor(messages) {
|
|
|
3158
3361
|
}
|
|
3159
3362
|
function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3160
3363
|
const { state, send } = controller;
|
|
3161
|
-
const listRef = (0,
|
|
3162
|
-
const endRef = (0,
|
|
3163
|
-
const pinnedRef = (0,
|
|
3164
|
-
const anchoredTurnRef = (0,
|
|
3165
|
-
(0,
|
|
3364
|
+
const listRef = (0, import_react23.useRef)(null);
|
|
3365
|
+
const endRef = (0, import_react23.useRef)(null);
|
|
3366
|
+
const pinnedRef = (0, import_react23.useRef)(true);
|
|
3367
|
+
const anchoredTurnRef = (0, import_react23.useRef)(null);
|
|
3368
|
+
(0, import_react23.useEffect)(() => {
|
|
3166
3369
|
const anchor = turnAnchor(state.messages);
|
|
3167
3370
|
const list = listRef.current;
|
|
3168
3371
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -3218,10 +3421,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3218
3421
|
}
|
|
3219
3422
|
|
|
3220
3423
|
// src/components/ChatInput.tsx
|
|
3221
|
-
var
|
|
3424
|
+
var import_react24 = require("react");
|
|
3222
3425
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
3223
3426
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
3224
|
-
const [value, setValue] = (0,
|
|
3427
|
+
const [value, setValue] = (0, import_react24.useState)("");
|
|
3225
3428
|
const submit = () => {
|
|
3226
3429
|
const t = value.trim();
|
|
3227
3430
|
if (!t) return;
|
|
@@ -3242,22 +3445,16 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
3242
3445
|
|
|
3243
3446
|
// src/components/TabBar.tsx
|
|
3244
3447
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
]
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
chat: monitor.chatDot && monitor.activeTab !== "chat",
|
|
3255
|
-
matches: monitor.matchesDot && monitor.activeTab !== "matches",
|
|
3256
|
-
odds: monitor.oddsDot && monitor.activeTab !== "odds"
|
|
3257
|
-
};
|
|
3258
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "ss-w-tabs", role: "tablist", children: TABS.map(({ tab, labelKey }) => {
|
|
3448
|
+
function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday }) {
|
|
3449
|
+
const tabs = [
|
|
3450
|
+
{ tab: "chat", label: ui.tabChat, count: 0, dot: monitor.chatDot },
|
|
3451
|
+
...hasToday ? [{ tab: "today", label: ui.tabToday, count: todayCount, dot: monitor.todayDot }] : [],
|
|
3452
|
+
...matchCount > 0 ? [{ tab: "following", label: ui.tabFollowing, count: matchCount, dot: monitor.matchesDot }] : [],
|
|
3453
|
+
...oddsCount > 0 ? [{ tab: "odds", label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : []
|
|
3454
|
+
];
|
|
3455
|
+
if (tabs.length < 2) return null;
|
|
3456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "ss-w-tabs", role: "tablist", children: tabs.map(({ tab, label, count, dot }) => {
|
|
3259
3457
|
const active = monitor.activeTab === tab;
|
|
3260
|
-
const count = counts[tab];
|
|
3261
3458
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3262
3459
|
"button",
|
|
3263
3460
|
{
|
|
@@ -3268,9 +3465,9 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
|
|
|
3268
3465
|
className: "ss-w-tab",
|
|
3269
3466
|
onClick: () => monitor.setActiveTab(tab),
|
|
3270
3467
|
children: [
|
|
3271
|
-
|
|
3468
|
+
label,
|
|
3272
3469
|
count > 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "ss-w-tab-count", children: count }),
|
|
3273
|
-
|
|
3470
|
+
dot && !active && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "ss-w-tab-dot", "aria-hidden": "true" })
|
|
3274
3471
|
]
|
|
3275
3472
|
},
|
|
3276
3473
|
tab
|
|
@@ -3526,12 +3723,96 @@ function OddsPanel({ monitor, ui, slip }) {
|
|
|
3526
3723
|
}) });
|
|
3527
3724
|
}
|
|
3528
3725
|
|
|
3529
|
-
// src/components/
|
|
3726
|
+
// src/components/FixtureRow.tsx
|
|
3530
3727
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3728
|
+
function kickoffLabel(kickoffUnix) {
|
|
3729
|
+
const d = new Date(kickoffUnix * 1e3);
|
|
3730
|
+
return `${`${d.getHours()}`.padStart(2, "0")}:${`${d.getMinutes()}`.padStart(2, "0")}`;
|
|
3731
|
+
}
|
|
3732
|
+
function Side({ name, crest }) {
|
|
3733
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ss-w-drow-side", children: [
|
|
3734
|
+
crest ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("img", { className: "ss-w-drow-crest", src: crest, alt: "" }) : null,
|
|
3735
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "ss-w-drow-nm", children: name })
|
|
3736
|
+
] });
|
|
3737
|
+
}
|
|
3738
|
+
function FixtureRow({ match, state, stale, ui, monitor }) {
|
|
3739
|
+
const isLive = state?.phase === "live" && !stale;
|
|
3740
|
+
const hasScore = (state?.phase === "live" || state?.phase === "fullTime") && typeof state.homeScore === "number" && typeof state.awayScore === "number";
|
|
3741
|
+
const when = stale && state?.phase === "live" ? "\u2014" : isLive ? state?.minuteLabel ?? "\u2014" : kickoffLabel(match.kickoffUnix);
|
|
3742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: isLive ? "ss-w-drow ss-w-drow--live" : "ss-w-drow", children: [
|
|
3743
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: isLive ? "ss-w-drow-when ss-w-drow-when--live" : "ss-w-drow-when", children: when }),
|
|
3744
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "ss-w-drow-fx", children: [
|
|
3745
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Side, { name: match.homeTeamName, crest: match.homeTeamImagePath }),
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "ss-w-drow-dash", children: "\u2013" }),
|
|
3747
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Side, { name: match.awayTeamName, crest: match.awayTeamImagePath })
|
|
3748
|
+
] }),
|
|
3749
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: hasScore ? "ss-w-drow-sc" : "ss-w-drow-sc ss-w-drow-sc--idle", children: hasScore ? `${state.homeScore}\u2013${state.awayScore}` : "\u2013" }),
|
|
3750
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
|
|
3751
|
+
] });
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
// src/components/CompetitionGroup.tsx
|
|
3755
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3756
|
+
function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor }) {
|
|
3757
|
+
const own = group.matches.filter((m) => states[m.matchId]?.phase !== "live" || stale);
|
|
3758
|
+
const hasLive = own.length !== group.matches.length;
|
|
3759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "ss-w-grp", children: [
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("button", { type: "button", className: "ss-w-grp-head", "aria-expanded": open, onClick: onToggle, children: [
|
|
3761
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ss-w-grp-chev", children: open ? "\u25BE" : "\u25B8" }),
|
|
3762
|
+
hasLive && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ss-w-sec-dot", "aria-hidden": "true" }),
|
|
3763
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ss-w-grp-name", children: group.competitionName }),
|
|
3764
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ss-w-grp-count", children: own.length })
|
|
3765
|
+
] }),
|
|
3766
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "ss-w-grp-body", children: own.map((m) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(FixtureRow, { match: m, state: states[m.matchId], stale, ui, monitor }, m.matchId)) })
|
|
3767
|
+
] });
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
// src/components/TodayPanel.tsx
|
|
3771
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
3772
|
+
function TodayPanel({ discovery, ui, monitor }) {
|
|
3773
|
+
const { groups, states, stale, expanded, toggleGroup } = discovery;
|
|
3774
|
+
const liveRows = stale ? [] : groups.flatMap((group) => group.matches.filter((m) => states[m.matchId]?.phase === "live").map((match) => ({ match, rank: group.rank }))).sort((a, b) => a.rank - b.rank);
|
|
3775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "ss-w-mon-list", children: [
|
|
3776
|
+
stale && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "ss-w-stale", children: ui.staleStates }),
|
|
3777
|
+
liveRows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
3778
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "ss-w-sec-head", children: [
|
|
3779
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "ss-w-sec-dot", "aria-hidden": "true" }),
|
|
3780
|
+
ui.sectionLive
|
|
3781
|
+
] }),
|
|
3782
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "ss-w-today-live", children: liveRows.map(({ match }) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3783
|
+
FixtureRow,
|
|
3784
|
+
{
|
|
3785
|
+
match,
|
|
3786
|
+
state: states[match.matchId],
|
|
3787
|
+
stale,
|
|
3788
|
+
ui,
|
|
3789
|
+
monitor
|
|
3790
|
+
},
|
|
3791
|
+
match.matchId
|
|
3792
|
+
)) })
|
|
3793
|
+
] }),
|
|
3794
|
+
groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3795
|
+
CompetitionGroup,
|
|
3796
|
+
{
|
|
3797
|
+
group,
|
|
3798
|
+
open: expanded[group.competitionId] ?? group.expandedByDefault,
|
|
3799
|
+
onToggle: () => toggleGroup(group.competitionId),
|
|
3800
|
+
states,
|
|
3801
|
+
stale,
|
|
3802
|
+
ui,
|
|
3803
|
+
monitor
|
|
3804
|
+
},
|
|
3805
|
+
group.competitionId
|
|
3806
|
+
))
|
|
3807
|
+
] });
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// src/components/ChatPanel.tsx
|
|
3811
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
3531
3812
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
3532
3813
|
function useIsModal() {
|
|
3533
|
-
const [modal, setModal] = (0,
|
|
3534
|
-
(0,
|
|
3814
|
+
const [modal, setModal] = (0, import_react25.useState)(false);
|
|
3815
|
+
(0, import_react25.useEffect)(() => {
|
|
3535
3816
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
3536
3817
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
3537
3818
|
const sync = () => setModal(mql.matches);
|
|
@@ -3541,10 +3822,10 @@ function useIsModal() {
|
|
|
3541
3822
|
}, []);
|
|
3542
3823
|
return modal;
|
|
3543
3824
|
}
|
|
3544
|
-
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
3825
|
+
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery }) {
|
|
3545
3826
|
const { state, close, stop, send, reset } = controller;
|
|
3546
3827
|
const isModal = useIsModal();
|
|
3547
|
-
(0,
|
|
3828
|
+
(0, import_react25.useEffect)(() => {
|
|
3548
3829
|
const onKey = (e) => {
|
|
3549
3830
|
if (e.key === "Escape") close();
|
|
3550
3831
|
};
|
|
@@ -3555,11 +3836,11 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3555
3836
|
monitor?.setActiveTab("chat");
|
|
3556
3837
|
send(text);
|
|
3557
3838
|
};
|
|
3558
|
-
(0,
|
|
3839
|
+
(0, import_react25.useEffect)(() => {
|
|
3559
3840
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
3560
3841
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
3561
|
-
return /* @__PURE__ */ (0,
|
|
3562
|
-
/* @__PURE__ */ (0,
|
|
3842
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3563
3844
|
ChatHeader,
|
|
3564
3845
|
{
|
|
3565
3846
|
onClose: close,
|
|
@@ -3572,25 +3853,28 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3572
3853
|
moreOptionsLabel: ui.moreOptions
|
|
3573
3854
|
}
|
|
3574
3855
|
),
|
|
3575
|
-
monitor && /* @__PURE__ */ (0,
|
|
3856
|
+
monitor && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3576
3857
|
TabBar,
|
|
3577
3858
|
{
|
|
3578
3859
|
monitor,
|
|
3579
3860
|
ui,
|
|
3580
3861
|
matchCount: monitor.pins.filter((p) => p.kind === "match").length,
|
|
3581
|
-
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
|
|
3862
|
+
oddsCount: monitor.pins.filter((p) => p.kind !== "match").length,
|
|
3863
|
+
todayCount: discovery?.liveCount ?? 0,
|
|
3864
|
+
hasToday: (discovery?.groups.length ?? 0) > 0
|
|
3582
3865
|
}
|
|
3583
3866
|
),
|
|
3584
|
-
/* @__PURE__ */ (0,
|
|
3867
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3585
3868
|
"div",
|
|
3586
3869
|
{
|
|
3587
3870
|
style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
|
|
3588
|
-
children: /* @__PURE__ */ (0,
|
|
3871
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
|
|
3589
3872
|
}
|
|
3590
3873
|
),
|
|
3591
|
-
monitor && monitor.activeTab === "
|
|
3592
|
-
monitor && monitor.activeTab === "
|
|
3593
|
-
/* @__PURE__ */ (0,
|
|
3874
|
+
monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(TodayPanel, { discovery, ui, monitor }),
|
|
3875
|
+
monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MatchesPanel, { monitor, ui, slip }),
|
|
3876
|
+
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(OddsPanel, { monitor, ui, slip }),
|
|
3877
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
3594
3878
|
] });
|
|
3595
3879
|
}
|
|
3596
3880
|
|
|
@@ -4327,8 +4611,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4327
4611
|
.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }
|
|
4328
4612
|
|
|
4329
4613
|
/* live monitor tab bar: underline pattern mirrors .ss-w-ecard-scope; the unread dot uses --ss-w-neg */
|
|
4330
|
-
.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); }
|
|
4331
|
-
.ss-w-
|
|
4614
|
+
.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); overflow-x: auto; scrollbar-width: none; }
|
|
4615
|
+
.ss-w-tabs::-webkit-scrollbar { display: none; }
|
|
4616
|
+
.ss-w-tab { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 9px 12px; margin-bottom: -1px; border-bottom: 2px solid transparent; flex: none; white-space: nowrap; }
|
|
4332
4617
|
.ss-w-tab[data-on] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }
|
|
4333
4618
|
.ss-w-tab-count { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 999px; padding: 1px 6px; }
|
|
4334
4619
|
.ss-w-tab[data-on] .ss-w-tab-count { color: var(--ss-w-accent); }
|
|
@@ -4417,10 +4702,41 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
4417
4702
|
.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
|
|
4418
4703
|
.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; }
|
|
4419
4704
|
.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
|
|
4705
|
+
|
|
4706
|
+
/* ---- Today tab (u355) ---- */
|
|
4707
|
+
.ss-w-sec-head { display: flex; align-items: center; gap: 7px; padding: 2px 2px 0; font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
4708
|
+
.ss-w-sec-head::after { content: ""; flex: 1; height: 1px; background: var(--ss-w-line); }
|
|
4709
|
+
.ss-w-sec-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }
|
|
4710
|
+
.ss-w-today-live { display: flex; flex-direction: column; gap: 2px; }
|
|
4711
|
+
|
|
4712
|
+
.ss-w-grp { border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; }
|
|
4713
|
+
.ss-w-grp-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 11px; background: var(--ss-w-bubble); border: none; font: inherit; color: var(--ss-w-ink); cursor: pointer; text-align: left; }
|
|
4714
|
+
.ss-w-grp-head:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: -2px; }
|
|
4715
|
+
.ss-w-grp-chev { color: var(--ss-w-faint); font-size: 10px; flex: none; }
|
|
4716
|
+
.ss-w-grp-name { font-size: 12px; font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
4717
|
+
.ss-w-grp-count { margin-left: auto; flex: none; font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 999px; padding: 1px 7px; font-variant-numeric: tabular-nums; }
|
|
4718
|
+
.ss-w-grp-body { display: flex; flex-direction: column; padding: 2px 11px 6px; }
|
|
4719
|
+
|
|
4720
|
+
.ss-w-drow { display: grid; grid-template-columns: 42px minmax(0,1fr) auto 22px; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--ss-w-line); }
|
|
4721
|
+
.ss-w-drow:last-child { border-bottom: none; }
|
|
4722
|
+
.ss-w-drow-when { font-size: 11px; font-weight: 700; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
|
|
4723
|
+
.ss-w-drow-when--live { color: var(--ss-w-neg); }
|
|
4724
|
+
/* Each side ellipsises independently: a single joined string truncates the away team off the end,
|
|
4725
|
+
which is the u350 betting-card truncation one layer down. */
|
|
4726
|
+
.ss-w-drow-fx { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
4727
|
+
.ss-w-drow-side { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1 1 0; }
|
|
4728
|
+
.ss-w-drow-nm { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
4729
|
+
.ss-w-drow-dash { flex: none; color: var(--ss-w-faint); font-size: 11px; }
|
|
4730
|
+
.ss-w-drow-sc { font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
|
|
4731
|
+
.ss-w-drow-sc--idle { color: var(--ss-w-faint); font-weight: 600; }
|
|
4732
|
+
.ss-w-drow--live { background: color-mix(in srgb, var(--ss-w-neg) 5%, transparent); border-radius: 8px; padding: 7px 6px; margin: 0 -6px; border-bottom: none; }
|
|
4733
|
+
.ss-w-drow-crest { width: 16px; height: 16px; flex: none; border-radius: 50%; object-fit: contain; background: var(--ss-w-bubble); }
|
|
4734
|
+
|
|
4735
|
+
.ss-w-stale { font-size: 11px; font-weight: 600; color: var(--ss-w-cta); background: color-mix(in srgb, var(--ss-w-cta) 12%, var(--ss-w-panel)); border-radius: 8px; padding: 6px 9px; }
|
|
4420
4736
|
`;
|
|
4421
4737
|
|
|
4422
4738
|
// src/StatsWidget.tsx
|
|
4423
|
-
var
|
|
4739
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
4424
4740
|
function buildClient(props) {
|
|
4425
4741
|
try {
|
|
4426
4742
|
if ("client" in props && props.client) {
|
|
@@ -4445,29 +4761,61 @@ function injectStyles(root) {
|
|
|
4445
4761
|
function StatsWidget(props) {
|
|
4446
4762
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
4447
4763
|
const cfg = props.config;
|
|
4448
|
-
const built = (0,
|
|
4449
|
-
const logger = (0,
|
|
4764
|
+
const built = (0, import_react26.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
4765
|
+
const logger = (0, import_react26.useMemo)(
|
|
4450
4766
|
() => built ? built.client.createEventLogger({
|
|
4451
4767
|
operatorUserId: cfg?.userContext?.operatorUserId,
|
|
4452
4768
|
anonymousUserId: cfg?.userContext?.anonymousUserId
|
|
4453
4769
|
}) : null,
|
|
4454
4770
|
[built?.client]
|
|
4455
4771
|
);
|
|
4456
|
-
const ui = (0,
|
|
4457
|
-
const rootRef = (0,
|
|
4458
|
-
const introDoneRef = (0,
|
|
4459
|
-
const markIntroDone = (0,
|
|
4772
|
+
const ui = (0, import_react26.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
4773
|
+
const rootRef = (0, import_react26.useRef)(null);
|
|
4774
|
+
const introDoneRef = (0, import_react26.useRef)(false);
|
|
4775
|
+
const markIntroDone = (0, import_react26.useCallback)(() => {
|
|
4460
4776
|
introDoneRef.current = true;
|
|
4461
4777
|
}, []);
|
|
4462
4778
|
const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
|
|
4463
4779
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
|
|
4780
|
+
const [hasToday, setHasToday] = (0, import_react26.useState)(false);
|
|
4464
4781
|
const monitor = useLiveMonitor({
|
|
4465
4782
|
getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
|
|
4466
4783
|
getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
|
|
4467
4784
|
storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
|
|
4468
|
-
isOpen: controller.state.isOpen
|
|
4785
|
+
isOpen: controller.state.isOpen,
|
|
4786
|
+
hasToday
|
|
4787
|
+
});
|
|
4788
|
+
const getSchedule = (0, import_react26.useCallback)(
|
|
4789
|
+
(localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
|
|
4790
|
+
[built]
|
|
4791
|
+
);
|
|
4792
|
+
const getStates = (0, import_react26.useCallback)(
|
|
4793
|
+
(matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
|
|
4794
|
+
[built]
|
|
4795
|
+
);
|
|
4796
|
+
const pinnedMatchIds = (0, import_react26.useMemo)(
|
|
4797
|
+
() => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
|
|
4798
|
+
[monitor.pins]
|
|
4799
|
+
);
|
|
4800
|
+
const discovery = useMatchDiscovery({
|
|
4801
|
+
getSchedule,
|
|
4802
|
+
getStates,
|
|
4803
|
+
operatorId: cfg?.operatorId ?? "",
|
|
4804
|
+
isOpen: controller.state.isOpen,
|
|
4805
|
+
pinnedMatchIds
|
|
4469
4806
|
});
|
|
4470
|
-
const
|
|
4807
|
+
const todayHasContent = discovery.groups.length > 0;
|
|
4808
|
+
(0, import_react26.useEffect)(() => {
|
|
4809
|
+
setHasToday(todayHasContent);
|
|
4810
|
+
}, [todayHasContent]);
|
|
4811
|
+
const markTodayActivity = monitor.markTodayActivity;
|
|
4812
|
+
const prevLiveCountRef = (0, import_react26.useRef)(0);
|
|
4813
|
+
(0, import_react26.useEffect)(() => {
|
|
4814
|
+
const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
|
|
4815
|
+
prevLiveCountRef.current = discovery.liveCount;
|
|
4816
|
+
if (rose) markTodayActivity();
|
|
4817
|
+
}, [discovery.liveCount, markTodayActivity]);
|
|
4818
|
+
const slip = (0, import_react26.useMemo)(
|
|
4471
4819
|
() => {
|
|
4472
4820
|
const handler = props.config?.onAddToSlip;
|
|
4473
4821
|
return {
|
|
@@ -4490,18 +4838,18 @@ function StatsWidget(props) {
|
|
|
4490
4838
|
},
|
|
4491
4839
|
[props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
|
|
4492
4840
|
);
|
|
4493
|
-
const onDashboardTap = (0,
|
|
4841
|
+
const onDashboardTap = (0, import_react26.useMemo)(
|
|
4494
4842
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
|
|
4495
4843
|
[built, logger]
|
|
4496
4844
|
);
|
|
4497
4845
|
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
4498
4846
|
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
4499
4847
|
const conversationId = controller.state.conversationId ?? void 0;
|
|
4500
|
-
(0,
|
|
4848
|
+
(0, import_react26.useEffect)(() => {
|
|
4501
4849
|
if (!logger) return;
|
|
4502
4850
|
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
4503
4851
|
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
4504
|
-
(0,
|
|
4852
|
+
(0, import_react26.useEffect)(() => {
|
|
4505
4853
|
if (!logger) return;
|
|
4506
4854
|
const onHide = () => {
|
|
4507
4855
|
logger.flushOnHide();
|
|
@@ -4518,14 +4866,14 @@ function StatsWidget(props) {
|
|
|
4518
4866
|
logger.dispose();
|
|
4519
4867
|
};
|
|
4520
4868
|
}, [logger]);
|
|
4521
|
-
(0,
|
|
4869
|
+
(0, import_react26.useEffect)(() => {
|
|
4522
4870
|
if (!built || !ui.injectStyles) return;
|
|
4523
4871
|
const node = rootRef.current?.getRootNode();
|
|
4524
4872
|
if (node) injectStyles(node);
|
|
4525
4873
|
}, [built, ui.injectStyles]);
|
|
4526
4874
|
if (!built) return null;
|
|
4527
4875
|
const attrs = themeAttrs(ui);
|
|
4528
|
-
return /* @__PURE__ */ (0,
|
|
4876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime53.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_runtime53.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0, discovery }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
4529
4877
|
ChatFab,
|
|
4530
4878
|
{
|
|
4531
4879
|
label: ui.launcherLabel,
|