@sensiblestats/widget-react 0.22.0 → 0.23.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 +439 -55
- 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 +431 -47
- package/dist/index.js.map +1 -1
- package/dist/styles.css +112 -0
- 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 { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -519,8 +519,8 @@ function applyEvent(state, event) {
|
|
|
519
519
|
return { ...state, actionsLoading: true, status: event.data.message };
|
|
520
520
|
case "turn_complete": {
|
|
521
521
|
const active = activeTurn(state);
|
|
522
|
-
const
|
|
523
|
-
const popupText = active?.isGreeting && !state.isOpen &&
|
|
522
|
+
const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? "");
|
|
523
|
+
const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText;
|
|
524
524
|
return {
|
|
525
525
|
...state,
|
|
526
526
|
isStreaming: false,
|
|
@@ -531,7 +531,8 @@ function applyEvent(state, event) {
|
|
|
531
531
|
messages: mapActive(state, (t) => ({
|
|
532
532
|
...t,
|
|
533
533
|
done: true,
|
|
534
|
-
greetingDashboard: event.data.dashboard ?? void 0
|
|
534
|
+
greetingDashboard: event.data.dashboard ?? void 0,
|
|
535
|
+
clubFanDashboard: event.data.clubFanDashboard ?? void 0
|
|
535
536
|
}))
|
|
536
537
|
};
|
|
537
538
|
}
|
|
@@ -728,7 +729,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
728
729
|
}
|
|
729
730
|
|
|
730
731
|
// src/components/ChatPanel.tsx
|
|
731
|
-
import { useEffect as
|
|
732
|
+
import { useEffect as useEffect5, useState as useState8 } from "react";
|
|
732
733
|
|
|
733
734
|
// src/components/ChatHeader.tsx
|
|
734
735
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -741,7 +742,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
741
742
|
}
|
|
742
743
|
|
|
743
744
|
// src/components/MessageList.tsx
|
|
744
|
-
import { useEffect as
|
|
745
|
+
import { useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
745
746
|
|
|
746
747
|
// src/components/Markdown.tsx
|
|
747
748
|
import ReactMarkdown from "react-markdown";
|
|
@@ -1287,28 +1288,299 @@ function GreetingDashboard({ dashboard, onTap }) {
|
|
|
1287
1288
|
] });
|
|
1288
1289
|
}
|
|
1289
1290
|
|
|
1291
|
+
// src/components/dashboard/FixtureCard.tsx
|
|
1292
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1293
|
+
function resultClass(result) {
|
|
1294
|
+
const upper = result.toUpperCase();
|
|
1295
|
+
if (upper === "W") return "ss-w-fandash-form-pill--win";
|
|
1296
|
+
if (upper === "L") return "ss-w-fandash-form-pill--loss";
|
|
1297
|
+
return "ss-w-fandash-form-pill--draw";
|
|
1298
|
+
}
|
|
1299
|
+
function FormStrip({ form }) {
|
|
1300
|
+
return /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-form", children: form.map((r, i) => /* @__PURE__ */ jsx17("span", { className: `ss-w-fandash-form-pill ${resultClass(r)}`, children: r }, `${r}-${i}`)) });
|
|
1301
|
+
}
|
|
1302
|
+
function FormRow({ name, form }) {
|
|
1303
|
+
return /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-formrow", children: [
|
|
1304
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-formrow-name", children: name }),
|
|
1305
|
+
/* @__PURE__ */ jsx17(FormStrip, { form })
|
|
1306
|
+
] });
|
|
1307
|
+
}
|
|
1308
|
+
function FixtureCard({ card, onTap }) {
|
|
1309
|
+
const { data } = card;
|
|
1310
|
+
const h2h = data.h2H;
|
|
1311
|
+
return /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
1312
|
+
/* @__PURE__ */ jsxs13("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-fixture", onClick: () => onTap(card), children: [
|
|
1313
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-eyebrow", children: [
|
|
1314
|
+
card.title,
|
|
1315
|
+
" \xB7 ",
|
|
1316
|
+
data.competition
|
|
1317
|
+
] }),
|
|
1318
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-teams", children: [
|
|
1319
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-fixture-team", children: [
|
|
1320
|
+
/* @__PURE__ */ jsx17(Crest2, { url: data.homeCrestUrl ?? void 0, name: data.homeName, kind: "team" }),
|
|
1321
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-name", children: data.homeName })
|
|
1322
|
+
] }),
|
|
1323
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-vs", children: "v" }),
|
|
1324
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away", children: [
|
|
1325
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-name", children: data.awayName }),
|
|
1326
|
+
/* @__PURE__ */ jsx17(Crest2, { url: data.awayCrestUrl ?? void 0, name: data.awayName, kind: "team" })
|
|
1327
|
+
] })
|
|
1328
|
+
] }),
|
|
1329
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-meta", children: [
|
|
1330
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-metarow", children: [
|
|
1331
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metakey", children: data.dateLabel }),
|
|
1332
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metaval", children: data.kickoffLabel })
|
|
1333
|
+
] }),
|
|
1334
|
+
data.venue ? /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-metarow", children: [
|
|
1335
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metakey", children: data.venueLabel }),
|
|
1336
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metaval", children: data.venue })
|
|
1337
|
+
] }) : null
|
|
1338
|
+
] }),
|
|
1339
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
|
|
1340
|
+
] }),
|
|
1341
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-card ss-w-fandash-lastfive", children: [
|
|
1342
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-eyebrow", children: data.formLabel }),
|
|
1343
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-form", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx17(FormRow, { name: data.homeName, form: data.homeForm }),
|
|
1345
|
+
/* @__PURE__ */ jsx17(FormRow, { name: data.awayName, form: data.awayForm })
|
|
1346
|
+
] })
|
|
1347
|
+
] }),
|
|
1348
|
+
h2h || data.fact ? /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-card ss-w-fandash-h2h", children: [
|
|
1349
|
+
h2h ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
1350
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-eyebrow", children: h2h.label }),
|
|
1351
|
+
/* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-split", children: [
|
|
1352
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1353
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.wins }),
|
|
1354
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.homeWinsLabel })
|
|
1355
|
+
] }),
|
|
1356
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1357
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.draws }),
|
|
1358
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.drawsLabel })
|
|
1359
|
+
] }),
|
|
1360
|
+
/* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1361
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.losses }),
|
|
1362
|
+
/* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.awayWinsLabel })
|
|
1363
|
+
] })
|
|
1364
|
+
] })
|
|
1365
|
+
] }) : null,
|
|
1366
|
+
data.fact ? /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fact", children: data.fact }) : null
|
|
1367
|
+
] }) : null
|
|
1368
|
+
] });
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// src/components/dashboard/CountdownCard.tsx
|
|
1372
|
+
import { Fragment as Fragment6, useEffect as useEffect3, useState as useState6 } from "react";
|
|
1373
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1374
|
+
var DAY_MS = 864e5;
|
|
1375
|
+
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
1376
|
+
const totalSeconds = Math.floor((kickoffUnix * 1e3 - nowMs) / 1e3);
|
|
1377
|
+
if (totalSeconds <= 0) return null;
|
|
1378
|
+
const days = Math.floor(totalSeconds / 86400);
|
|
1379
|
+
const hours = Math.floor(totalSeconds % 86400 / 3600);
|
|
1380
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
1381
|
+
const seconds = totalSeconds % 60;
|
|
1382
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
1383
|
+
if (days > 0) return [{ value: pad(days), unit: "d" }, { value: pad(hours), unit: "h" }];
|
|
1384
|
+
const segs = [{ value: pad(hours), unit: "h" }, { value: pad(minutes), unit: "m" }];
|
|
1385
|
+
if (withSeconds) segs.push({ value: pad(seconds), unit: "s" });
|
|
1386
|
+
return segs;
|
|
1387
|
+
}
|
|
1388
|
+
function CountdownCard({ card }) {
|
|
1389
|
+
const { data } = card;
|
|
1390
|
+
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
1391
|
+
const [nowMs, setNowMs] = useState6(() => Date.now());
|
|
1392
|
+
const [reduced] = useState6(
|
|
1393
|
+
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
1394
|
+
);
|
|
1395
|
+
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
1396
|
+
useEffect3(() => {
|
|
1397
|
+
if (reduced) return;
|
|
1398
|
+
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
1399
|
+
return () => window.clearInterval(id);
|
|
1400
|
+
}, [reduced, withinDay]);
|
|
1401
|
+
const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
|
|
1402
|
+
return /* @__PURE__ */ jsx18("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ jsxs14("div", { className: "ss-w-fandash-countdown-top", children: [
|
|
1403
|
+
/* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
|
|
1404
|
+
segments ? /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
1405
|
+
i > 0 ? /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
|
|
1406
|
+
/* @__PURE__ */ jsxs14("span", { className: "ss-w-fandash-countdown-seg", children: [
|
|
1407
|
+
/* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
|
|
1408
|
+
/* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-unit", children: unitLabel[s.unit] })
|
|
1409
|
+
] })
|
|
1410
|
+
] }, s.unit)) }) : null
|
|
1411
|
+
] }) });
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// src/components/dashboard/InjuriesCard.tsx
|
|
1415
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1416
|
+
function ColHead({ name, crestUrl }) {
|
|
1417
|
+
return /* @__PURE__ */ jsxs15("span", { className: "ss-w-fandash-injuries-col-head", children: [
|
|
1418
|
+
/* @__PURE__ */ jsx19(Crest2, { url: crestUrl ?? void 0, name, kind: "team" }),
|
|
1419
|
+
/* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injuries-col-head-name", children: name })
|
|
1420
|
+
] });
|
|
1421
|
+
}
|
|
1422
|
+
function InjuryList({ rows, emptyLabel }) {
|
|
1423
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injuries-empty", children: emptyLabel });
|
|
1424
|
+
return /* @__PURE__ */ jsx19("ul", { className: "ss-w-fandash-injury-list", children: rows.map((r, i) => /* @__PURE__ */ jsxs15("li", { className: "ss-w-fandash-injury-row", children: [
|
|
1425
|
+
/* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-name", children: r.playerName }),
|
|
1426
|
+
/* @__PURE__ */ jsxs15("span", { className: "ss-w-fandash-injury-meta", children: [
|
|
1427
|
+
/* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-status", children: r.status }),
|
|
1428
|
+
r.injuryType ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-type", children: r.injuryType }) : null,
|
|
1429
|
+
r.expectedReturnLabel ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-return", children: r.expectedReturnLabel }) : null
|
|
1430
|
+
] })
|
|
1431
|
+
] }, `${r.playerName}-${i}`)) });
|
|
1432
|
+
}
|
|
1433
|
+
function InjuriesCard({ card }) {
|
|
1434
|
+
const { data } = card;
|
|
1435
|
+
return /* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-card ss-w-fandash-injuries", children: [
|
|
1436
|
+
card.title ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1437
|
+
/* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-cols", children: [
|
|
1438
|
+
/* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-col", children: [
|
|
1439
|
+
/* @__PURE__ */ jsx19(ColHead, { name: data.oursName, crestUrl: data.oursCrestUrl }),
|
|
1440
|
+
/* @__PURE__ */ jsx19(InjuryList, { rows: data.ours, emptyLabel: data.emptyLabel })
|
|
1441
|
+
] }),
|
|
1442
|
+
/* @__PURE__ */ jsx19("div", { className: "ss-w-fandash-injuries-divider" }),
|
|
1443
|
+
/* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-col", children: [
|
|
1444
|
+
/* @__PURE__ */ jsx19(ColHead, { name: data.theirsName, crestUrl: data.theirsCrestUrl }),
|
|
1445
|
+
/* @__PURE__ */ jsx19(InjuryList, { rows: data.theirs, emptyLabel: data.emptyLabel })
|
|
1446
|
+
] })
|
|
1447
|
+
] })
|
|
1448
|
+
] });
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// src/components/dashboard/ReasonToBetCard.tsx
|
|
1452
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1453
|
+
function ReasonToBetCard({ card }) {
|
|
1454
|
+
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-fandash-card ss-w-fandash-reasons", children: [
|
|
1455
|
+
card.title ? /* @__PURE__ */ jsx20("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1456
|
+
/* @__PURE__ */ jsx20("ul", { className: "ss-w-fandash-reason-list", children: card.data.angles.map((angle, i) => /* @__PURE__ */ jsx20("li", { className: "ss-w-fandash-reason-item", children: angle }, `${angle}-${i}`)) })
|
|
1457
|
+
] });
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// src/components/dashboard/WhereToWatchCard.tsx
|
|
1461
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1462
|
+
function WhereToWatchCard({ card }) {
|
|
1463
|
+
return /* @__PURE__ */ jsxs17("div", { className: "ss-w-fandash-card ss-w-fandash-watch", children: [
|
|
1464
|
+
card.title ? /* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1465
|
+
/* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-stations", children: card.data.stations.map((station, i) => /* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-station-chip", children: station }, `${station}-${i}`)) })
|
|
1466
|
+
] });
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// src/components/dashboard/CongestedWeekCard.tsx
|
|
1470
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1471
|
+
function CongestedWeekCard({ card, onTap }) {
|
|
1472
|
+
return /* @__PURE__ */ jsxs18("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested", onClick: () => onTap(card), children: [
|
|
1473
|
+
card.title ? /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1474
|
+
/* @__PURE__ */ jsx22("div", { className: "ss-w-fandash-congested-grid", children: card.data.entries.map((entry, i) => /* @__PURE__ */ jsxs18("span", { className: "ss-w-fandash-congested-cell", children: [
|
|
1475
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-day", children: entry.dayLabel }),
|
|
1476
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-opponent", children: entry.opponent }),
|
|
1477
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-comp", children: entry.competition }),
|
|
1478
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-time", children: entry.timeLabel })
|
|
1479
|
+
] }, `${entry.opponent}-${i}`)) }),
|
|
1480
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
|
|
1481
|
+
] });
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
// src/components/dashboard/TransfersCard.tsx
|
|
1485
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1486
|
+
function TransferList({ rows }) {
|
|
1487
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-empty", children: "None" });
|
|
1488
|
+
return /* @__PURE__ */ jsx23("ul", { className: "ss-w-fandash-transfer-list", children: rows.map((r, i) => /* @__PURE__ */ jsxs19("li", { className: "ss-w-fandash-transfer-row", children: [
|
|
1489
|
+
/* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-name", children: r.playerName }),
|
|
1490
|
+
/* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-club", children: r.otherClub }),
|
|
1491
|
+
r.type ? /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-type", children: r.type }) : null
|
|
1492
|
+
] }, `${r.playerName}-${i}`)) });
|
|
1493
|
+
}
|
|
1494
|
+
function TransfersCard({ card }) {
|
|
1495
|
+
const { data } = card;
|
|
1496
|
+
return /* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-card ss-w-fandash-transfers", children: [
|
|
1497
|
+
card.title ? /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1498
|
+
/* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-cols", children: [
|
|
1499
|
+
/* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-col", children: [
|
|
1500
|
+
/* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-col-head", children: "In" }),
|
|
1501
|
+
/* @__PURE__ */ jsx23(TransferList, { rows: data.in })
|
|
1502
|
+
] }),
|
|
1503
|
+
/* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-col", children: [
|
|
1504
|
+
/* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-col-head", children: "Out" }),
|
|
1505
|
+
/* @__PURE__ */ jsx23(TransferList, { rows: data.out })
|
|
1506
|
+
] })
|
|
1507
|
+
] })
|
|
1508
|
+
] });
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// src/components/dashboard/LinksCard.tsx
|
|
1512
|
+
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1513
|
+
function LinksCard({ card }) {
|
|
1514
|
+
return /* @__PURE__ */ jsxs20("div", { className: "ss-w-fandash-card ss-w-fandash-links", children: [
|
|
1515
|
+
card.title ? /* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1516
|
+
/* @__PURE__ */ jsx24("div", { className: "ss-w-fandash-link-grid", children: card.data.links.map((link, i) => /* @__PURE__ */ jsxs20("a", { className: "ss-w-fandash-link-tile", href: link.url, target: "_blank", rel: "noopener noreferrer", children: [
|
|
1517
|
+
/* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-link-label", children: link.label }),
|
|
1518
|
+
/* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-link-chevron", children: /* @__PURE__ */ jsx24(ChevronIcon, {}) })
|
|
1519
|
+
] }, `${link.url}-${i}`)) })
|
|
1520
|
+
] });
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// src/components/dashboard/ClubFanDashboard.tsx
|
|
1524
|
+
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1525
|
+
function ClubFanDashboard({ dashboard, onTap, ui }) {
|
|
1526
|
+
const orderedCards = [
|
|
1527
|
+
...dashboard.cards.filter((c) => c.cardType === "countdown"),
|
|
1528
|
+
...dashboard.cards.filter((c) => c.cardType !== "countdown")
|
|
1529
|
+
];
|
|
1530
|
+
return /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash", children: [
|
|
1531
|
+
dashboard.greeting ? /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
|
|
1532
|
+
/* @__PURE__ */ jsx25("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ jsx25(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
|
|
1533
|
+
] });
|
|
1534
|
+
}
|
|
1535
|
+
function FanDashboardCard({ card, onTap, ui }) {
|
|
1536
|
+
switch (card.cardType) {
|
|
1537
|
+
case "fixture":
|
|
1538
|
+
return /* @__PURE__ */ jsx25(FixtureCard, { card, onTap });
|
|
1539
|
+
case "countdown":
|
|
1540
|
+
return /* @__PURE__ */ jsx25(CountdownCard, { card });
|
|
1541
|
+
case "injuries":
|
|
1542
|
+
return /* @__PURE__ */ jsx25(InjuriesCard, { card });
|
|
1543
|
+
case "reasonToBet":
|
|
1544
|
+
return /* @__PURE__ */ jsx25(ReasonToBetCard, { card });
|
|
1545
|
+
case "whereToWatch":
|
|
1546
|
+
return /* @__PURE__ */ jsx25(WhereToWatchCard, { card });
|
|
1547
|
+
case "congestedWeek":
|
|
1548
|
+
return /* @__PURE__ */ jsx25(CongestedWeekCard, { card, onTap });
|
|
1549
|
+
case "transfers":
|
|
1550
|
+
return /* @__PURE__ */ jsx25(TransfersCard, { card });
|
|
1551
|
+
case "links":
|
|
1552
|
+
return /* @__PURE__ */ jsx25(LinksCard, { card });
|
|
1553
|
+
default:
|
|
1554
|
+
return null;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1290
1558
|
// src/components/ChatMessage.tsx
|
|
1291
|
-
import { jsx as
|
|
1559
|
+
import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1292
1560
|
function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
|
|
1293
1561
|
if (message.role === "user") {
|
|
1294
|
-
return /* @__PURE__ */
|
|
1562
|
+
return /* @__PURE__ */ jsx26("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx26("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1295
1563
|
}
|
|
1296
|
-
|
|
1297
|
-
message.
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1564
|
+
const onFanDashboardTap = (card) => {
|
|
1565
|
+
onAct({ message: card.actionValue, label: card.actionLabel || card.title || "" });
|
|
1566
|
+
};
|
|
1567
|
+
return /* @__PURE__ */ jsxs22("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1568
|
+
message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ jsx26(Markdown, { text: message.text }) : null,
|
|
1569
|
+
message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ jsx26(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1570
|
+
message.clubFanDashboard ? /* @__PURE__ */ jsx26(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
|
|
1571
|
+
/* @__PURE__ */ jsx26(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1572
|
+
/* @__PURE__ */ jsx26(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1573
|
+
/* @__PURE__ */ jsx26(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1574
|
+
/* @__PURE__ */ jsx26(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1575
|
+
/* @__PURE__ */ jsx26(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1304
1576
|
] });
|
|
1305
1577
|
}
|
|
1306
1578
|
|
|
1307
1579
|
// src/components/IntentChips.tsx
|
|
1308
|
-
import { jsx as
|
|
1580
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1309
1581
|
function IntentChips({ chips, onPick }) {
|
|
1310
1582
|
if (chips.length === 0) return null;
|
|
1311
|
-
return /* @__PURE__ */
|
|
1583
|
+
return /* @__PURE__ */ jsx27("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx27("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1312
1584
|
}
|
|
1313
1585
|
|
|
1314
1586
|
// src/scroll.ts
|
|
@@ -1318,18 +1590,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1318
1590
|
}
|
|
1319
1591
|
|
|
1320
1592
|
// src/components/MessageList.tsx
|
|
1321
|
-
import { jsx as
|
|
1593
|
+
import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1322
1594
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1323
1595
|
const { state, send } = controller;
|
|
1324
1596
|
const listRef = useRef2(null);
|
|
1325
1597
|
const endRef = useRef2(null);
|
|
1326
1598
|
const pinnedRef = useRef2(true);
|
|
1327
|
-
|
|
1599
|
+
useEffect4(() => {
|
|
1328
1600
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
1329
1601
|
}, [state.messages, state.status]);
|
|
1330
1602
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1331
|
-
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1332
|
-
return /* @__PURE__ */
|
|
1603
|
+
const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
|
|
1604
|
+
return /* @__PURE__ */ jsxs23(
|
|
1333
1605
|
"div",
|
|
1334
1606
|
{
|
|
1335
1607
|
className: "ss-w-list",
|
|
@@ -1339,7 +1611,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1339
1611
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1340
1612
|
},
|
|
1341
1613
|
children: [
|
|
1342
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
1614
|
+
state.messages.map((m) => /* @__PURE__ */ jsx28(
|
|
1343
1615
|
ChatMessage,
|
|
1344
1616
|
{
|
|
1345
1617
|
message: m,
|
|
@@ -1354,25 +1626,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1354
1626
|
},
|
|
1355
1627
|
m.id
|
|
1356
1628
|
)),
|
|
1357
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
1629
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx28(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1358
1630
|
} }) : null,
|
|
1359
|
-
state.status ? /* @__PURE__ */
|
|
1360
|
-
state.error ? /* @__PURE__ */
|
|
1361
|
-
/* @__PURE__ */
|
|
1362
|
-
/* @__PURE__ */
|
|
1631
|
+
state.status ? /* @__PURE__ */ jsx28("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1632
|
+
state.error ? /* @__PURE__ */ jsxs23("div", { className: "ss-w-error", role: "alert", children: [
|
|
1633
|
+
/* @__PURE__ */ jsx28("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1634
|
+
/* @__PURE__ */ jsx28("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1363
1635
|
] }) : null,
|
|
1364
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */
|
|
1365
|
-
/* @__PURE__ */
|
|
1636
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx28(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1637
|
+
/* @__PURE__ */ jsx28("div", { ref: endRef })
|
|
1366
1638
|
]
|
|
1367
1639
|
}
|
|
1368
1640
|
);
|
|
1369
1641
|
}
|
|
1370
1642
|
|
|
1371
1643
|
// src/components/ChatInput.tsx
|
|
1372
|
-
import { useState as
|
|
1373
|
-
import { jsx as
|
|
1644
|
+
import { useState as useState7 } from "react";
|
|
1645
|
+
import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1374
1646
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1375
|
-
const [value, setValue] =
|
|
1647
|
+
const [value, setValue] = useState7("");
|
|
1376
1648
|
const submit = () => {
|
|
1377
1649
|
const t = value.trim();
|
|
1378
1650
|
if (!t) return;
|
|
@@ -1385,18 +1657,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1385
1657
|
submit();
|
|
1386
1658
|
}
|
|
1387
1659
|
};
|
|
1388
|
-
return /* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
streaming ? /* @__PURE__ */
|
|
1660
|
+
return /* @__PURE__ */ jsxs24("div", { className: "ss-w-input", children: [
|
|
1661
|
+
/* @__PURE__ */ jsx29("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1662
|
+
streaming ? /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx29("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx29(SendIcon, {}) })
|
|
1391
1663
|
] });
|
|
1392
1664
|
}
|
|
1393
1665
|
|
|
1394
1666
|
// src/components/ChatPanel.tsx
|
|
1395
|
-
import { jsx as
|
|
1667
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1396
1668
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1397
1669
|
function useIsModal() {
|
|
1398
|
-
const [modal, setModal] =
|
|
1399
|
-
|
|
1670
|
+
const [modal, setModal] = useState8(false);
|
|
1671
|
+
useEffect5(() => {
|
|
1400
1672
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1401
1673
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1402
1674
|
const sync = () => setModal(mql.matches);
|
|
@@ -1409,17 +1681,17 @@ function useIsModal() {
|
|
|
1409
1681
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
1410
1682
|
const { state, close, stop, send } = controller;
|
|
1411
1683
|
const isModal = useIsModal();
|
|
1412
|
-
|
|
1684
|
+
useEffect5(() => {
|
|
1413
1685
|
const onKey = (e) => {
|
|
1414
1686
|
if (e.key === "Escape") close();
|
|
1415
1687
|
};
|
|
1416
1688
|
window.addEventListener("keydown", onKey);
|
|
1417
1689
|
return () => window.removeEventListener("keydown", onKey);
|
|
1418
1690
|
}, [close]);
|
|
1419
|
-
return /* @__PURE__ */
|
|
1420
|
-
/* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1422
|
-
/* @__PURE__ */
|
|
1691
|
+
return /* @__PURE__ */ jsxs25("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1692
|
+
/* @__PURE__ */ jsx30(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1693
|
+
/* @__PURE__ */ jsx30(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1694
|
+
/* @__PURE__ */ jsx30(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1423
1695
|
] });
|
|
1424
1696
|
}
|
|
1425
1697
|
|
|
@@ -1772,10 +2044,122 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1772
2044
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
|
|
1773
2045
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
|
|
1774
2046
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
|
|
2047
|
+
|
|
2048
|
+
/* club fan pre-match dashboard */
|
|
2049
|
+
.ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
|
|
2050
|
+
.ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }
|
|
2051
|
+
.ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }
|
|
2052
|
+
|
|
2053
|
+
/* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both
|
|
2054
|
+
share the same box so the two families read as one system, not two ad hoc layouts. */
|
|
2055
|
+
.ss-w-fandash-card {
|
|
2056
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
2057
|
+
padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);
|
|
2058
|
+
background: var(--ss-w-panel); text-align: left;
|
|
2059
|
+
color: inherit; font: inherit; width: 100%; min-width: 0;
|
|
2060
|
+
}
|
|
2061
|
+
.ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }
|
|
2062
|
+
.ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }
|
|
2063
|
+
.ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2064
|
+
|
|
2065
|
+
/* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label
|
|
2066
|
+
split reused by the fixture head-to-head (and any future stat-row card). */
|
|
2067
|
+
.ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
|
|
2068
|
+
.ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
2069
|
+
.ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }
|
|
2070
|
+
.ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }
|
|
2071
|
+
.ss-w-fandash-split-label { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); overflow-wrap: anywhere; }
|
|
2072
|
+
|
|
2073
|
+
/* fixture card */
|
|
2074
|
+
.ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }
|
|
2075
|
+
.ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
|
|
2076
|
+
.ss-w-fandash-fixture-team--away { justify-content: flex-end; }
|
|
2077
|
+
.ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }
|
|
2078
|
+
.ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }
|
|
2079
|
+
.ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
|
|
2080
|
+
.ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }
|
|
2081
|
+
.ss-w-fandash-fixture-vs { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
|
|
2082
|
+
/* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */
|
|
2083
|
+
.ss-w-fandash-fixture-meta { display: flex; flex-direction: column; gap: 1px; border-top: 1px solid var(--ss-w-line); padding-top: 8px; }
|
|
2084
|
+
.ss-w-fandash-fixture-metarow { display: flex; align-items: baseline; gap: 9px; }
|
|
2085
|
+
.ss-w-fandash-fixture-metakey { flex: none; width: 44px; font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
|
|
2086
|
+
.ss-w-fandash-fixture-metaval { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
|
|
2087
|
+
.ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }
|
|
2088
|
+
/* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */
|
|
2089
|
+
.ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }
|
|
2090
|
+
/* extra breathing room between the tally row and the fact beyond the card's own gap */
|
|
2091
|
+
.ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }
|
|
2092
|
+
|
|
2093
|
+
/* last-five: one row per side, team name left, form pills right */
|
|
2094
|
+
.ss-w-fandash-fixture-form { display: flex; flex-direction: column; gap: 5px; }
|
|
2095
|
+
.ss-w-fandash-formrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
2096
|
+
.ss-w-fandash-formrow-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 600; }
|
|
2097
|
+
.ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }
|
|
2098
|
+
.ss-w-fandash-form-pill {
|
|
2099
|
+
display: inline-grid; place-items: center; width: 16px; height: 16px;
|
|
2100
|
+
border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;
|
|
2101
|
+
}
|
|
2102
|
+
.ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }
|
|
2103
|
+
.ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }
|
|
2104
|
+
.ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }
|
|
2105
|
+
|
|
2106
|
+
/* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each
|
|
2107
|
+
segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not
|
|
2108
|
+
repeated here; the fixture card below carries it. */
|
|
2109
|
+
.ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
2110
|
+
.ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }
|
|
2111
|
+
.ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }
|
|
2112
|
+
.ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }
|
|
2113
|
+
.ss-w-fandash-countdown-unit { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); margin-top: 3px; }
|
|
2114
|
+
.ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }
|
|
2115
|
+
|
|
2116
|
+
/* injuries + transfers: two-column ours/theirs, in/out */
|
|
2117
|
+
.ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
|
|
2118
|
+
/* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */
|
|
2119
|
+
.ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }
|
|
2120
|
+
.ss-w-fandash-injuries-divider { background: var(--ss-w-line); }
|
|
2121
|
+
.ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
2122
|
+
.ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }
|
|
2123
|
+
.ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }
|
|
2124
|
+
.ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }
|
|
2125
|
+
.ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }
|
|
2126
|
+
.ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2127
|
+
.ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }
|
|
2128
|
+
.ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }
|
|
2129
|
+
.ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }
|
|
2130
|
+
.ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }
|
|
2131
|
+
.ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
2132
|
+
.ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }
|
|
2133
|
+
.ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }
|
|
2134
|
+
.ss-w-fandash-transfer-type { align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 1px 7px; margin-top: 2px; }
|
|
2135
|
+
|
|
2136
|
+
/* reason-to-bet */
|
|
2137
|
+
.ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
|
|
2138
|
+
.ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }
|
|
2139
|
+
.ss-w-fandash-reason-item::before { content: "\u2022"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }
|
|
2140
|
+
|
|
2141
|
+
/* where-to-watch */
|
|
2142
|
+
.ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
2143
|
+
.ss-w-fandash-station-chip { font-size: 11.5px; font-weight: 600; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 999px; padding: 4px 10px; }
|
|
2144
|
+
|
|
2145
|
+
/* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */
|
|
2146
|
+
.ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
2147
|
+
.ss-w-fandash-congested-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 8px; border-radius: 10px; background: var(--ss-w-bubble); }
|
|
2148
|
+
.ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
|
|
2149
|
+
.ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
|
|
2150
|
+
.ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
|
|
2151
|
+
.ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
|
|
2152
|
+
|
|
2153
|
+
/* links: 2-column grid of tappable tiles */
|
|
2154
|
+
.ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
2155
|
+
.ss-w-fandash-link-tile { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 11px 13px; border-radius: 10px; border: 1px solid transparent; text-decoration: none; color: inherit; background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); }
|
|
2156
|
+
.ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
|
|
2157
|
+
.ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
|
|
2158
|
+
.ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }
|
|
1775
2159
|
`;
|
|
1776
2160
|
|
|
1777
2161
|
// src/StatsWidget.tsx
|
|
1778
|
-
import { jsx as
|
|
2162
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1779
2163
|
function buildClient(props) {
|
|
1780
2164
|
try {
|
|
1781
2165
|
if ("client" in props && props.client) {
|
|
@@ -1821,14 +2205,14 @@ function StatsWidget(props) {
|
|
|
1821
2205
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
1822
2206
|
[built]
|
|
1823
2207
|
);
|
|
1824
|
-
|
|
2208
|
+
useEffect6(() => {
|
|
1825
2209
|
if (!built || !ui.injectStyles) return;
|
|
1826
2210
|
const node = rootRef.current?.getRootNode();
|
|
1827
2211
|
if (node) injectStyles(node);
|
|
1828
2212
|
}, [built, ui.injectStyles]);
|
|
1829
2213
|
if (!built) return null;
|
|
1830
2214
|
const attrs = themeAttrs(ui);
|
|
1831
|
-
return /* @__PURE__ */
|
|
2215
|
+
return /* @__PURE__ */ jsx31("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__ */ jsx31(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx31(
|
|
1832
2216
|
ChatFab,
|
|
1833
2217
|
{
|
|
1834
2218
|
label: ui.launcherLabel,
|