@sensiblestats/widget-react 0.20.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 +22 -0
- package/dist/index.cjs +53 -302
- 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 -294
- package/dist/index.js.map +1 -1
- package/dist/styles.css +0 -39
- 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,218 +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/FormGuideBlock.tsx
|
|
1354
|
-
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1355
|
-
function FormGuideBlock({ block }) {
|
|
1356
|
-
if (block.rows.length === 0) return null;
|
|
1357
|
-
return /* @__PURE__ */ jsx19("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ jsxs15("div", { className: "ss-w-cdash-form-row", children: [
|
|
1358
|
-
/* @__PURE__ */ jsxs15("span", { className: "ss-w-cdash-form-name", children: [
|
|
1359
|
-
row.name,
|
|
1360
|
-
row.position != null ? ` #${row.position}` : ""
|
|
1361
|
-
] }),
|
|
1362
|
-
/* @__PURE__ */ jsx19("span", { className: "ss-w-cdash-form-pills", children: row.last5.map((r, i) => /* @__PURE__ */ jsx19("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) })
|
|
1363
|
-
] }, row.name)) });
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1367
|
-
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1368
|
-
function MatchPreviewBlock({
|
|
1369
|
-
block,
|
|
1370
|
-
ui,
|
|
1371
|
-
onAction
|
|
1372
|
-
}) {
|
|
1373
|
-
if (block.facts.length === 0) return null;
|
|
1374
|
-
const heading = ui.clubMatchPreviewHeading;
|
|
1375
|
-
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-cdash-lines", children: [
|
|
1376
|
-
/* @__PURE__ */ jsx20("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1377
|
-
block.facts.map(
|
|
1378
|
-
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs16(
|
|
1379
|
-
"button",
|
|
1380
|
-
{
|
|
1381
|
-
type: "button",
|
|
1382
|
-
className: "ss-w-cdash-fact",
|
|
1383
|
-
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1384
|
-
children: [
|
|
1385
|
-
f.sentence,
|
|
1386
|
-
f.label ? /* @__PURE__ */ jsxs16("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1387
|
-
" ",
|
|
1388
|
-
f.label
|
|
1389
|
-
] }) : null
|
|
1390
|
-
]
|
|
1391
|
-
},
|
|
1392
|
-
i
|
|
1393
|
-
) : /* @__PURE__ */ jsx20("p", { children: f.sentence }, i)
|
|
1394
|
-
)
|
|
1395
|
-
] });
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1399
|
-
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1400
|
-
function TeamDnaBlock({
|
|
1401
|
-
block,
|
|
1402
|
-
ui,
|
|
1403
|
-
onAction
|
|
1404
|
-
}) {
|
|
1405
|
-
if (block.facts.length === 0) return null;
|
|
1406
|
-
const heading = ui.clubTeamDnaHeading;
|
|
1407
|
-
return /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-lines", children: [
|
|
1408
|
-
/* @__PURE__ */ jsx21("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1409
|
-
block.facts.map(
|
|
1410
|
-
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs17(
|
|
1411
|
-
"button",
|
|
1412
|
-
{
|
|
1413
|
-
type: "button",
|
|
1414
|
-
className: "ss-w-cdash-fact",
|
|
1415
|
-
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1416
|
-
children: [
|
|
1417
|
-
f.sentence,
|
|
1418
|
-
f.label ? /* @__PURE__ */ jsxs17("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1419
|
-
" ",
|
|
1420
|
-
f.label
|
|
1421
|
-
] }) : null
|
|
1422
|
-
]
|
|
1423
|
-
},
|
|
1424
|
-
i
|
|
1425
|
-
) : /* @__PURE__ */ jsx21("p", { children: f.sentence }, i)
|
|
1426
|
-
)
|
|
1427
|
-
] });
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1431
|
-
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
1432
|
-
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1433
|
-
var DAY_MS = 24 * 3600 * 1e3;
|
|
1434
|
-
function pad2(n) {
|
|
1435
|
-
return String(n).padStart(2, "0");
|
|
1436
|
-
}
|
|
1437
|
-
function splitRemaining(remainingMs) {
|
|
1438
|
-
const totalSeconds = Math.max(0, Math.floor(remainingMs / 1e3));
|
|
1439
|
-
const h = Math.floor(totalSeconds / 3600);
|
|
1440
|
-
const m = Math.floor(totalSeconds % 3600 / 60);
|
|
1441
|
-
const s = totalSeconds % 60;
|
|
1442
|
-
return { h: pad2(h), m: pad2(m), s: pad2(s) };
|
|
1443
|
-
}
|
|
1444
|
-
function CountdownBlock({ block, ui }) {
|
|
1445
|
-
const [remainingMs, setRemainingMs] = useState7(() => block.kickoffUnix * 1e3 - Date.now());
|
|
1446
|
-
useEffect3(() => {
|
|
1447
|
-
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1448
|
-
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1449
|
-
const id = setInterval(() => {
|
|
1450
|
-
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1451
|
-
}, 1e3);
|
|
1452
|
-
return () => clearInterval(id);
|
|
1453
|
-
}, [block.kickoffUnix]);
|
|
1454
|
-
if (remainingMs <= 0) return null;
|
|
1455
|
-
if (remainingMs > DAY_MS) return null;
|
|
1456
|
-
const { h, m, s } = splitRemaining(remainingMs);
|
|
1457
|
-
return /* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
|
|
1458
|
-
/* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
|
|
1459
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-h", children: h }),
|
|
1460
|
-
"h",
|
|
1461
|
-
" ",
|
|
1462
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1463
|
-
"m",
|
|
1464
|
-
" ",
|
|
1465
|
-
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1466
|
-
"s"
|
|
1467
|
-
] }),
|
|
1468
|
-
/* @__PURE__ */ jsx22("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1469
|
-
] });
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1473
|
-
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1474
|
-
var CLUB_BLOCK_REGISTRY = {
|
|
1475
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ jsx23(GreetingHeaderBlock, { block }) : null,
|
|
1476
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ jsx23(FixtureHeroBlock, { block, ui, onAction }) : null,
|
|
1477
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ jsx23(FormGuideBlock, { block, ui }) : null,
|
|
1478
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ jsx23(MatchPreviewBlock, { block, ui, onAction }) : null,
|
|
1479
|
-
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ jsx23(TeamDnaBlock, { block, ui, onAction }) : null,
|
|
1480
|
-
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ jsx23(CountdownBlock, { block, ui }) : null
|
|
1481
|
-
};
|
|
1482
|
-
function ClubDashboard({
|
|
1483
|
-
dashboard,
|
|
1484
|
-
ui,
|
|
1485
|
-
onAction
|
|
1486
|
-
}) {
|
|
1487
|
-
if (!dashboard.blocks.length) return null;
|
|
1488
|
-
return /* @__PURE__ */ jsx23("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1489
|
-
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1490
|
-
if (!Comp) {
|
|
1491
|
-
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1492
|
-
return null;
|
|
1493
|
-
}
|
|
1494
|
-
return /* @__PURE__ */ jsx23("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ jsx23(Comp, { block, ui, onAction }) }, i);
|
|
1495
|
-
}) });
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
1290
|
// src/components/ChatMessage.tsx
|
|
1499
|
-
import { jsx as
|
|
1500
|
-
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 }) {
|
|
1501
1293
|
if (message.role === "user") {
|
|
1502
|
-
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 }) });
|
|
1503
1295
|
}
|
|
1504
|
-
return /* @__PURE__ */
|
|
1505
|
-
message.text && !message.greetingDashboard
|
|
1506
|
-
message.greetingDashboard ? /* @__PURE__ */
|
|
1507
|
-
|
|
1508
|
-
/* @__PURE__ */
|
|
1509
|
-
/* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */ jsx24(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 })
|
|
1513
1304
|
] });
|
|
1514
1305
|
}
|
|
1515
1306
|
|
|
1516
1307
|
// src/components/IntentChips.tsx
|
|
1517
|
-
import { jsx as
|
|
1308
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1518
1309
|
function IntentChips({ chips, onPick }) {
|
|
1519
1310
|
if (chips.length === 0) return null;
|
|
1520
|
-
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}`)) });
|
|
1521
1312
|
}
|
|
1522
1313
|
|
|
1523
1314
|
// src/scroll.ts
|
|
@@ -1527,18 +1318,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1527
1318
|
}
|
|
1528
1319
|
|
|
1529
1320
|
// src/components/MessageList.tsx
|
|
1530
|
-
import { jsx as
|
|
1321
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1531
1322
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1532
1323
|
const { state, send } = controller;
|
|
1533
1324
|
const listRef = useRef2(null);
|
|
1534
1325
|
const endRef = useRef2(null);
|
|
1535
1326
|
const pinnedRef = useRef2(true);
|
|
1536
|
-
|
|
1327
|
+
useEffect3(() => {
|
|
1537
1328
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
1538
1329
|
}, [state.messages, state.status]);
|
|
1539
1330
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1540
1331
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1541
|
-
return /* @__PURE__ */
|
|
1332
|
+
return /* @__PURE__ */ jsxs14(
|
|
1542
1333
|
"div",
|
|
1543
1334
|
{
|
|
1544
1335
|
className: "ss-w-list",
|
|
@@ -1548,7 +1339,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1548
1339
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1549
1340
|
},
|
|
1550
1341
|
children: [
|
|
1551
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
1342
|
+
state.messages.map((m) => /* @__PURE__ */ jsx19(
|
|
1552
1343
|
ChatMessage,
|
|
1553
1344
|
{
|
|
1554
1345
|
message: m,
|
|
@@ -1558,31 +1349,30 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1558
1349
|
send(tile.actionValue, { displayText: tile.title });
|
|
1559
1350
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1560
1351
|
},
|
|
1561
|
-
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1562
1352
|
ui,
|
|
1563
1353
|
slip
|
|
1564
1354
|
},
|
|
1565
1355
|
m.id
|
|
1566
1356
|
)),
|
|
1567
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
1357
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx19(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1568
1358
|
} }) : null,
|
|
1569
|
-
state.status ? /* @__PURE__ */
|
|
1570
|
-
state.error ? /* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
1572
|
-
/* @__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 })
|
|
1573
1363
|
] }) : null,
|
|
1574
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */
|
|
1575
|
-
/* @__PURE__ */
|
|
1364
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx19(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1365
|
+
/* @__PURE__ */ jsx19("div", { ref: endRef })
|
|
1576
1366
|
]
|
|
1577
1367
|
}
|
|
1578
1368
|
);
|
|
1579
1369
|
}
|
|
1580
1370
|
|
|
1581
1371
|
// src/components/ChatInput.tsx
|
|
1582
|
-
import { useState as
|
|
1583
|
-
import { jsx as
|
|
1372
|
+
import { useState as useState6 } from "react";
|
|
1373
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1584
1374
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1585
|
-
const [value, setValue] =
|
|
1375
|
+
const [value, setValue] = useState6("");
|
|
1586
1376
|
const submit = () => {
|
|
1587
1377
|
const t = value.trim();
|
|
1588
1378
|
if (!t) return;
|
|
@@ -1595,18 +1385,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1595
1385
|
submit();
|
|
1596
1386
|
}
|
|
1597
1387
|
};
|
|
1598
|
-
return /* @__PURE__ */
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
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, {}) })
|
|
1601
1391
|
] });
|
|
1602
1392
|
}
|
|
1603
1393
|
|
|
1604
1394
|
// src/components/ChatPanel.tsx
|
|
1605
|
-
import { jsx as
|
|
1395
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1606
1396
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1607
1397
|
function useIsModal() {
|
|
1608
|
-
const [modal, setModal] =
|
|
1609
|
-
|
|
1398
|
+
const [modal, setModal] = useState7(false);
|
|
1399
|
+
useEffect4(() => {
|
|
1610
1400
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1611
1401
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1612
1402
|
const sync = () => setModal(mql.matches);
|
|
@@ -1619,17 +1409,17 @@ function useIsModal() {
|
|
|
1619
1409
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
1620
1410
|
const { state, close, stop, send } = controller;
|
|
1621
1411
|
const isModal = useIsModal();
|
|
1622
|
-
|
|
1412
|
+
useEffect4(() => {
|
|
1623
1413
|
const onKey = (e) => {
|
|
1624
1414
|
if (e.key === "Escape") close();
|
|
1625
1415
|
};
|
|
1626
1416
|
window.addEventListener("keydown", onKey);
|
|
1627
1417
|
return () => window.removeEventListener("keydown", onKey);
|
|
1628
1418
|
}, [close]);
|
|
1629
|
-
return /* @__PURE__ */
|
|
1630
|
-
/* @__PURE__ */
|
|
1631
|
-
/* @__PURE__ */
|
|
1632
|
-
/* @__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 })
|
|
1633
1423
|
] });
|
|
1634
1424
|
}
|
|
1635
1425
|
|
|
@@ -1982,49 +1772,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1982
1772
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
|
|
1983
1773
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
|
|
1984
1774
|
.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
|
|
1985
|
-
|
|
1986
|
-
/* club match-day dashboard */
|
|
1987
|
-
.ss-w-cdash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
|
|
1988
|
-
.ss-w-cdash-block { display: flex; flex-direction: column; }
|
|
1989
|
-
|
|
1990
|
-
.ss-w-cdash-greeting { display: flex; flex-direction: column; gap: 2px; }
|
|
1991
|
-
.ss-w-cdash-greeting-title { font-weight: 700; font-size: 14px; color: var(--ss-w-ink); }
|
|
1992
|
-
.ss-w-cdash-greeting-subtitle { font-size: 11.5px; color: var(--ss-w-faint); }
|
|
1993
|
-
|
|
1994
|
-
.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; }
|
|
1995
|
-
.ss-w-cdash-tie { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
|
|
1996
|
-
.ss-w-cdash-team { font-weight: 650; font-size: 13px; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
|
|
1997
|
-
.ss-w-cdash-vs { font-size: 11px; color: var(--ss-w-faint); font-weight: 600; }
|
|
1998
|
-
.ss-w-cdash-crest { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; background: var(--ss-w-bubble); }
|
|
1999
|
-
.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)); }
|
|
2000
|
-
.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); }
|
|
2001
|
-
.ss-w-cdash-kickoff { font-weight: 700; color: var(--ss-w-ink); }
|
|
2002
|
-
.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; }
|
|
2003
|
-
|
|
2004
|
-
.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; }
|
|
2005
|
-
.ss-w-cdash-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
2006
|
-
.ss-w-cdash-form-name { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
|
|
2007
|
-
.ss-w-cdash-form-pills { flex: none; display: flex; align-items: center; gap: 3px; }
|
|
2008
|
-
.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; }
|
|
2009
|
-
.ss-w-cdash-pill--w { background: color-mix(in srgb, var(--ss-w-pos) 88%, black); }
|
|
2010
|
-
.ss-w-cdash-pill--d { background: var(--ss-w-faint); }
|
|
2011
|
-
.ss-w-cdash-pill--l { background: color-mix(in srgb, var(--ss-w-neg) 88%, black); }
|
|
2012
|
-
|
|
2013
|
-
.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; }
|
|
2014
|
-
.ss-w-cdash-lines-heading { font-size: 12px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2015
|
-
.ss-w-cdash-lines p { font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); margin: 0; }
|
|
2016
|
-
.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; }
|
|
2017
|
-
.ss-w-cdash-fact:hover, .ss-w-cdash-fact:focus-visible { color: var(--ss-w-accent); text-decoration: underline; }
|
|
2018
|
-
.ss-w-cdash-fact-label { font-size: 11px; font-weight: 700; color: var(--ss-w-accent); }
|
|
2019
|
-
|
|
2020
|
-
.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; }
|
|
2021
|
-
.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); }
|
|
2022
|
-
.ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
|
|
2023
|
-
.ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
|
|
2024
1775
|
`;
|
|
2025
1776
|
|
|
2026
1777
|
// src/StatsWidget.tsx
|
|
2027
|
-
import { jsx as
|
|
1778
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
2028
1779
|
function buildClient(props) {
|
|
2029
1780
|
try {
|
|
2030
1781
|
if ("client" in props && props.client) {
|
|
@@ -2070,14 +1821,14 @@ function StatsWidget(props) {
|
|
|
2070
1821
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
2071
1822
|
[built]
|
|
2072
1823
|
);
|
|
2073
|
-
|
|
1824
|
+
useEffect5(() => {
|
|
2074
1825
|
if (!built || !ui.injectStyles) return;
|
|
2075
1826
|
const node = rootRef.current?.getRootNode();
|
|
2076
1827
|
if (node) injectStyles(node);
|
|
2077
1828
|
}, [built, ui.injectStyles]);
|
|
2078
1829
|
if (!built) return null;
|
|
2079
1830
|
const attrs = themeAttrs(ui);
|
|
2080
|
-
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(
|
|
2081
1832
|
ChatFab,
|
|
2082
1833
|
{
|
|
2083
1834
|
label: ui.launcherLabel,
|