@sensiblestats/widget-react 0.21.0 → 0.22.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 +11 -0
- package/dist/index.cjs +53 -360
- 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 +45 -352
- package/dist/index.js.map +1 -1
- package/dist/styles.css +0 -56
- 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 useEffect5, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -55,12 +55,6 @@ var STRINGS = {
|
|
|
55
55
|
const drift = direction ? `, ${direction}` : "";
|
|
56
56
|
return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`;
|
|
57
57
|
},
|
|
58
|
-
clubMatchPreviewHeading: "Match preview",
|
|
59
|
-
clubTeamDnaHeading: "How they play",
|
|
60
|
-
clubFormHeading: "Recent form",
|
|
61
|
-
clubCountdownLabel: "Countdown to kick-off",
|
|
62
|
-
clubKickoff: (ms) => new Intl.DateTimeFormat("en-GB", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
|
|
63
|
-
clubKickoffAria: (ms) => `Kick-off ${new Intl.DateTimeFormat("en-GB", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
|
|
64
58
|
inSlip: "In slip",
|
|
65
59
|
slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
|
|
66
60
|
slipDuplicate: "Already in your slip",
|
|
@@ -112,12 +106,6 @@ var STRINGS = {
|
|
|
112
106
|
const drift = direction ? `, ${direction}` : "";
|
|
113
107
|
return `Son ${span} i\xE7indeki oran hareketi: ${opening} ile a\xE7\u0131ld\u0131, \u015Fu anda ${current}${drift}.`;
|
|
114
108
|
},
|
|
115
|
-
clubMatchPreviewHeading: "Ma\xE7 \xF6nizlemesi",
|
|
116
|
-
clubTeamDnaHeading: "Nas\u0131l oynuyorlar",
|
|
117
|
-
clubFormHeading: "Son form",
|
|
118
|
-
clubCountdownLabel: "Ba\u015Flama vuru\u015Funa kalan",
|
|
119
|
-
clubKickoff: (ms) => new Intl.DateTimeFormat("tr-TR", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
|
|
120
|
-
clubKickoffAria: (ms) => `Ba\u015Flama vuru\u015Fu ${new Intl.DateTimeFormat("tr-TR", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
|
|
121
109
|
inSlip: "Kuponda",
|
|
122
110
|
slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
|
|
123
111
|
slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
|
|
@@ -181,12 +169,6 @@ function normalizeUi(cfg) {
|
|
|
181
169
|
excludedSuspended: strings.excludedSuspended,
|
|
182
170
|
chartTimeLabel: strings.chartTimeLabel,
|
|
183
171
|
chartAria: strings.chartAria,
|
|
184
|
-
clubMatchPreviewHeading: strings.clubMatchPreviewHeading,
|
|
185
|
-
clubTeamDnaHeading: strings.clubTeamDnaHeading,
|
|
186
|
-
clubFormHeading: strings.clubFormHeading,
|
|
187
|
-
clubCountdownLabel: strings.clubCountdownLabel,
|
|
188
|
-
clubKickoff: strings.clubKickoff,
|
|
189
|
-
clubKickoffAria: strings.clubKickoffAria,
|
|
190
172
|
addToSlip: strings.addToSlip,
|
|
191
173
|
inSlip: strings.inSlip,
|
|
192
174
|
slipAdded: strings.slipAdded,
|
|
@@ -549,8 +531,7 @@ function applyEvent(state, event) {
|
|
|
549
531
|
messages: mapActive(state, (t) => ({
|
|
550
532
|
...t,
|
|
551
533
|
done: true,
|
|
552
|
-
greetingDashboard: event.data.dashboard ?? void 0
|
|
553
|
-
clubDashboard: event.data.clubDashboard ?? void 0
|
|
534
|
+
greetingDashboard: event.data.dashboard ?? void 0
|
|
554
535
|
}))
|
|
555
536
|
};
|
|
556
537
|
}
|
|
@@ -747,7 +728,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
747
728
|
}
|
|
748
729
|
|
|
749
730
|
// src/components/ChatPanel.tsx
|
|
750
|
-
import { useEffect as
|
|
731
|
+
import { useEffect as useEffect4, useState as useState7 } from "react";
|
|
751
732
|
|
|
752
733
|
// src/components/ChatHeader.tsx
|
|
753
734
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -760,7 +741,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
760
741
|
}
|
|
761
742
|
|
|
762
743
|
// src/components/MessageList.tsx
|
|
763
|
-
import { useEffect as
|
|
744
|
+
import { useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
764
745
|
|
|
765
746
|
// src/components/Markdown.tsx
|
|
766
747
|
import ReactMarkdown from "react-markdown";
|
|
@@ -1306,259 +1287,28 @@ function GreetingDashboard({ dashboard, onTap }) {
|
|
|
1306
1287
|
] });
|
|
1307
1288
|
}
|
|
1308
1289
|
|
|
1309
|
-
// src/components/club-dashboard/GreetingHeaderBlock.tsx
|
|
1310
|
-
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1311
|
-
function GreetingHeaderBlock({ block }) {
|
|
1312
|
-
return /* @__PURE__ */ jsxs13("div", { className: "ss-w-cdash-greeting", children: [
|
|
1313
|
-
/* @__PURE__ */ jsx17("div", { className: "ss-w-cdash-greeting-title", children: block.title }),
|
|
1314
|
-
/* @__PURE__ */ jsx17("div", { className: "ss-w-cdash-greeting-subtitle", children: block.subtitle })
|
|
1315
|
-
] });
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
// src/components/club-dashboard/FixtureHeroBlock.tsx
|
|
1319
|
-
import { useState as useState6 } from "react";
|
|
1320
|
-
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1321
|
-
function initials3(name) {
|
|
1322
|
-
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
|
|
1323
|
-
}
|
|
1324
|
-
function Crest3({ url, name }) {
|
|
1325
|
-
const [broken, setBroken] = useState6(false);
|
|
1326
|
-
if (!url || broken) {
|
|
1327
|
-
return /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials3(name) });
|
|
1328
|
-
}
|
|
1329
|
-
return /* @__PURE__ */ jsx18("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
|
|
1330
|
-
}
|
|
1331
|
-
function FixtureHeroBlock({
|
|
1332
|
-
block,
|
|
1333
|
-
ui,
|
|
1334
|
-
onAction
|
|
1335
|
-
}) {
|
|
1336
|
-
return /* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture", children: [
|
|
1337
|
-
/* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-tie", children: [
|
|
1338
|
-
/* @__PURE__ */ jsx18(Crest3, { url: block.homeCrestUrl, name: block.homeName }),
|
|
1339
|
-
/* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-team", children: block.homeName }),
|
|
1340
|
-
/* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-vs", children: "v" }),
|
|
1341
|
-
/* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-team", children: block.awayName }),
|
|
1342
|
-
/* @__PURE__ */ jsx18(Crest3, { url: block.awayCrestUrl, name: block.awayName })
|
|
1343
|
-
] }),
|
|
1344
|
-
/* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture-meta", children: [
|
|
1345
|
-
/* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-kickoff", children: ui.clubKickoff(block.kickoffUnix * 1e3) }),
|
|
1346
|
-
block.venue ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
|
|
1347
|
-
block.competition ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
|
|
1348
|
-
] }),
|
|
1349
|
-
/* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
|
|
1350
|
-
] });
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
// src/components/club-dashboard/ResultPills.tsx
|
|
1354
|
-
import { Fragment as Fragment5, jsx as jsx19 } from "react/jsx-runtime";
|
|
1355
|
-
function ResultPills({ results }) {
|
|
1356
|
-
return /* @__PURE__ */ jsx19(Fragment5, { children: results.map((r, i) => /* @__PURE__ */ jsx19("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) });
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
|
-
// src/components/club-dashboard/FormGuideBlock.tsx
|
|
1360
|
-
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1361
|
-
function FormGuideBlock({ block }) {
|
|
1362
|
-
if (block.rows.length === 0) return null;
|
|
1363
|
-
return /* @__PURE__ */ jsx20("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ jsxs15("div", { className: "ss-w-cdash-form-row", children: [
|
|
1364
|
-
/* @__PURE__ */ jsxs15("span", { className: "ss-w-cdash-form-name", children: [
|
|
1365
|
-
row.name,
|
|
1366
|
-
row.position != null ? ` #${row.position}` : ""
|
|
1367
|
-
] }),
|
|
1368
|
-
/* @__PURE__ */ jsx20("span", { className: "ss-w-cdash-form-pills", children: /* @__PURE__ */ jsx20(ResultPills, { results: row.last5 }) })
|
|
1369
|
-
] }, row.name)) });
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1373
|
-
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1374
|
-
function MatchPreviewBlock({
|
|
1375
|
-
block,
|
|
1376
|
-
ui,
|
|
1377
|
-
onAction
|
|
1378
|
-
}) {
|
|
1379
|
-
if (block.facts.length === 0) return null;
|
|
1380
|
-
const heading = ui.clubMatchPreviewHeading;
|
|
1381
|
-
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-cdash-lines", children: [
|
|
1382
|
-
/* @__PURE__ */ jsx21("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1383
|
-
block.facts.map(
|
|
1384
|
-
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs16(
|
|
1385
|
-
"button",
|
|
1386
|
-
{
|
|
1387
|
-
type: "button",
|
|
1388
|
-
className: "ss-w-cdash-fact",
|
|
1389
|
-
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1390
|
-
children: [
|
|
1391
|
-
f.sentence,
|
|
1392
|
-
f.label ? /* @__PURE__ */ jsxs16("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1393
|
-
" ",
|
|
1394
|
-
f.label
|
|
1395
|
-
] }) : null
|
|
1396
|
-
]
|
|
1397
|
-
},
|
|
1398
|
-
i
|
|
1399
|
-
) : /* @__PURE__ */ jsx21("p", { children: f.sentence }, i)
|
|
1400
|
-
)
|
|
1401
|
-
] });
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
// src/components/club-dashboard/MatchPreviewCardBlock.tsx
|
|
1405
|
-
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1406
|
-
function position(p) {
|
|
1407
|
-
return p != null ? `#${p}` : "\u2014";
|
|
1408
|
-
}
|
|
1409
|
-
function MatchPreviewCardBlock({ block }) {
|
|
1410
|
-
return /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview", children: [
|
|
1411
|
-
/* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-header", children: [
|
|
1412
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-team", children: block.homeName }),
|
|
1413
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-vs", children: "v" }),
|
|
1414
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-team", children: block.awayName })
|
|
1415
|
-
] }),
|
|
1416
|
-
/* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-row", children: [
|
|
1417
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-value", children: position(block.homePosition) }),
|
|
1418
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-label", children: block.tableLabel }),
|
|
1419
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-value", children: position(block.awayPosition) })
|
|
1420
|
-
] }),
|
|
1421
|
-
/* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-row", children: [
|
|
1422
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ jsx22(ResultPills, { results: block.homeLast5 }) }),
|
|
1423
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-label", children: block.last5Label }),
|
|
1424
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ jsx22(ResultPills, { results: block.awayLast5 }) })
|
|
1425
|
-
] }),
|
|
1426
|
-
block.edgeTeamName ? /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-edge", children: [
|
|
1427
|
-
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u25B8" }),
|
|
1428
|
-
/* @__PURE__ */ jsx22("strong", { children: block.edgeTeamName }),
|
|
1429
|
-
block.edgeReason ? /* @__PURE__ */ jsxs17("span", { children: [
|
|
1430
|
-
" \u2014 ",
|
|
1431
|
-
block.edgeReason
|
|
1432
|
-
] }) : null
|
|
1433
|
-
] }) : null,
|
|
1434
|
-
block.h2HLines.length > 0 ? /* @__PURE__ */ jsx22("div", { className: "ss-w-cdash-preview-h2h", children: block.h2HLines.map((line, i) => /* @__PURE__ */ jsx22("p", { children: line }, i)) }) : null
|
|
1435
|
-
] });
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1439
|
-
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1440
|
-
function TeamDnaBlock({
|
|
1441
|
-
block,
|
|
1442
|
-
ui,
|
|
1443
|
-
onAction
|
|
1444
|
-
}) {
|
|
1445
|
-
if (block.facts.length === 0) return null;
|
|
1446
|
-
const heading = ui.clubTeamDnaHeading;
|
|
1447
|
-
return /* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-lines", children: [
|
|
1448
|
-
/* @__PURE__ */ jsx23("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1449
|
-
block.facts.map(
|
|
1450
|
-
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs18(
|
|
1451
|
-
"button",
|
|
1452
|
-
{
|
|
1453
|
-
type: "button",
|
|
1454
|
-
className: "ss-w-cdash-fact",
|
|
1455
|
-
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1456
|
-
children: [
|
|
1457
|
-
f.sentence,
|
|
1458
|
-
f.label ? /* @__PURE__ */ jsxs18("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1459
|
-
" ",
|
|
1460
|
-
f.label
|
|
1461
|
-
] }) : null
|
|
1462
|
-
]
|
|
1463
|
-
},
|
|
1464
|
-
i
|
|
1465
|
-
) : /* @__PURE__ */ jsx23("p", { children: f.sentence }, i)
|
|
1466
|
-
)
|
|
1467
|
-
] });
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1471
|
-
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
1472
|
-
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1473
|
-
var DAY_MS = 24 * 3600 * 1e3;
|
|
1474
|
-
function pad2(n) {
|
|
1475
|
-
return String(n).padStart(2, "0");
|
|
1476
|
-
}
|
|
1477
|
-
function splitRemaining(remainingMs) {
|
|
1478
|
-
const totalSeconds = Math.max(0, Math.floor(remainingMs / 1e3));
|
|
1479
|
-
const h = Math.floor(totalSeconds / 3600);
|
|
1480
|
-
const m = Math.floor(totalSeconds % 3600 / 60);
|
|
1481
|
-
const s = totalSeconds % 60;
|
|
1482
|
-
return { h: pad2(h), m: pad2(m), s: pad2(s) };
|
|
1483
|
-
}
|
|
1484
|
-
function CountdownBlock({ block, ui }) {
|
|
1485
|
-
const [remainingMs, setRemainingMs] = useState7(() => block.kickoffUnix * 1e3 - Date.now());
|
|
1486
|
-
useEffect3(() => {
|
|
1487
|
-
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1488
|
-
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1489
|
-
const id = setInterval(() => {
|
|
1490
|
-
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1491
|
-
}, 1e3);
|
|
1492
|
-
return () => clearInterval(id);
|
|
1493
|
-
}, [block.kickoffUnix]);
|
|
1494
|
-
if (remainingMs <= 0) return null;
|
|
1495
|
-
if (remainingMs > DAY_MS) return null;
|
|
1496
|
-
const { h, m, s } = splitRemaining(remainingMs);
|
|
1497
|
-
return /* @__PURE__ */ jsxs19("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
|
|
1498
|
-
/* @__PURE__ */ jsxs19("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
|
|
1499
|
-
/* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-h", children: h }),
|
|
1500
|
-
"h",
|
|
1501
|
-
" ",
|
|
1502
|
-
/* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1503
|
-
"m",
|
|
1504
|
-
" ",
|
|
1505
|
-
/* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1506
|
-
"s"
|
|
1507
|
-
] }),
|
|
1508
|
-
/* @__PURE__ */ jsx24("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1509
|
-
] });
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1513
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1514
|
-
var CLUB_BLOCK_REGISTRY = {
|
|
1515
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ jsx25(GreetingHeaderBlock, { block }) : null,
|
|
1516
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ jsx25(FixtureHeroBlock, { block, ui, onAction }) : null,
|
|
1517
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ jsx25(FormGuideBlock, { block, ui }) : null,
|
|
1518
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ jsx25(MatchPreviewBlock, { block, ui, onAction }) : null,
|
|
1519
|
-
matchPreviewCard: ({ block, ui }) => block.type === "matchPreviewCard" ? /* @__PURE__ */ jsx25(MatchPreviewCardBlock, { block, ui }) : null,
|
|
1520
|
-
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ jsx25(TeamDnaBlock, { block, ui, onAction }) : null,
|
|
1521
|
-
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ jsx25(CountdownBlock, { block, ui }) : null
|
|
1522
|
-
};
|
|
1523
|
-
function ClubDashboard({
|
|
1524
|
-
dashboard,
|
|
1525
|
-
ui,
|
|
1526
|
-
onAction
|
|
1527
|
-
}) {
|
|
1528
|
-
if (!dashboard.blocks.length) return null;
|
|
1529
|
-
return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1530
|
-
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1531
|
-
if (!Comp) {
|
|
1532
|
-
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1533
|
-
return null;
|
|
1534
|
-
}
|
|
1535
|
-
return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ jsx25(Comp, { block, ui, onAction }) }, i);
|
|
1536
|
-
}) });
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
1290
|
// src/components/ChatMessage.tsx
|
|
1540
|
-
import { jsx as
|
|
1541
|
-
function ChatMessage({ message, disabled, onAct, onTap,
|
|
1291
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1292
|
+
function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
|
|
1542
1293
|
if (message.role === "user") {
|
|
1543
|
-
return /* @__PURE__ */
|
|
1294
|
+
return /* @__PURE__ */ jsx17("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx17("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1544
1295
|
}
|
|
1545
|
-
return /* @__PURE__ */
|
|
1546
|
-
message.text && !message.greetingDashboard
|
|
1547
|
-
message.greetingDashboard ? /* @__PURE__ */
|
|
1548
|
-
|
|
1549
|
-
/* @__PURE__ */
|
|
1550
|
-
/* @__PURE__ */
|
|
1551
|
-
/* @__PURE__ */
|
|
1552
|
-
/* @__PURE__ */
|
|
1553
|
-
/* @__PURE__ */ jsx26(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1296
|
+
return /* @__PURE__ */ jsxs13("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1297
|
+
message.text && !message.greetingDashboard ? /* @__PURE__ */ jsx17(Markdown, { text: message.text }) : null,
|
|
1298
|
+
message.greetingDashboard ? /* @__PURE__ */ jsx17(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1299
|
+
/* @__PURE__ */ jsx17(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1300
|
+
/* @__PURE__ */ jsx17(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1301
|
+
/* @__PURE__ */ jsx17(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1302
|
+
/* @__PURE__ */ jsx17(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1303
|
+
/* @__PURE__ */ jsx17(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1554
1304
|
] });
|
|
1555
1305
|
}
|
|
1556
1306
|
|
|
1557
1307
|
// src/components/IntentChips.tsx
|
|
1558
|
-
import { jsx as
|
|
1308
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1559
1309
|
function IntentChips({ chips, onPick }) {
|
|
1560
1310
|
if (chips.length === 0) return null;
|
|
1561
|
-
return /* @__PURE__ */
|
|
1311
|
+
return /* @__PURE__ */ jsx18("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1562
1312
|
}
|
|
1563
1313
|
|
|
1564
1314
|
// src/scroll.ts
|
|
@@ -1568,18 +1318,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1568
1318
|
}
|
|
1569
1319
|
|
|
1570
1320
|
// src/components/MessageList.tsx
|
|
1571
|
-
import { jsx as
|
|
1321
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1572
1322
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1573
1323
|
const { state, send } = controller;
|
|
1574
1324
|
const listRef = useRef2(null);
|
|
1575
1325
|
const endRef = useRef2(null);
|
|
1576
1326
|
const pinnedRef = useRef2(true);
|
|
1577
|
-
|
|
1327
|
+
useEffect3(() => {
|
|
1578
1328
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
1579
1329
|
}, [state.messages, state.status]);
|
|
1580
1330
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1581
1331
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1582
|
-
return /* @__PURE__ */
|
|
1332
|
+
return /* @__PURE__ */ jsxs14(
|
|
1583
1333
|
"div",
|
|
1584
1334
|
{
|
|
1585
1335
|
className: "ss-w-list",
|
|
@@ -1589,7 +1339,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1589
1339
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1590
1340
|
},
|
|
1591
1341
|
children: [
|
|
1592
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
1342
|
+
state.messages.map((m) => /* @__PURE__ */ jsx19(
|
|
1593
1343
|
ChatMessage,
|
|
1594
1344
|
{
|
|
1595
1345
|
message: m,
|
|
@@ -1599,31 +1349,30 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1599
1349
|
send(tile.actionValue, { displayText: tile.title });
|
|
1600
1350
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1601
1351
|
},
|
|
1602
|
-
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1603
1352
|
ui,
|
|
1604
1353
|
slip
|
|
1605
1354
|
},
|
|
1606
1355
|
m.id
|
|
1607
1356
|
)),
|
|
1608
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
1357
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx19(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1609
1358
|
} }) : null,
|
|
1610
|
-
state.status ? /* @__PURE__ */
|
|
1611
|
-
state.error ? /* @__PURE__ */
|
|
1612
|
-
/* @__PURE__ */
|
|
1613
|
-
/* @__PURE__ */
|
|
1359
|
+
state.status ? /* @__PURE__ */ jsx19("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1360
|
+
state.error ? /* @__PURE__ */ jsxs14("div", { className: "ss-w-error", role: "alert", children: [
|
|
1361
|
+
/* @__PURE__ */ jsx19("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1362
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1614
1363
|
] }) : null,
|
|
1615
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */
|
|
1616
|
-
/* @__PURE__ */
|
|
1364
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx19(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1365
|
+
/* @__PURE__ */ jsx19("div", { ref: endRef })
|
|
1617
1366
|
]
|
|
1618
1367
|
}
|
|
1619
1368
|
);
|
|
1620
1369
|
}
|
|
1621
1370
|
|
|
1622
1371
|
// src/components/ChatInput.tsx
|
|
1623
|
-
import { useState as
|
|
1624
|
-
import { jsx as
|
|
1372
|
+
import { useState as useState6 } from "react";
|
|
1373
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1625
1374
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1626
|
-
const [value, setValue] =
|
|
1375
|
+
const [value, setValue] = useState6("");
|
|
1627
1376
|
const submit = () => {
|
|
1628
1377
|
const t = value.trim();
|
|
1629
1378
|
if (!t) return;
|
|
@@ -1636,18 +1385,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1636
1385
|
submit();
|
|
1637
1386
|
}
|
|
1638
1387
|
};
|
|
1639
|
-
return /* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
streaming ? /* @__PURE__ */
|
|
1388
|
+
return /* @__PURE__ */ jsxs15("div", { className: "ss-w-input", children: [
|
|
1389
|
+
/* @__PURE__ */ jsx20("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1390
|
+
streaming ? /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx20("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx20(SendIcon, {}) })
|
|
1642
1391
|
] });
|
|
1643
1392
|
}
|
|
1644
1393
|
|
|
1645
1394
|
// src/components/ChatPanel.tsx
|
|
1646
|
-
import { jsx as
|
|
1395
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1647
1396
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1648
1397
|
function useIsModal() {
|
|
1649
|
-
const [modal, setModal] =
|
|
1650
|
-
|
|
1398
|
+
const [modal, setModal] = useState7(false);
|
|
1399
|
+
useEffect4(() => {
|
|
1651
1400
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1652
1401
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1653
1402
|
const sync = () => setModal(mql.matches);
|
|
@@ -1660,17 +1409,17 @@ function useIsModal() {
|
|
|
1660
1409
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
1661
1410
|
const { state, close, stop, send } = controller;
|
|
1662
1411
|
const isModal = useIsModal();
|
|
1663
|
-
|
|
1412
|
+
useEffect4(() => {
|
|
1664
1413
|
const onKey = (e) => {
|
|
1665
1414
|
if (e.key === "Escape") close();
|
|
1666
1415
|
};
|
|
1667
1416
|
window.addEventListener("keydown", onKey);
|
|
1668
1417
|
return () => window.removeEventListener("keydown", onKey);
|
|
1669
1418
|
}, [close]);
|
|
1670
|
-
return /* @__PURE__ */
|
|
1671
|
-
/* @__PURE__ */
|
|
1672
|
-
/* @__PURE__ */
|
|
1673
|
-
/* @__PURE__ */
|
|
1419
|
+
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1420
|
+
/* @__PURE__ */ jsx21(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1421
|
+
/* @__PURE__ */ jsx21(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1422
|
+
/* @__PURE__ */ jsx21(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1674
1423
|
] });
|
|
1675
1424
|
}
|
|
1676
1425
|
|
|
@@ -2023,66 +1772,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2023
1772
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
|
|
2024
1773
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
|
|
2025
1774
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
|
|
2026
|
-
|
|
2027
|
-
/* club match-day dashboard */
|
|
2028
|
-
.ss-w-cdash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
|
|
2029
|
-
.ss-w-cdash-block { display: flex; flex-direction: column; }
|
|
2030
|
-
|
|
2031
|
-
.ss-w-cdash-greeting { display: flex; flex-direction: column; gap: 2px; }
|
|
2032
|
-
.ss-w-cdash-greeting-title { font-weight: 700; font-size: 14px; color: var(--ss-w-ink); }
|
|
2033
|
-
.ss-w-cdash-greeting-subtitle { font-size: 11.5px; color: var(--ss-w-faint); }
|
|
2034
|
-
|
|
2035
|
-
.ss-w-cdash-fixture { display: flex; flex-direction: column; align-items: center; gap: 8px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 12px; text-align: center; }
|
|
2036
|
-
.ss-w-cdash-tie { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
|
|
2037
|
-
.ss-w-cdash-team { font-weight: 650; font-size: 13px; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
|
|
2038
|
-
.ss-w-cdash-vs { font-size: 11px; color: var(--ss-w-faint); font-weight: 600; }
|
|
2039
|
-
.ss-w-cdash-crest { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; background: var(--ss-w-bubble); }
|
|
2040
|
-
.ss-w-cdash-crest--fallback { display: grid; place-items: center; font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
|
|
2041
|
-
.ss-w-cdash-fixture-meta { display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--ss-w-faint); }
|
|
2042
|
-
.ss-w-cdash-kickoff { font-weight: 700; color: var(--ss-w-ink); }
|
|
2043
|
-
.ss-w-cdash-cta { font: inherit; font-weight: 700; font-size: 12px; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border: none; border-radius: 999px; padding: 8px 18px; cursor: pointer; }
|
|
2044
|
-
|
|
2045
|
-
.ss-w-cdash-form { display: flex; flex-direction: column; gap: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; }
|
|
2046
|
-
.ss-w-cdash-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
2047
|
-
.ss-w-cdash-form-name { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
|
|
2048
|
-
.ss-w-cdash-form-pills { flex: none; display: flex; align-items: center; gap: 3px; }
|
|
2049
|
-
.ss-w-cdash-pill { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; font-size: 9.5px; font-weight: 700; color: #fff; }
|
|
2050
|
-
.ss-w-cdash-pill--w { background: color-mix(in srgb, var(--ss-w-pos) 88%, black); }
|
|
2051
|
-
.ss-w-cdash-pill--d { background: var(--ss-w-faint); }
|
|
2052
|
-
.ss-w-cdash-pill--l { background: color-mix(in srgb, var(--ss-w-neg) 88%, black); }
|
|
2053
|
-
|
|
2054
|
-
.ss-w-cdash-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: 100%; text-align: left; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-left: 3px solid var(--ss-w-accent); border-radius: 12px; padding: 10px 12px; }
|
|
2055
|
-
.ss-w-cdash-lines-heading { font-size: 12px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2056
|
-
.ss-w-cdash-lines p { font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); margin: 0; }
|
|
2057
|
-
.ss-w-cdash-fact { display: block; width: 100%; text-align: left; font: inherit; font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); background: none; border: none; padding: 0; cursor: pointer; }
|
|
2058
|
-
.ss-w-cdash-fact:hover, .ss-w-cdash-fact:focus-visible { color: var(--ss-w-accent); text-decoration: underline; }
|
|
2059
|
-
.ss-w-cdash-fact-label { font-size: 11px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2060
|
-
|
|
2061
|
-
.ss-w-cdash-cd { display: flex; flex-direction: column; align-items: center; gap: 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; text-align: center; }
|
|
2062
|
-
.ss-w-cdash-cd-clock { display: flex; align-items: baseline; justify-content: center; gap: 2px; font-variant-numeric: tabular-nums; font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-weight: 700; font-size: 18px; color: var(--ss-w-ink); }
|
|
2063
|
-
.ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
|
|
2064
|
-
.ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
|
|
2065
|
-
|
|
2066
|
-
.ss-w-cdash-preview { display: flex; flex-direction: column; gap: 8px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; }
|
|
2067
|
-
.ss-w-cdash-preview-header { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 6px; }
|
|
2068
|
-
.ss-w-cdash-preview-header .ss-w-cdash-team:first-child { justify-self: start; text-align: left; }
|
|
2069
|
-
.ss-w-cdash-preview-header .ss-w-cdash-team:last-child { justify-self: end; text-align: right; }
|
|
2070
|
-
.ss-w-cdash-preview-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 6px; }
|
|
2071
|
-
.ss-w-cdash-preview-label { font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); text-align: center; text-transform: uppercase; letter-spacing: 0.03em; }
|
|
2072
|
-
.ss-w-cdash-preview-value { font-size: 12px; font-weight: 700; color: var(--ss-w-ink); text-align: center; }
|
|
2073
|
-
.ss-w-cdash-preview-pills { display: flex; align-items: center; justify-content: center; gap: 3px; }
|
|
2074
|
-
.ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value { justify-self: start; }
|
|
2075
|
-
.ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value:last-child { justify-self: end; }
|
|
2076
|
-
.ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:first-child { justify-self: start; }
|
|
2077
|
-
.ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:last-child { justify-self: end; }
|
|
2078
|
-
.ss-w-cdash-preview-edge { display: flex; align-items: baseline; gap: 4px; font-size: 12px; line-height: 1.4; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, transparent); border-radius: 8px; padding: 6px 8px; }
|
|
2079
|
-
.ss-w-cdash-preview-edge strong { color: var(--ss-w-ink); }
|
|
2080
|
-
.ss-w-cdash-preview-h2h { display: flex; flex-direction: column; gap: 2px; }
|
|
2081
|
-
.ss-w-cdash-preview-h2h p { font-size: 11.5px; line-height: 1.4; color: var(--ss-w-faint); margin: 0; }
|
|
2082
1775
|
`;
|
|
2083
1776
|
|
|
2084
1777
|
// src/StatsWidget.tsx
|
|
2085
|
-
import { jsx as
|
|
1778
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
2086
1779
|
function buildClient(props) {
|
|
2087
1780
|
try {
|
|
2088
1781
|
if ("client" in props && props.client) {
|
|
@@ -2128,14 +1821,14 @@ function StatsWidget(props) {
|
|
|
2128
1821
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
2129
1822
|
[built]
|
|
2130
1823
|
);
|
|
2131
|
-
|
|
1824
|
+
useEffect5(() => {
|
|
2132
1825
|
if (!built || !ui.injectStyles) return;
|
|
2133
1826
|
const node = rootRef.current?.getRootNode();
|
|
2134
1827
|
if (node) injectStyles(node);
|
|
2135
1828
|
}, [built, ui.injectStyles]);
|
|
2136
1829
|
if (!built) return null;
|
|
2137
1830
|
const attrs = themeAttrs(ui);
|
|
2138
|
-
return /* @__PURE__ */
|
|
1831
|
+
return /* @__PURE__ */ jsx22("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__ */ jsx22(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx22(
|
|
2139
1832
|
ChatFab,
|
|
2140
1833
|
{
|
|
2141
1834
|
label: ui.launcherLabel,
|