@sensiblestats/widget-react 0.22.0 → 0.23.1
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 +21 -0
- package/dist/index.cjs +442 -57
- 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 +434 -49
- package/dist/index.js.map +1 -1
- package/dist/styles.css +112 -0
- 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_react12 = require("react");
|
|
40
40
|
var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/kickoff.ts
|
|
@@ -359,8 +359,9 @@ function toCardVM(card) {
|
|
|
359
359
|
function toActionVM(action) {
|
|
360
360
|
const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
|
|
361
361
|
const actionId = str(action.actionId) ?? str(action.id);
|
|
362
|
+
const actionRef = str(action.actionRef);
|
|
362
363
|
const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
|
|
363
|
-
return { label, actionId, message };
|
|
364
|
+
return { label, actionId, actionRef, message };
|
|
364
365
|
}
|
|
365
366
|
function toChipVM(intent) {
|
|
366
367
|
const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
|
|
@@ -556,8 +557,8 @@ function applyEvent(state, event) {
|
|
|
556
557
|
return { ...state, actionsLoading: true, status: event.data.message };
|
|
557
558
|
case "turn_complete": {
|
|
558
559
|
const active = activeTurn(state);
|
|
559
|
-
const
|
|
560
|
-
const popupText = active?.isGreeting && !state.isOpen &&
|
|
560
|
+
const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? "");
|
|
561
|
+
const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText;
|
|
561
562
|
return {
|
|
562
563
|
...state,
|
|
563
564
|
isStreaming: false,
|
|
@@ -568,7 +569,8 @@ function applyEvent(state, event) {
|
|
|
568
569
|
messages: mapActive(state, (t) => ({
|
|
569
570
|
...t,
|
|
570
571
|
done: true,
|
|
571
|
-
greetingDashboard: event.data.dashboard ?? void 0
|
|
572
|
+
greetingDashboard: event.data.dashboard ?? void 0,
|
|
573
|
+
clubFanDashboard: event.data.clubFanDashboard ?? void 0
|
|
572
574
|
}))
|
|
573
575
|
};
|
|
574
576
|
}
|
|
@@ -765,7 +767,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
765
767
|
}
|
|
766
768
|
|
|
767
769
|
// src/components/ChatPanel.tsx
|
|
768
|
-
var
|
|
770
|
+
var import_react11 = require("react");
|
|
769
771
|
|
|
770
772
|
// src/components/ChatHeader.tsx
|
|
771
773
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -778,7 +780,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
778
780
|
}
|
|
779
781
|
|
|
780
782
|
// src/components/MessageList.tsx
|
|
781
|
-
var
|
|
783
|
+
var import_react9 = require("react");
|
|
782
784
|
|
|
783
785
|
// src/components/Markdown.tsx
|
|
784
786
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -1324,28 +1326,299 @@ function GreetingDashboard({ dashboard, onTap }) {
|
|
|
1324
1326
|
] });
|
|
1325
1327
|
}
|
|
1326
1328
|
|
|
1327
|
-
// src/components/
|
|
1329
|
+
// src/components/dashboard/FixtureCard.tsx
|
|
1328
1330
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1331
|
+
function resultClass(result) {
|
|
1332
|
+
const upper = result.toUpperCase();
|
|
1333
|
+
if (upper === "W") return "ss-w-fandash-form-pill--win";
|
|
1334
|
+
if (upper === "L") return "ss-w-fandash-form-pill--loss";
|
|
1335
|
+
return "ss-w-fandash-form-pill--draw";
|
|
1336
|
+
}
|
|
1337
|
+
function FormStrip({ form }) {
|
|
1338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-form", children: form.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: `ss-w-fandash-form-pill ${resultClass(r)}`, children: r }, `${r}-${i}`)) });
|
|
1339
|
+
}
|
|
1340
|
+
function FormRow({ name, form }) {
|
|
1341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-formrow", children: [
|
|
1342
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-formrow-name", children: name }),
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormStrip, { form })
|
|
1344
|
+
] });
|
|
1345
|
+
}
|
|
1346
|
+
function FixtureCard({ card, onTap }) {
|
|
1347
|
+
const { data } = card;
|
|
1348
|
+
const h2h = data.h2H;
|
|
1349
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-fixture", onClick: () => onTap(card), children: [
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-eyebrow", children: [
|
|
1352
|
+
card.title,
|
|
1353
|
+
" \xB7 ",
|
|
1354
|
+
data.competition
|
|
1355
|
+
] }),
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-teams", children: [
|
|
1357
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-fixture-team", children: [
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: data.homeCrestUrl ?? void 0, name: data.homeName, kind: "team" }),
|
|
1359
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-name", children: data.homeName })
|
|
1360
|
+
] }),
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-vs", children: "v" }),
|
|
1362
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away", children: [
|
|
1363
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-name", children: data.awayName }),
|
|
1364
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: data.awayCrestUrl ?? void 0, name: data.awayName, kind: "team" })
|
|
1365
|
+
] })
|
|
1366
|
+
] }),
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-meta", children: [
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-metarow", children: [
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metakey", children: data.dateLabel }),
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metaval", children: data.kickoffLabel })
|
|
1371
|
+
] }),
|
|
1372
|
+
data.venue ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-metarow", children: [
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metakey", children: data.venueLabel }),
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metaval", children: data.venue })
|
|
1375
|
+
] }) : null
|
|
1376
|
+
] }),
|
|
1377
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
|
|
1378
|
+
] }),
|
|
1379
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-lastfive", children: [
|
|
1380
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-eyebrow", children: data.formLabel }),
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-form", children: [
|
|
1382
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormRow, { name: data.homeName, form: data.homeForm }),
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormRow, { name: data.awayName, form: data.awayForm })
|
|
1384
|
+
] })
|
|
1385
|
+
] }),
|
|
1386
|
+
h2h || data.fact ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-h2h", children: [
|
|
1387
|
+
h2h ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
1388
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-eyebrow", children: h2h.label }),
|
|
1389
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-split", children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.wins }),
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.homeWinsLabel })
|
|
1393
|
+
] }),
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.draws }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.drawsLabel })
|
|
1397
|
+
] }),
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.losses }),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.awayWinsLabel })
|
|
1401
|
+
] })
|
|
1402
|
+
] })
|
|
1403
|
+
] }) : null,
|
|
1404
|
+
data.fact ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fact", children: data.fact }) : null
|
|
1405
|
+
] }) : null
|
|
1406
|
+
] });
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/components/dashboard/CountdownCard.tsx
|
|
1410
|
+
var import_react8 = require("react");
|
|
1411
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1412
|
+
var DAY_MS = 864e5;
|
|
1413
|
+
function remainingSegments(kickoffUnix, nowMs, withSeconds) {
|
|
1414
|
+
const totalSeconds = Math.floor((kickoffUnix * 1e3 - nowMs) / 1e3);
|
|
1415
|
+
if (totalSeconds <= 0) return null;
|
|
1416
|
+
const days = Math.floor(totalSeconds / 86400);
|
|
1417
|
+
const hours = Math.floor(totalSeconds % 86400 / 3600);
|
|
1418
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
1419
|
+
const seconds = totalSeconds % 60;
|
|
1420
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
1421
|
+
if (days > 0) return [{ value: pad(days), unit: "d" }, { value: pad(hours), unit: "h" }];
|
|
1422
|
+
const segs = [{ value: pad(hours), unit: "h" }, { value: pad(minutes), unit: "m" }];
|
|
1423
|
+
if (withSeconds) segs.push({ value: pad(seconds), unit: "s" });
|
|
1424
|
+
return segs;
|
|
1425
|
+
}
|
|
1426
|
+
function CountdownCard({ card }) {
|
|
1427
|
+
const { data } = card;
|
|
1428
|
+
const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
|
|
1429
|
+
const [nowMs, setNowMs] = (0, import_react8.useState)(() => Date.now());
|
|
1430
|
+
const [reduced] = (0, import_react8.useState)(
|
|
1431
|
+
() => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
1432
|
+
);
|
|
1433
|
+
const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
|
|
1434
|
+
(0, import_react8.useEffect)(() => {
|
|
1435
|
+
if (reduced) return;
|
|
1436
|
+
const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
|
|
1437
|
+
return () => window.clearInterval(id);
|
|
1438
|
+
}, [reduced, withinDay]);
|
|
1439
|
+
const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
|
|
1440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-fandash-countdown-top", children: [
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
|
|
1442
|
+
segments ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react8.Fragment, { children: [
|
|
1443
|
+
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
|
|
1446
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-unit", children: unitLabel[s.unit] })
|
|
1447
|
+
] })
|
|
1448
|
+
] }, s.unit)) }) : null
|
|
1449
|
+
] }) });
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// src/components/dashboard/InjuriesCard.tsx
|
|
1453
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1454
|
+
function ColHead({ name, crestUrl }) {
|
|
1455
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-fandash-injuries-col-head", children: [
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Crest2, { url: crestUrl ?? void 0, name, kind: "team" }),
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injuries-col-head-name", children: name })
|
|
1458
|
+
] });
|
|
1459
|
+
}
|
|
1460
|
+
function InjuryList({ rows, emptyLabel }) {
|
|
1461
|
+
if (rows.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injuries-empty", children: emptyLabel });
|
|
1462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "ss-w-fandash-injury-list", children: rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "ss-w-fandash-injury-row", children: [
|
|
1463
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-name", children: r.playerName }),
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-fandash-injury-meta", children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-status", children: r.status }),
|
|
1466
|
+
r.injuryType ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-type", children: r.injuryType }) : null,
|
|
1467
|
+
r.expectedReturnLabel ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-return", children: r.expectedReturnLabel }) : null
|
|
1468
|
+
] })
|
|
1469
|
+
] }, `${r.playerName}-${i}`)) });
|
|
1470
|
+
}
|
|
1471
|
+
function InjuriesCard({ card }) {
|
|
1472
|
+
const { data } = card;
|
|
1473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-injuries", children: [
|
|
1474
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-cols", children: [
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-col", children: [
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColHead, { name: data.oursName, crestUrl: data.oursCrestUrl }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InjuryList, { rows: data.ours, emptyLabel: data.emptyLabel })
|
|
1479
|
+
] }),
|
|
1480
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-fandash-injuries-divider" }),
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-col", children: [
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColHead, { name: data.theirsName, crestUrl: data.theirsCrestUrl }),
|
|
1483
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InjuryList, { rows: data.theirs, emptyLabel: data.emptyLabel })
|
|
1484
|
+
] })
|
|
1485
|
+
] })
|
|
1486
|
+
] });
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// src/components/dashboard/ReasonToBetCard.tsx
|
|
1490
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1491
|
+
function ReasonToBetCard({ card }) {
|
|
1492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-reasons", children: [
|
|
1493
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "ss-w-fandash-reason-list", children: card.data.angles.map((angle, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: "ss-w-fandash-reason-item", children: angle }, `${angle}-${i}`)) })
|
|
1495
|
+
] });
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// src/components/dashboard/WhereToWatchCard.tsx
|
|
1499
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1500
|
+
function WhereToWatchCard({ card }) {
|
|
1501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-watch", children: [
|
|
1502
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1503
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-stations", children: card.data.stations.map((station, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-station-chip", children: station }, `${station}-${i}`)) })
|
|
1504
|
+
] });
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/components/dashboard/CongestedWeekCard.tsx
|
|
1508
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1509
|
+
function CongestedWeekCard({ card, onTap }) {
|
|
1510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested", onClick: () => onTap(card), children: [
|
|
1511
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1512
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-fandash-congested-grid", children: card.data.entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "ss-w-fandash-congested-cell", children: [
|
|
1513
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-day", children: entry.dayLabel }),
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-opponent", children: entry.opponent }),
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-comp", children: entry.competition }),
|
|
1516
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-time", children: entry.timeLabel })
|
|
1517
|
+
] }, `${entry.opponent}-${i}`)) }),
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
|
|
1519
|
+
] });
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// src/components/dashboard/TransfersCard.tsx
|
|
1523
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1524
|
+
function TransferList({ rows }) {
|
|
1525
|
+
if (rows.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-empty", children: "None" });
|
|
1526
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "ss-w-fandash-transfer-list", children: rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { className: "ss-w-fandash-transfer-row", children: [
|
|
1527
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-name", children: r.playerName }),
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-club", children: r.otherClub }),
|
|
1529
|
+
r.type ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-type", children: r.type }) : null
|
|
1530
|
+
] }, `${r.playerName}-${i}`)) });
|
|
1531
|
+
}
|
|
1532
|
+
function TransfersCard({ card }) {
|
|
1533
|
+
const { data } = card;
|
|
1534
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-transfers", children: [
|
|
1535
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-cols", children: [
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-col", children: [
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-col-head", children: "In" }),
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TransferList, { rows: data.in })
|
|
1540
|
+
] }),
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-col", children: [
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-col-head", children: "Out" }),
|
|
1543
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TransferList, { rows: data.out })
|
|
1544
|
+
] })
|
|
1545
|
+
] })
|
|
1546
|
+
] });
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// src/components/dashboard/LinksCard.tsx
|
|
1550
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1551
|
+
function LinksCard({ card }) {
|
|
1552
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-links", children: [
|
|
1553
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1554
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-fandash-link-grid", children: card.data.links.map((link, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("a", { className: "ss-w-fandash-link-tile", href: link.url, target: "_blank", rel: "noopener noreferrer", children: [
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-link-label", children: link.label }),
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-link-chevron", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChevronIcon, {}) })
|
|
1557
|
+
] }, `${link.url}-${i}`)) })
|
|
1558
|
+
] });
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
// src/components/dashboard/ClubFanDashboard.tsx
|
|
1562
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1563
|
+
function ClubFanDashboard({ dashboard, onTap, ui }) {
|
|
1564
|
+
const orderedCards = [
|
|
1565
|
+
...dashboard.cards.filter((c) => c.cardType === "countdown"),
|
|
1566
|
+
...dashboard.cards.filter((c) => c.cardType !== "countdown")
|
|
1567
|
+
];
|
|
1568
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "ss-w-fandash", children: [
|
|
1569
|
+
dashboard.greeting ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
|
|
1570
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
|
|
1571
|
+
] });
|
|
1572
|
+
}
|
|
1573
|
+
function FanDashboardCard({ card, onTap, ui }) {
|
|
1574
|
+
switch (card.cardType) {
|
|
1575
|
+
case "fixture":
|
|
1576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FixtureCard, { card, onTap });
|
|
1577
|
+
case "countdown":
|
|
1578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CountdownCard, { card });
|
|
1579
|
+
case "injuries":
|
|
1580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InjuriesCard, { card });
|
|
1581
|
+
case "reasonToBet":
|
|
1582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReasonToBetCard, { card });
|
|
1583
|
+
case "whereToWatch":
|
|
1584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(WhereToWatchCard, { card });
|
|
1585
|
+
case "congestedWeek":
|
|
1586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CongestedWeekCard, { card, onTap });
|
|
1587
|
+
case "transfers":
|
|
1588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TransfersCard, { card });
|
|
1589
|
+
case "links":
|
|
1590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LinksCard, { card });
|
|
1591
|
+
default:
|
|
1592
|
+
return null;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// src/components/ChatMessage.tsx
|
|
1597
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1329
1598
|
function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
|
|
1330
1599
|
if (message.role === "user") {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
1600
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1332
1601
|
}
|
|
1333
|
-
|
|
1334
|
-
message.
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1340
|
-
/* @__PURE__ */ (0,
|
|
1602
|
+
const onFanDashboardTap = (card) => {
|
|
1603
|
+
onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || "" });
|
|
1604
|
+
};
|
|
1605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1606
|
+
message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Markdown, { text: message.text }) : null,
|
|
1607
|
+
message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1608
|
+
message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
|
|
1609
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1610
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1341
1614
|
] });
|
|
1342
1615
|
}
|
|
1343
1616
|
|
|
1344
1617
|
// src/components/IntentChips.tsx
|
|
1345
|
-
var
|
|
1618
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1346
1619
|
function IntentChips({ chips, onPick }) {
|
|
1347
1620
|
if (chips.length === 0) return null;
|
|
1348
|
-
return /* @__PURE__ */ (0,
|
|
1621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1349
1622
|
}
|
|
1350
1623
|
|
|
1351
1624
|
// src/scroll.ts
|
|
@@ -1355,18 +1628,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1355
1628
|
}
|
|
1356
1629
|
|
|
1357
1630
|
// src/components/MessageList.tsx
|
|
1358
|
-
var
|
|
1631
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1359
1632
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1360
1633
|
const { state, send } = controller;
|
|
1361
|
-
const listRef = (0,
|
|
1362
|
-
const endRef = (0,
|
|
1363
|
-
const pinnedRef = (0,
|
|
1364
|
-
(0,
|
|
1634
|
+
const listRef = (0, import_react9.useRef)(null);
|
|
1635
|
+
const endRef = (0, import_react9.useRef)(null);
|
|
1636
|
+
const pinnedRef = (0, import_react9.useRef)(true);
|
|
1637
|
+
(0, import_react9.useEffect)(() => {
|
|
1365
1638
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
1366
1639
|
}, [state.messages, state.status]);
|
|
1367
1640
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1368
|
-
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1369
|
-
return /* @__PURE__ */ (0,
|
|
1641
|
+
const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
|
|
1642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1370
1643
|
"div",
|
|
1371
1644
|
{
|
|
1372
1645
|
className: "ss-w-list",
|
|
@@ -1376,12 +1649,12 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1376
1649
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1377
1650
|
},
|
|
1378
1651
|
children: [
|
|
1379
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
1652
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1380
1653
|
ChatMessage,
|
|
1381
1654
|
{
|
|
1382
1655
|
message: m,
|
|
1383
1656
|
disabled: state.isStreaming,
|
|
1384
|
-
onAct: (a) => send(a.message, { actionId: a.actionId, displayText: a.label }),
|
|
1657
|
+
onAct: (a) => send(a.message, { actionId: a.actionId, actionRef: a.actionRef, displayText: a.label }),
|
|
1385
1658
|
onTap: (tile, index) => {
|
|
1386
1659
|
send(tile.actionValue, { displayText: tile.title });
|
|
1387
1660
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
@@ -1391,25 +1664,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1391
1664
|
},
|
|
1392
1665
|
m.id
|
|
1393
1666
|
)),
|
|
1394
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
1667
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1395
1668
|
} }) : null,
|
|
1396
|
-
state.status ? /* @__PURE__ */ (0,
|
|
1397
|
-
state.error ? /* @__PURE__ */ (0,
|
|
1398
|
-
/* @__PURE__ */ (0,
|
|
1399
|
-
/* @__PURE__ */ (0,
|
|
1669
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1670
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1400
1673
|
] }) : null,
|
|
1401
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0,
|
|
1402
|
-
/* @__PURE__ */ (0,
|
|
1674
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { ref: endRef })
|
|
1403
1676
|
]
|
|
1404
1677
|
}
|
|
1405
1678
|
);
|
|
1406
1679
|
}
|
|
1407
1680
|
|
|
1408
1681
|
// src/components/ChatInput.tsx
|
|
1409
|
-
var
|
|
1410
|
-
var
|
|
1682
|
+
var import_react10 = require("react");
|
|
1683
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1411
1684
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1412
|
-
const [value, setValue] = (0,
|
|
1685
|
+
const [value, setValue] = (0, import_react10.useState)("");
|
|
1413
1686
|
const submit = () => {
|
|
1414
1687
|
const t = value.trim();
|
|
1415
1688
|
if (!t) return;
|
|
@@ -1422,18 +1695,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1422
1695
|
submit();
|
|
1423
1696
|
}
|
|
1424
1697
|
};
|
|
1425
|
-
return /* @__PURE__ */ (0,
|
|
1426
|
-
/* @__PURE__ */ (0,
|
|
1427
|
-
streaming ? /* @__PURE__ */ (0,
|
|
1698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "ss-w-input", children: [
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1700
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SendIcon, {}) })
|
|
1428
1701
|
] });
|
|
1429
1702
|
}
|
|
1430
1703
|
|
|
1431
1704
|
// src/components/ChatPanel.tsx
|
|
1432
|
-
var
|
|
1705
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1433
1706
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1434
1707
|
function useIsModal() {
|
|
1435
|
-
const [modal, setModal] = (0,
|
|
1436
|
-
(0,
|
|
1708
|
+
const [modal, setModal] = (0, import_react11.useState)(false);
|
|
1709
|
+
(0, import_react11.useEffect)(() => {
|
|
1437
1710
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1438
1711
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1439
1712
|
const sync = () => setModal(mql.matches);
|
|
@@ -1446,17 +1719,17 @@ function useIsModal() {
|
|
|
1446
1719
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
1447
1720
|
const { state, close, stop, send } = controller;
|
|
1448
1721
|
const isModal = useIsModal();
|
|
1449
|
-
(0,
|
|
1722
|
+
(0, import_react11.useEffect)(() => {
|
|
1450
1723
|
const onKey = (e) => {
|
|
1451
1724
|
if (e.key === "Escape") close();
|
|
1452
1725
|
};
|
|
1453
1726
|
window.addEventListener("keydown", onKey);
|
|
1454
1727
|
return () => window.removeEventListener("keydown", onKey);
|
|
1455
1728
|
}, [close]);
|
|
1456
|
-
return /* @__PURE__ */ (0,
|
|
1457
|
-
/* @__PURE__ */ (0,
|
|
1458
|
-
/* @__PURE__ */ (0,
|
|
1459
|
-
/* @__PURE__ */ (0,
|
|
1729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1730
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1731
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1732
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1460
1733
|
] });
|
|
1461
1734
|
}
|
|
1462
1735
|
|
|
@@ -1809,10 +2082,122 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1809
2082
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
|
|
1810
2083
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
|
|
1811
2084
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
|
|
2085
|
+
|
|
2086
|
+
/* club fan pre-match dashboard */
|
|
2087
|
+
.ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
|
|
2088
|
+
.ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }
|
|
2089
|
+
.ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }
|
|
2090
|
+
|
|
2091
|
+
/* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both
|
|
2092
|
+
share the same box so the two families read as one system, not two ad hoc layouts. */
|
|
2093
|
+
.ss-w-fandash-card {
|
|
2094
|
+
display: flex; flex-direction: column; gap: 8px;
|
|
2095
|
+
padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);
|
|
2096
|
+
background: var(--ss-w-panel); text-align: left;
|
|
2097
|
+
color: inherit; font: inherit; width: 100%; min-width: 0;
|
|
2098
|
+
}
|
|
2099
|
+
.ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }
|
|
2100
|
+
.ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }
|
|
2101
|
+
.ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2102
|
+
|
|
2103
|
+
/* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label
|
|
2104
|
+
split reused by the fixture head-to-head (and any future stat-row card). */
|
|
2105
|
+
.ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
|
|
2106
|
+
.ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
2107
|
+
.ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }
|
|
2108
|
+
.ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }
|
|
2109
|
+
.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; }
|
|
2110
|
+
|
|
2111
|
+
/* fixture card */
|
|
2112
|
+
.ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }
|
|
2113
|
+
.ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
|
|
2114
|
+
.ss-w-fandash-fixture-team--away { justify-content: flex-end; }
|
|
2115
|
+
.ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }
|
|
2116
|
+
.ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }
|
|
2117
|
+
.ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
|
|
2118
|
+
.ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }
|
|
2119
|
+
.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); }
|
|
2120
|
+
/* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */
|
|
2121
|
+
.ss-w-fandash-fixture-meta { display: flex; flex-direction: column; gap: 1px; border-top: 1px solid var(--ss-w-line); padding-top: 8px; }
|
|
2122
|
+
.ss-w-fandash-fixture-metarow { display: flex; align-items: baseline; gap: 9px; }
|
|
2123
|
+
.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); }
|
|
2124
|
+
.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); }
|
|
2125
|
+
.ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }
|
|
2126
|
+
/* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */
|
|
2127
|
+
.ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }
|
|
2128
|
+
/* extra breathing room between the tally row and the fact beyond the card's own gap */
|
|
2129
|
+
.ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }
|
|
2130
|
+
|
|
2131
|
+
/* last-five: one row per side, team name left, form pills right */
|
|
2132
|
+
.ss-w-fandash-fixture-form { display: flex; flex-direction: column; gap: 5px; }
|
|
2133
|
+
.ss-w-fandash-formrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
2134
|
+
.ss-w-fandash-formrow-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 600; }
|
|
2135
|
+
.ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }
|
|
2136
|
+
.ss-w-fandash-form-pill {
|
|
2137
|
+
display: inline-grid; place-items: center; width: 16px; height: 16px;
|
|
2138
|
+
border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;
|
|
2139
|
+
}
|
|
2140
|
+
.ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }
|
|
2141
|
+
.ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }
|
|
2142
|
+
.ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }
|
|
2143
|
+
|
|
2144
|
+
/* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each
|
|
2145
|
+
segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not
|
|
2146
|
+
repeated here; the fixture card below carries it. */
|
|
2147
|
+
.ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
2148
|
+
.ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }
|
|
2149
|
+
.ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }
|
|
2150
|
+
.ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }
|
|
2151
|
+
.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; }
|
|
2152
|
+
.ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }
|
|
2153
|
+
|
|
2154
|
+
/* injuries + transfers: two-column ours/theirs, in/out */
|
|
2155
|
+
.ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
|
|
2156
|
+
/* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */
|
|
2157
|
+
.ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }
|
|
2158
|
+
.ss-w-fandash-injuries-divider { background: var(--ss-w-line); }
|
|
2159
|
+
.ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
2160
|
+
.ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }
|
|
2161
|
+
.ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }
|
|
2162
|
+
.ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }
|
|
2163
|
+
.ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }
|
|
2164
|
+
.ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2165
|
+
.ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }
|
|
2166
|
+
.ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }
|
|
2167
|
+
.ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }
|
|
2168
|
+
.ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }
|
|
2169
|
+
.ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
2170
|
+
.ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }
|
|
2171
|
+
.ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }
|
|
2172
|
+
.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; }
|
|
2173
|
+
|
|
2174
|
+
/* reason-to-bet */
|
|
2175
|
+
.ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
|
|
2176
|
+
.ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }
|
|
2177
|
+
.ss-w-fandash-reason-item::before { content: "\u2022"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }
|
|
2178
|
+
|
|
2179
|
+
/* where-to-watch */
|
|
2180
|
+
.ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
2181
|
+
.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; }
|
|
2182
|
+
|
|
2183
|
+
/* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */
|
|
2184
|
+
.ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
2185
|
+
.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); }
|
|
2186
|
+
.ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
|
|
2187
|
+
.ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
|
|
2188
|
+
.ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
|
|
2189
|
+
.ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
|
|
2190
|
+
|
|
2191
|
+
/* links: 2-column grid of tappable tiles */
|
|
2192
|
+
.ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
2193
|
+
.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)); }
|
|
2194
|
+
.ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
|
|
2195
|
+
.ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
|
|
2196
|
+
.ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }
|
|
1812
2197
|
`;
|
|
1813
2198
|
|
|
1814
2199
|
// src/StatsWidget.tsx
|
|
1815
|
-
var
|
|
2200
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1816
2201
|
function buildClient(props) {
|
|
1817
2202
|
try {
|
|
1818
2203
|
if ("client" in props && props.client) {
|
|
@@ -1837,11 +2222,11 @@ function injectStyles(root) {
|
|
|
1837
2222
|
function StatsWidget(props) {
|
|
1838
2223
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
1839
2224
|
const cfg = props.config;
|
|
1840
|
-
const built = (0,
|
|
1841
|
-
const ui = (0,
|
|
1842
|
-
const rootRef = (0,
|
|
2225
|
+
const built = (0, import_react12.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
2226
|
+
const ui = (0, import_react12.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
2227
|
+
const rootRef = (0, import_react12.useRef)(null);
|
|
1843
2228
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
1844
|
-
const slip = (0,
|
|
2229
|
+
const slip = (0, import_react12.useMemo)(
|
|
1845
2230
|
() => ({
|
|
1846
2231
|
onAddToSlip: props.config?.onAddToSlip,
|
|
1847
2232
|
conversationId: controller.state.conversationId ?? void 0,
|
|
@@ -1854,18 +2239,18 @@ function StatsWidget(props) {
|
|
|
1854
2239
|
}),
|
|
1855
2240
|
[props.config?.onAddToSlip, controller.state.conversationId, built]
|
|
1856
2241
|
);
|
|
1857
|
-
const onDashboardTap = (0,
|
|
2242
|
+
const onDashboardTap = (0, import_react12.useMemo)(
|
|
1858
2243
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
1859
2244
|
[built]
|
|
1860
2245
|
);
|
|
1861
|
-
(0,
|
|
2246
|
+
(0, import_react12.useEffect)(() => {
|
|
1862
2247
|
if (!built || !ui.injectStyles) return;
|
|
1863
2248
|
const node = rootRef.current?.getRootNode();
|
|
1864
2249
|
if (node) injectStyles(node);
|
|
1865
2250
|
}, [built, ui.injectStyles]);
|
|
1866
2251
|
if (!built) return null;
|
|
1867
2252
|
const attrs = themeAttrs(ui);
|
|
1868
|
-
return /* @__PURE__ */ (0,
|
|
2253
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.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_runtime31.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1869
2254
|
ChatFab,
|
|
1870
2255
|
{
|
|
1871
2256
|
label: ui.launcherLabel,
|