@sensiblestats/widget-react 0.18.0 → 0.19.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 +6 -0
- package/dist/index.cjs +308 -275
- 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 +249 -216
- package/dist/index.js.map +1 -1
- package/dist/styles.css +24 -22
- package/package.json +1 -1
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_react13 = require("react");
|
|
40
40
|
var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/kickoff.ts
|
|
@@ -472,7 +472,13 @@ function toMarketOddsVM(card) {
|
|
|
472
472
|
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
473
473
|
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
474
474
|
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
475
|
+
homeTeamName: home,
|
|
476
|
+
awayTeamName: away,
|
|
477
|
+
homeCrest: str(card.homeTeamImagePath),
|
|
478
|
+
awayCrest: str(card.awayTeamImagePath),
|
|
479
|
+
competitionCrest: str(card.competitionImagePath),
|
|
475
480
|
competition: str(card.competitionName),
|
|
481
|
+
kickoffUtc: str(card.kickoffUtc),
|
|
476
482
|
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
477
483
|
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
478
484
|
isLive: rows.some((r) => r.isLive === true),
|
|
@@ -748,7 +754,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
748
754
|
}
|
|
749
755
|
|
|
750
756
|
// src/components/ChatPanel.tsx
|
|
751
|
-
var
|
|
757
|
+
var import_react12 = require("react");
|
|
752
758
|
|
|
753
759
|
// src/components/ChatHeader.tsx
|
|
754
760
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -761,7 +767,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
761
767
|
}
|
|
762
768
|
|
|
763
769
|
// src/components/MessageList.tsx
|
|
764
|
-
var
|
|
770
|
+
var import_react10 = require("react");
|
|
765
771
|
|
|
766
772
|
// src/components/Markdown.tsx
|
|
767
773
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -881,7 +887,7 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
881
887
|
}
|
|
882
888
|
|
|
883
889
|
// src/components/BettingInsightList.tsx
|
|
884
|
-
var
|
|
890
|
+
var import_react6 = require("react");
|
|
885
891
|
|
|
886
892
|
// src/components/AddToSlipButton.tsx
|
|
887
893
|
var import_react4 = require("react");
|
|
@@ -1004,53 +1010,64 @@ function OddsMovementBadge({
|
|
|
1004
1010
|
] });
|
|
1005
1011
|
}
|
|
1006
1012
|
|
|
1007
|
-
// src/components/
|
|
1013
|
+
// src/components/Crest.tsx
|
|
1014
|
+
var import_react5 = require("react");
|
|
1008
1015
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1016
|
+
function initials2(name) {
|
|
1017
|
+
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1018
|
+
}
|
|
1019
|
+
function Crest2({ url, name, kind }) {
|
|
1020
|
+
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1021
|
+
const [failed, setFailed] = (0, import_react5.useState)(false);
|
|
1022
|
+
if (url && !failed) {
|
|
1023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1024
|
+
}
|
|
1025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `${cls} ss-w-bi-crest-mono`, "aria-hidden": "true", children: initials2(name) });
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// src/components/BettingInsightList.tsx
|
|
1029
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1009
1030
|
function StatRows2({ stats }) {
|
|
1010
|
-
return /* @__PURE__ */ (0,
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1012
|
-
/* @__PURE__ */ (0,
|
|
1031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-rows", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-row", children: [
|
|
1032
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
1013
1034
|
] }, `${s.label}:${s.value}`)) });
|
|
1014
1035
|
}
|
|
1015
1036
|
function ScopedStats({ scopes }) {
|
|
1016
|
-
const [active, setActive] = (0,
|
|
1037
|
+
const [active, setActive] = (0, import_react6.useState)(0);
|
|
1017
1038
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
1018
|
-
return /* @__PURE__ */ (0,
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-scoped", children: [
|
|
1040
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
1041
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows2, { stats: current.stats }, current.key)
|
|
1021
1042
|
] });
|
|
1022
1043
|
}
|
|
1023
1044
|
function hasStatsContent(it) {
|
|
1024
1045
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
1025
1046
|
}
|
|
1026
|
-
function
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
function Crest2({ url, name, kind }) {
|
|
1030
|
-
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1031
|
-
if (url) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cls, style: { backgroundImage: `url(${url})` }, "aria-hidden": "true" });
|
|
1032
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `${cls} ss-w-bi-crest-mono`, "aria-hidden": "true", children: initials2(name) });
|
|
1033
|
-
}
|
|
1034
|
-
function StatsDisclosure({ it, ui }) {
|
|
1035
|
-
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
1047
|
+
function ReasonStrip({ it, ui }) {
|
|
1048
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
1036
1049
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1037
1050
|
const hasStats = hasStatsContent(it);
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1051
|
+
const hasText = !!it.text;
|
|
1052
|
+
if (!hasText && !hasStats) return null;
|
|
1053
|
+
const expandable = hasStats || (it.text?.length ?? 0) > 90;
|
|
1054
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-reason", children: [
|
|
1055
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-chart", "aria-hidden": "true" }),
|
|
1056
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-reason-body", children: [
|
|
1057
|
+
hasText ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: `ss-w-bi-text${open ? "" : " ss-w-bi-text-clamp"}`, children: it.text }) : null,
|
|
1058
|
+
open && hasStats ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows2, { stats: it.stats }) : null
|
|
1059
|
+
] }),
|
|
1060
|
+
expandable ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1041
1061
|
"button",
|
|
1042
1062
|
{
|
|
1043
1063
|
type: "button",
|
|
1044
|
-
className: "ss-w-bi-
|
|
1064
|
+
className: "ss-w-bi-expand",
|
|
1045
1065
|
"aria-expanded": open,
|
|
1066
|
+
"aria-label": open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats",
|
|
1046
1067
|
onClick: () => setOpen((v) => !v),
|
|
1047
|
-
children:
|
|
1048
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats" }),
|
|
1049
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
1050
|
-
]
|
|
1068
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `ss-w-bi-arrow${open ? " ss-w-bi-arrow-open" : ""}`, "aria-hidden": "true" })
|
|
1051
1069
|
}
|
|
1052
|
-
)
|
|
1053
|
-
open ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRows2, { stats: it.stats }) : null
|
|
1070
|
+
) : null
|
|
1054
1071
|
] });
|
|
1055
1072
|
}
|
|
1056
1073
|
function InsightCard({ it, ui, slip }) {
|
|
@@ -1058,105 +1075,119 @@ function InsightCard({ it, ui, slip }) {
|
|
|
1058
1075
|
const kickoff = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : void 0;
|
|
1059
1076
|
const hasNamedTeams = !!it.homeTeamName && !!it.awayTeamName;
|
|
1060
1077
|
const showHeader = !!it.competition || live || !!kickoff;
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
/* @__PURE__ */ (0,
|
|
1066
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-comp", children: it.competition })
|
|
1078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-binsight", children: [
|
|
1079
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-header", children: [
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-header-left", children: it.competition ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Crest2, { kind: "comp", url: it.competitionCrest, name: it.competition }),
|
|
1082
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-comp", children: it.competition })
|
|
1067
1083
|
] }) : null }),
|
|
1068
|
-
/* @__PURE__ */ (0,
|
|
1069
|
-
live ? /* @__PURE__ */ (0,
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1084
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ss-w-bi-header-right", children: [
|
|
1085
|
+
live ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ss-w-bi-live", children: [
|
|
1086
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1071
1087
|
ui?.liveLabel ?? "Live"
|
|
1072
1088
|
] }) : null,
|
|
1073
|
-
kickoff ? /* @__PURE__ */ (0,
|
|
1089
|
+
kickoff ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ss-w-bi-kick", children: [
|
|
1074
1090
|
kickoff.dayLabel,
|
|
1075
1091
|
" ",
|
|
1076
1092
|
kickoff.time
|
|
1077
1093
|
] }) : null
|
|
1078
1094
|
] })
|
|
1079
1095
|
] }) : null,
|
|
1080
|
-
/* @__PURE__ */ (0,
|
|
1081
|
-
/* @__PURE__ */ (0,
|
|
1082
|
-
/* @__PURE__ */ (0,
|
|
1083
|
-
/* @__PURE__ */ (0,
|
|
1084
|
-
/* @__PURE__ */ (0,
|
|
1085
|
-
/* @__PURE__ */ (0,
|
|
1086
|
-
/* @__PURE__ */ (0,
|
|
1087
|
-
] }) : it.fixture ? /* @__PURE__ */ (0,
|
|
1088
|
-
/* @__PURE__ */ (0,
|
|
1089
|
-
/* @__PURE__ */ (0,
|
|
1090
|
-
/* @__PURE__ */ (0,
|
|
1091
|
-
it.selection ? /* @__PURE__ */ (0,
|
|
1096
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-body", children: [
|
|
1097
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-fixture", children: hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1098
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Crest2, { kind: "team", url: it.homeCrest, name: it.homeTeamName }),
|
|
1099
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-team", children: it.homeTeamName }),
|
|
1100
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-team", children: it.awayTeamName }),
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Crest2, { kind: "team", url: it.awayCrest, name: it.awayTeamName })
|
|
1103
|
+
] }) : it.fixture ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-fixture-txt", children: it.fixture }) : null }),
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-action", children: [
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ss-w-bi-mkt", children: [
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-market", children: it.market }),
|
|
1107
|
+
it.selection ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-sel", children: it.selection }) : null
|
|
1092
1108
|
] }),
|
|
1093
|
-
it.isMarketFloor ? /* @__PURE__ */ (0,
|
|
1094
|
-
it.odds ? /* @__PURE__ */ (0,
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1096
|
-
/* @__PURE__ */ (0,
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1098
|
-
it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
1109
|
+
it.isMarketFloor ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-floor", children: ui?.marketFloorLabel ?? "Market price \xB7 not a value pick" }) : null,
|
|
1110
|
+
it.odds ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "ss-w-bi-odds", children: [
|
|
1111
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: it.odds }),
|
|
1112
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OddsMovementBadge, { previous: it.previousOdds, current: it.odds, direction: it.movementDirection, ui }),
|
|
1113
|
+
it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
1099
1114
|
] }) : null,
|
|
1100
|
-
/* @__PURE__ */ (0,
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AddToSlipButton, { it, slip, ui })
|
|
1101
1116
|
] })
|
|
1102
1117
|
] }),
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-reason-body", children: [
|
|
1106
|
-
it.text ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
1107
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatsDisclosure, { it, ui })
|
|
1108
|
-
] })
|
|
1109
|
-
] }) : null,
|
|
1110
|
-
it.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
1118
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ReasonStrip, { it, ui }),
|
|
1119
|
+
it.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
1111
1120
|
] });
|
|
1112
1121
|
}
|
|
1113
1122
|
function BettingInsightList({ insights, ui, slip }) {
|
|
1114
1123
|
if (!insights || insights.length === 0) return null;
|
|
1115
|
-
return /* @__PURE__ */ (0,
|
|
1124
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(InsightCard, { it, ui, slip }, it.id)) });
|
|
1116
1125
|
}
|
|
1117
1126
|
|
|
1118
1127
|
// src/components/MarketOddsCardList.tsx
|
|
1119
|
-
var
|
|
1120
|
-
var
|
|
1128
|
+
var import_react7 = require("react");
|
|
1129
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1121
1130
|
function OddsRow({ vm, row, ui, slip }) {
|
|
1122
1131
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
1123
|
-
return /* @__PURE__ */ (0,
|
|
1124
|
-
/* @__PURE__ */ (0,
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1126
|
-
/* @__PURE__ */ (0,
|
|
1127
|
-
/* @__PURE__ */ (0,
|
|
1132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-mo-row", children: [
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
1134
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OddsMovementBadge, { previous: row.previousOdds, current: row.odds, direction: row.movementDirection, ui }),
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
1128
1137
|
] });
|
|
1129
1138
|
}
|
|
1130
1139
|
function MarketOddsCard({ vm, ui, slip }) {
|
|
1131
|
-
const [open, setOpen] = (0,
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
+
const [open, setOpen] = (0, import_react7.useState)(false);
|
|
1141
|
+
const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
1142
|
+
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
1143
|
+
const showHeader = !!vm.competition || vm.isLive || !!kickoff;
|
|
1144
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-mocard", children: [
|
|
1145
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-bi-header", children: [
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1147
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-comp", children: vm.competition })
|
|
1149
|
+
] }) : null }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "ss-w-bi-header-right", children: [
|
|
1151
|
+
vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "ss-w-bi-live", children: [
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1153
|
+
ui?.liveLabel ?? "Live"
|
|
1154
|
+
] }) : null,
|
|
1155
|
+
kickoff ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "ss-w-bi-kick", children: [
|
|
1156
|
+
kickoff.dayLabel,
|
|
1157
|
+
" ",
|
|
1158
|
+
kickoff.time
|
|
1159
|
+
] }) : null
|
|
1160
|
+
] })
|
|
1140
1161
|
] }) : null,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1142
|
-
|
|
1143
|
-
|
|
1162
|
+
hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-mo-sub", children: [
|
|
1163
|
+
hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-bi-fixture", children: [
|
|
1164
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
|
|
1169
|
+
] }) : vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
|
|
1170
|
+
vm.market ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-mo-market", children: vm.market }) : null
|
|
1171
|
+
] }) : null,
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-mo-rows", children: [
|
|
1173
|
+
vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OddsRow, { vm, row, ui, slip }, row.key)),
|
|
1174
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OddsRow, { vm, row, ui, slip }, row.key)) : null
|
|
1144
1175
|
] }),
|
|
1145
|
-
vm.moreRows.length > 0 ? /* @__PURE__ */ (0,
|
|
1146
|
-
/* @__PURE__ */ (0,
|
|
1147
|
-
/* @__PURE__ */ (0,
|
|
1176
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
1178
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
|
|
1148
1179
|
] }) : null,
|
|
1149
|
-
vm.bookmaker ? /* @__PURE__ */ (0,
|
|
1150
|
-
vm.disclaimer ? /* @__PURE__ */ (0,
|
|
1180
|
+
vm.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: vm.bookmaker }) }) : null,
|
|
1181
|
+
vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
1151
1182
|
] });
|
|
1152
1183
|
}
|
|
1153
1184
|
function MarketOddsCardList({ cards, ui, slip }) {
|
|
1154
1185
|
if (!cards || cards.length === 0) return null;
|
|
1155
|
-
return /* @__PURE__ */ (0,
|
|
1186
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarketOddsCard, { vm, ui, slip }, vm.id)) });
|
|
1156
1187
|
}
|
|
1157
1188
|
|
|
1158
1189
|
// src/components/OddsMovementCard.tsx
|
|
1159
|
-
var
|
|
1190
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1160
1191
|
function directionWord(vm, ui) {
|
|
1161
1192
|
if (vm.direction === "shortened") return ui?.oddsShortened ?? "shortened";
|
|
1162
1193
|
if (vm.direction === "drifted") return ui?.oddsDrifted ?? "drifted";
|
|
@@ -1166,18 +1197,18 @@ function OddsMovementCard({ vm, ui }) {
|
|
|
1166
1197
|
const word = directionWord(vm, ui);
|
|
1167
1198
|
const drift = word ? `, ${word}` : "";
|
|
1168
1199
|
const aria = ui?.chartAria ? ui.chartAria(vm.opening, vm.current, word, vm.windowHours) : `Price movement over the last ${vm.windowHours} hours: opened at ${vm.opening}, currently ${vm.current}${drift}.`;
|
|
1169
|
-
return /* @__PURE__ */ (0,
|
|
1170
|
-
/* @__PURE__ */ (0,
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1172
|
-
/* @__PURE__ */ (0,
|
|
1200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-omcard", children: [
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-om-head", children: [
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-om-market", children: vm.market }),
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-om-tag", children: ui?.priceMovement ?? "Price movement" })
|
|
1173
1204
|
] }),
|
|
1174
|
-
vm.fixture ? /* @__PURE__ */ (0,
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
vm.competition ? /* @__PURE__ */ (0,
|
|
1205
|
+
vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-om-fixture", children: [
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: vm.fixture }),
|
|
1207
|
+
vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-om-comp", children: vm.competition }) : null
|
|
1177
1208
|
] }) : null,
|
|
1178
|
-
/* @__PURE__ */ (0,
|
|
1179
|
-
/* @__PURE__ */ (0,
|
|
1180
|
-
vm.geometry === null ? /* @__PURE__ */ (0,
|
|
1209
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-sel", children: vm.selection }),
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OddsMovementBadge, { previous: vm.opening, current: vm.current, direction: vm.direction, ui }),
|
|
1211
|
+
vm.geometry === null ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-empty", children: vm.observationCount === 1 ? ui?.singlePricePoint ?? "Only one price recorded so far for this selection." : ui?.notEnoughHistory ?? "No price history recorded yet for this selection." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1181
1212
|
"svg",
|
|
1182
1213
|
{
|
|
1183
1214
|
className: "ss-w-om-chart",
|
|
@@ -1186,83 +1217,83 @@ function OddsMovementCard({ vm, ui }) {
|
|
|
1186
1217
|
role: "img",
|
|
1187
1218
|
"aria-label": aria,
|
|
1188
1219
|
children: [
|
|
1189
|
-
vm.geometry.gridlines.map((g) => /* @__PURE__ */ (0,
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1191
|
-
/* @__PURE__ */ (0,
|
|
1220
|
+
vm.geometry.gridlines.map((g) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("g", { children: [
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("line", { className: "ss-w-om-grid", x1: 40, y1: g.y, x2: CHART_VIEW_W - 8, y2: g.y }),
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { className: "ss-w-om-ylab", x: 34, y: g.y + 3, textAnchor: "end", children: g.price.toFixed(2) })
|
|
1192
1223
|
] }, g.price)),
|
|
1193
|
-
/* @__PURE__ */ (0,
|
|
1194
|
-
vm.geometry.markers.map((m, i) => /* @__PURE__ */ (0,
|
|
1195
|
-
ui?.chartTimeLabel ? /* @__PURE__ */ (0,
|
|
1196
|
-
/* @__PURE__ */ (0,
|
|
1197
|
-
/* @__PURE__ */ (0,
|
|
1198
|
-
] }) : /* @__PURE__ */ (0,
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { className: "ss-w-om-line", d: vm.geometry.path, fill: "none" }),
|
|
1225
|
+
vm.geometry.markers.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("circle", { className: "ss-w-om-dot", cx: m.x, cy: m.y, r: 2.5 }, i)),
|
|
1226
|
+
ui?.chartTimeLabel ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
1227
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { className: "ss-w-om-xlab", x: 40, y: CHART_VIEW_H - 8, textAnchor: "start", children: ui.chartTimeLabel(vm.geometry.startMs) }),
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { className: "ss-w-om-xlab", x: CHART_VIEW_W - 8, y: CHART_VIEW_H - 8, textAnchor: "end", children: ui.chartTimeLabel(vm.geometry.endMs) })
|
|
1229
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("text", { className: "ss-w-om-xlab", x: 40, y: CHART_VIEW_H - 8, children: ui?.movementWindow ? ui.movementWindow(vm.windowHours) : `Last ${vm.windowHours}h` })
|
|
1199
1230
|
]
|
|
1200
1231
|
}
|
|
1201
1232
|
),
|
|
1202
|
-
/* @__PURE__ */ (0,
|
|
1203
|
-
/* @__PURE__ */ (0,
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-om-foot", children: [
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1204
1235
|
ui?.openingLabel ?? "Opening",
|
|
1205
1236
|
" ",
|
|
1206
|
-
/* @__PURE__ */ (0,
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: vm.opening })
|
|
1207
1238
|
] }),
|
|
1208
|
-
/* @__PURE__ */ (0,
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1209
1240
|
ui?.currentLabel ?? "Current",
|
|
1210
1241
|
" ",
|
|
1211
|
-
/* @__PURE__ */ (0,
|
|
1242
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: vm.current })
|
|
1212
1243
|
] })
|
|
1213
1244
|
] }),
|
|
1214
|
-
vm.bookmaker ? /* @__PURE__ */ (0,
|
|
1215
|
-
vm.excludedCount > 0 ? /* @__PURE__ */ (0,
|
|
1216
|
-
vm.isSuspended ? /* @__PURE__ */ (0,
|
|
1217
|
-
vm.disclaimer ? /* @__PURE__ */ (0,
|
|
1245
|
+
vm.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-foot", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: vm.bookmaker }) }) : null,
|
|
1246
|
+
vm.excludedCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-excl", children: ui?.excludedSuspended ? ui.excludedSuspended(vm.excludedCount) : `${vm.excludedCount} suspended price(s) excluded from this chart.` }) : null,
|
|
1247
|
+
vm.isSuspended ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-susp", children: ui?.selectionSuspended ?? "This selection is not currently available to bet." }) : null,
|
|
1248
|
+
vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-om-disc", children: vm.disclaimer }) : null
|
|
1218
1249
|
] });
|
|
1219
1250
|
}
|
|
1220
1251
|
function OddsMovementCardList({ cards, ui }) {
|
|
1221
1252
|
if (!cards || cards.length === 0) return null;
|
|
1222
|
-
return /* @__PURE__ */ (0,
|
|
1253
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-omcards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OddsMovementCard, { vm, ui }, vm.id)) });
|
|
1223
1254
|
}
|
|
1224
1255
|
|
|
1225
1256
|
// src/components/ActionButtons.tsx
|
|
1226
|
-
var
|
|
1257
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1227
1258
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
1228
1259
|
if (actions.length === 0 && !loading) return null;
|
|
1229
|
-
return /* @__PURE__ */ (0,
|
|
1230
|
-
actions.map((a, i) => /* @__PURE__ */ (0,
|
|
1231
|
-
actions.length === 0 && loading ? /* @__PURE__ */ (0,
|
|
1232
|
-
/* @__PURE__ */ (0,
|
|
1233
|
-
/* @__PURE__ */ (0,
|
|
1260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-actions", children: [
|
|
1261
|
+
actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
1262
|
+
actions.length === 0 && loading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-abtn-shimmer" }),
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-abtn-shimmer" })
|
|
1234
1265
|
] }) : null
|
|
1235
1266
|
] });
|
|
1236
1267
|
}
|
|
1237
1268
|
|
|
1238
1269
|
// src/components/dashboard/DashboardTile.tsx
|
|
1239
|
-
var
|
|
1270
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1240
1271
|
var MAX_CRESTS = 3;
|
|
1241
1272
|
function DashboardTile({ tile, onTap }) {
|
|
1242
1273
|
const spanClass = tile.span === "full" ? "ss-w-dash-tile--full" : "ss-w-dash-tile--half";
|
|
1243
1274
|
const crests = (tile.imageUrls ?? []).slice(0, MAX_CRESTS);
|
|
1244
1275
|
const hasMeta = Boolean(tile.badgeText) || crests.length > 0;
|
|
1245
|
-
return /* @__PURE__ */ (0,
|
|
1246
|
-
/* @__PURE__ */ (0,
|
|
1247
|
-
/* @__PURE__ */ (0,
|
|
1248
|
-
/* @__PURE__ */ (0,
|
|
1249
|
-
tile.subtitle ? /* @__PURE__ */ (0,
|
|
1276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", className: `ss-w-dash-tile ${spanClass}`, onClick: onTap, children: [
|
|
1277
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-icon", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DashboardIcon, { name: tile.icon }) }),
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-dash-tile-body", children: [
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-title", children: tile.title }),
|
|
1280
|
+
tile.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-subtitle", children: tile.subtitle }) : null,
|
|
1250
1281
|
hasMeta ? (
|
|
1251
1282
|
// Badge + crests sit on their own row, below the title, instead of sharing the
|
|
1252
1283
|
// icon/chevron row -- at the half-span tile's ~180px width a nowrap badge alone
|
|
1253
1284
|
// (~70px) left the title column at ~22px and forced character-by-character wrapping.
|
|
1254
|
-
/* @__PURE__ */ (0,
|
|
1255
|
-
tile.badgeText ? /* @__PURE__ */ (0,
|
|
1256
|
-
crests.length > 0 ? /* @__PURE__ */ (0,
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-dash-tile-meta", children: [
|
|
1286
|
+
tile.badgeText ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-badge", children: tile.badgeText }) : null,
|
|
1287
|
+
crests.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-crests", children: crests.map((url, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-crest", style: { backgroundImage: `url(${url})` }, "aria-hidden": "true" }, `${url}-${i}`)) }) : null
|
|
1257
1288
|
] })
|
|
1258
1289
|
) : null
|
|
1259
1290
|
] }),
|
|
1260
|
-
/* @__PURE__ */ (0,
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-dash-tile-chevron", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ChevronIcon, {}) })
|
|
1261
1292
|
] });
|
|
1262
1293
|
}
|
|
1263
1294
|
|
|
1264
1295
|
// src/components/dashboard/GreetingDashboard.tsx
|
|
1265
|
-
var
|
|
1296
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1266
1297
|
var LAYOUT_CLASSES = {
|
|
1267
1298
|
market: "ss-w-dash--market",
|
|
1268
1299
|
goal: "ss-w-dash--goal",
|
|
@@ -1272,75 +1303,75 @@ function layoutClass(layout) {
|
|
|
1272
1303
|
return Object.prototype.hasOwnProperty.call(LAYOUT_CLASSES, layout) ? LAYOUT_CLASSES[layout] : LAYOUT_CLASSES.goal;
|
|
1273
1304
|
}
|
|
1274
1305
|
function GreetingDashboard({ dashboard, onTap }) {
|
|
1275
|
-
return /* @__PURE__ */ (0,
|
|
1276
|
-
/* @__PURE__ */ (0,
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1278
|
-
dashboard.subtitle ? /* @__PURE__ */ (0,
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `ss-w-dash ${layoutClass(dashboard.layout)}`, children: [
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ss-w-dash-head", children: [
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "ss-w-dash-title", children: dashboard.title }),
|
|
1309
|
+
dashboard.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "ss-w-dash-subtitle", children: dashboard.subtitle }) : null
|
|
1279
1310
|
] }),
|
|
1280
|
-
/* @__PURE__ */ (0,
|
|
1281
|
-
dashboard.footerTip ? /* @__PURE__ */ (0,
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ss-w-dash-grid", children: dashboard.tiles.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DashboardTile, { tile: t, onTap: () => onTap(t, i) }, `${t.title}-${i}`)) }),
|
|
1312
|
+
dashboard.footerTip ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "ss-w-dash-foot", children: dashboard.footerTip }) : null
|
|
1282
1313
|
] });
|
|
1283
1314
|
}
|
|
1284
1315
|
|
|
1285
1316
|
// src/components/club-dashboard/GreetingHeaderBlock.tsx
|
|
1286
|
-
var
|
|
1317
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1287
1318
|
function GreetingHeaderBlock({ block }) {
|
|
1288
|
-
return /* @__PURE__ */ (0,
|
|
1289
|
-
/* @__PURE__ */ (0,
|
|
1290
|
-
/* @__PURE__ */ (0,
|
|
1319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-cdash-greeting", children: [
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-cdash-greeting-title", children: block.title }),
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-cdash-greeting-subtitle", children: block.subtitle })
|
|
1291
1322
|
] });
|
|
1292
1323
|
}
|
|
1293
1324
|
|
|
1294
1325
|
// src/components/club-dashboard/FixtureHeroBlock.tsx
|
|
1295
|
-
var
|
|
1296
|
-
var
|
|
1326
|
+
var import_react8 = require("react");
|
|
1327
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1297
1328
|
function initials3(name) {
|
|
1298
1329
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
|
|
1299
1330
|
}
|
|
1300
1331
|
function Crest3({ url, name }) {
|
|
1301
|
-
const [broken, setBroken] = (0,
|
|
1332
|
+
const [broken, setBroken] = (0, import_react8.useState)(false);
|
|
1302
1333
|
if (!url || broken) {
|
|
1303
|
-
return /* @__PURE__ */ (0,
|
|
1334
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials3(name) });
|
|
1304
1335
|
}
|
|
1305
|
-
return /* @__PURE__ */ (0,
|
|
1336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
|
|
1306
1337
|
}
|
|
1307
1338
|
function FixtureHeroBlock({
|
|
1308
1339
|
block,
|
|
1309
1340
|
ui,
|
|
1310
1341
|
onAction
|
|
1311
1342
|
}) {
|
|
1312
|
-
return /* @__PURE__ */ (0,
|
|
1313
|
-
/* @__PURE__ */ (0,
|
|
1314
|
-
/* @__PURE__ */ (0,
|
|
1315
|
-
/* @__PURE__ */ (0,
|
|
1316
|
-
/* @__PURE__ */ (0,
|
|
1317
|
-
/* @__PURE__ */ (0,
|
|
1318
|
-
/* @__PURE__ */ (0,
|
|
1343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-fixture", children: [
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-tie", children: [
|
|
1345
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Crest3, { url: block.homeCrestUrl, name: block.homeName }),
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-team", children: block.homeName }),
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-vs", children: "v" }),
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-team", children: block.awayName }),
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Crest3, { url: block.awayCrestUrl, name: block.awayName })
|
|
1319
1350
|
] }),
|
|
1320
|
-
/* @__PURE__ */ (0,
|
|
1321
|
-
/* @__PURE__ */ (0,
|
|
1322
|
-
block.venue ? /* @__PURE__ */ (0,
|
|
1323
|
-
block.competition ? /* @__PURE__ */ (0,
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-fixture-meta", children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-kickoff", children: ui.clubKickoff(block.kickoffUnix * 1e3) }),
|
|
1353
|
+
block.venue ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
|
|
1354
|
+
block.competition ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
|
|
1324
1355
|
] }),
|
|
1325
|
-
/* @__PURE__ */ (0,
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaActionValue, void 0, block.ctaLabel), children: block.ctaLabel })
|
|
1326
1357
|
] });
|
|
1327
1358
|
}
|
|
1328
1359
|
|
|
1329
1360
|
// src/components/club-dashboard/FormGuideBlock.tsx
|
|
1330
|
-
var
|
|
1361
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1331
1362
|
function FormGuideBlock({ block }) {
|
|
1332
1363
|
if (block.rows.length === 0) return null;
|
|
1333
|
-
return /* @__PURE__ */ (0,
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
1364
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-cdash-form-row", children: [
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-cdash-form-name", children: [
|
|
1335
1366
|
row.name,
|
|
1336
1367
|
row.position != null ? ` #${row.position}` : ""
|
|
1337
1368
|
] }),
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-cdash-form-pills", children: row.last5.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) })
|
|
1339
1370
|
] }, row.name)) });
|
|
1340
1371
|
}
|
|
1341
1372
|
|
|
1342
1373
|
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1343
|
-
var
|
|
1374
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1344
1375
|
function MatchPreviewBlock({
|
|
1345
1376
|
block,
|
|
1346
1377
|
ui,
|
|
@@ -1348,10 +1379,10 @@ function MatchPreviewBlock({
|
|
|
1348
1379
|
}) {
|
|
1349
1380
|
if (block.facts.length === 0) return null;
|
|
1350
1381
|
const heading = ui.clubMatchPreviewHeading;
|
|
1351
|
-
return /* @__PURE__ */ (0,
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1353
1384
|
block.facts.map(
|
|
1354
|
-
(f, i) => f.entityRef ? /* @__PURE__ */ (0,
|
|
1385
|
+
(f, i) => f.entityRef ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1355
1386
|
"button",
|
|
1356
1387
|
{
|
|
1357
1388
|
type: "button",
|
|
@@ -1359,20 +1390,20 @@ function MatchPreviewBlock({
|
|
|
1359
1390
|
onClick: () => onAction(f.question ?? f.sentence, { ...f.entityRef, subject: f.sentence, personaHint: "club" }),
|
|
1360
1391
|
children: [
|
|
1361
1392
|
f.sentence,
|
|
1362
|
-
f.label ? /* @__PURE__ */ (0,
|
|
1393
|
+
f.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1363
1394
|
" ",
|
|
1364
1395
|
f.label
|
|
1365
1396
|
] }) : null
|
|
1366
1397
|
]
|
|
1367
1398
|
},
|
|
1368
1399
|
i
|
|
1369
|
-
) : /* @__PURE__ */ (0,
|
|
1400
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: f.sentence }, i)
|
|
1370
1401
|
)
|
|
1371
1402
|
] });
|
|
1372
1403
|
}
|
|
1373
1404
|
|
|
1374
1405
|
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1375
|
-
var
|
|
1406
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1376
1407
|
function TeamDnaBlock({
|
|
1377
1408
|
block,
|
|
1378
1409
|
ui,
|
|
@@ -1380,10 +1411,10 @@ function TeamDnaBlock({
|
|
|
1380
1411
|
}) {
|
|
1381
1412
|
if (block.facts.length === 0) return null;
|
|
1382
1413
|
const heading = ui.clubTeamDnaHeading;
|
|
1383
|
-
return /* @__PURE__ */ (0,
|
|
1384
|
-
/* @__PURE__ */ (0,
|
|
1414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1385
1416
|
block.facts.map(
|
|
1386
|
-
(f, i) => f.entityRef ? /* @__PURE__ */ (0,
|
|
1417
|
+
(f, i) => f.entityRef ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1387
1418
|
"button",
|
|
1388
1419
|
{
|
|
1389
1420
|
type: "button",
|
|
@@ -1391,21 +1422,21 @@ function TeamDnaBlock({
|
|
|
1391
1422
|
onClick: () => onAction(f.question ?? f.sentence, { ...f.entityRef, subject: f.sentence, personaHint: "club" }),
|
|
1392
1423
|
children: [
|
|
1393
1424
|
f.sentence,
|
|
1394
|
-
f.label ? /* @__PURE__ */ (0,
|
|
1425
|
+
f.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1395
1426
|
" ",
|
|
1396
1427
|
f.label
|
|
1397
1428
|
] }) : null
|
|
1398
1429
|
]
|
|
1399
1430
|
},
|
|
1400
1431
|
i
|
|
1401
|
-
) : /* @__PURE__ */ (0,
|
|
1432
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: f.sentence }, i)
|
|
1402
1433
|
)
|
|
1403
1434
|
] });
|
|
1404
1435
|
}
|
|
1405
1436
|
|
|
1406
1437
|
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1407
|
-
var
|
|
1408
|
-
var
|
|
1438
|
+
var import_react9 = require("react");
|
|
1439
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1409
1440
|
var DAY_MS = 24 * 3600 * 1e3;
|
|
1410
1441
|
function pad2(n) {
|
|
1411
1442
|
return String(n).padStart(2, "0");
|
|
@@ -1418,8 +1449,8 @@ function splitRemaining(remainingMs) {
|
|
|
1418
1449
|
return { h: pad2(h), m: pad2(m), s: pad2(s) };
|
|
1419
1450
|
}
|
|
1420
1451
|
function CountdownBlock({ block, ui }) {
|
|
1421
|
-
const [remainingMs, setRemainingMs] = (0,
|
|
1422
|
-
(0,
|
|
1452
|
+
const [remainingMs, setRemainingMs] = (0, import_react9.useState)(() => block.kickoffUnix * 1e3 - Date.now());
|
|
1453
|
+
(0, import_react9.useEffect)(() => {
|
|
1423
1454
|
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1424
1455
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1425
1456
|
const id = setInterval(() => {
|
|
@@ -1430,30 +1461,30 @@ function CountdownBlock({ block, ui }) {
|
|
|
1430
1461
|
if (remainingMs <= 0) return null;
|
|
1431
1462
|
if (remainingMs > DAY_MS) return null;
|
|
1432
1463
|
const { h, m, s } = splitRemaining(remainingMs);
|
|
1433
|
-
return /* @__PURE__ */ (0,
|
|
1434
|
-
/* @__PURE__ */ (0,
|
|
1435
|
-
/* @__PURE__ */ (0,
|
|
1464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-h", children: h }),
|
|
1436
1467
|
"h",
|
|
1437
1468
|
" ",
|
|
1438
|
-
/* @__PURE__ */ (0,
|
|
1469
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1439
1470
|
"m",
|
|
1440
1471
|
" ",
|
|
1441
|
-
/* @__PURE__ */ (0,
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1442
1473
|
"s"
|
|
1443
1474
|
] }),
|
|
1444
|
-
/* @__PURE__ */ (0,
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1445
1476
|
] });
|
|
1446
1477
|
}
|
|
1447
1478
|
|
|
1448
1479
|
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1449
|
-
var
|
|
1480
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1450
1481
|
var CLUB_BLOCK_REGISTRY = {
|
|
1451
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0,
|
|
1452
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0,
|
|
1453
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0,
|
|
1454
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0,
|
|
1455
|
-
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ (0,
|
|
1456
|
-
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ (0,
|
|
1482
|
+
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(GreetingHeaderBlock, { block }) : null,
|
|
1483
|
+
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FixtureHeroBlock, { block, ui, onAction }) : null,
|
|
1484
|
+
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FormGuideBlock, { block, ui }) : null,
|
|
1485
|
+
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MatchPreviewBlock, { block, ui, onAction }) : null,
|
|
1486
|
+
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TeamDnaBlock, { block, ui, onAction }) : null,
|
|
1487
|
+
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CountdownBlock, { block, ui }) : null
|
|
1457
1488
|
};
|
|
1458
1489
|
function ClubDashboard({
|
|
1459
1490
|
dashboard,
|
|
@@ -1461,39 +1492,39 @@ function ClubDashboard({
|
|
|
1461
1492
|
onAction
|
|
1462
1493
|
}) {
|
|
1463
1494
|
if (!dashboard.blocks.length) return null;
|
|
1464
|
-
return /* @__PURE__ */ (0,
|
|
1495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1465
1496
|
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1466
1497
|
if (!Comp) {
|
|
1467
1498
|
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1468
1499
|
return null;
|
|
1469
1500
|
}
|
|
1470
|
-
return /* @__PURE__ */ (0,
|
|
1501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Comp, { block, ui, onAction }) }, i);
|
|
1471
1502
|
}) });
|
|
1472
1503
|
}
|
|
1473
1504
|
|
|
1474
1505
|
// src/components/ChatMessage.tsx
|
|
1475
|
-
var
|
|
1506
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1476
1507
|
function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
|
|
1477
1508
|
if (message.role === "user") {
|
|
1478
|
-
return /* @__PURE__ */ (0,
|
|
1509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1479
1510
|
}
|
|
1480
|
-
return /* @__PURE__ */ (0,
|
|
1481
|
-
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0,
|
|
1482
|
-
message.greetingDashboard ? /* @__PURE__ */ (0,
|
|
1483
|
-
message.clubDashboard && ui ? /* @__PURE__ */ (0,
|
|
1484
|
-
/* @__PURE__ */ (0,
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1486
|
-
/* @__PURE__ */ (0,
|
|
1487
|
-
/* @__PURE__ */ (0,
|
|
1488
|
-
/* @__PURE__ */ (0,
|
|
1511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1512
|
+
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Markdown, { text: message.text }) : null,
|
|
1513
|
+
message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1514
|
+
message.clubDashboard && ui ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1516
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1517
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1489
1520
|
] });
|
|
1490
1521
|
}
|
|
1491
1522
|
|
|
1492
1523
|
// src/components/IntentChips.tsx
|
|
1493
|
-
var
|
|
1524
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1494
1525
|
function IntentChips({ chips, onPick }) {
|
|
1495
1526
|
if (chips.length === 0) return null;
|
|
1496
|
-
return /* @__PURE__ */ (0,
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1497
1528
|
}
|
|
1498
1529
|
|
|
1499
1530
|
// src/scroll.ts
|
|
@@ -1503,18 +1534,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1503
1534
|
}
|
|
1504
1535
|
|
|
1505
1536
|
// src/components/MessageList.tsx
|
|
1506
|
-
var
|
|
1537
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1507
1538
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1508
1539
|
const { state, send } = controller;
|
|
1509
|
-
const listRef = (0,
|
|
1510
|
-
const endRef = (0,
|
|
1511
|
-
const pinnedRef = (0,
|
|
1512
|
-
(0,
|
|
1540
|
+
const listRef = (0, import_react10.useRef)(null);
|
|
1541
|
+
const endRef = (0, import_react10.useRef)(null);
|
|
1542
|
+
const pinnedRef = (0, import_react10.useRef)(true);
|
|
1543
|
+
(0, import_react10.useEffect)(() => {
|
|
1513
1544
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
1514
1545
|
}, [state.messages, state.status]);
|
|
1515
1546
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1516
1547
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1517
|
-
return /* @__PURE__ */ (0,
|
|
1548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1518
1549
|
"div",
|
|
1519
1550
|
{
|
|
1520
1551
|
className: "ss-w-list",
|
|
@@ -1524,7 +1555,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1524
1555
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1525
1556
|
},
|
|
1526
1557
|
children: [
|
|
1527
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
1558
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1528
1559
|
ChatMessage,
|
|
1529
1560
|
{
|
|
1530
1561
|
message: m,
|
|
@@ -1540,25 +1571,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1540
1571
|
},
|
|
1541
1572
|
m.id
|
|
1542
1573
|
)),
|
|
1543
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
1574
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1544
1575
|
} }) : null,
|
|
1545
|
-
state.status ? /* @__PURE__ */ (0,
|
|
1546
|
-
state.error ? /* @__PURE__ */ (0,
|
|
1547
|
-
/* @__PURE__ */ (0,
|
|
1548
|
-
/* @__PURE__ */ (0,
|
|
1576
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1577
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
1578
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1579
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1549
1580
|
] }) : null,
|
|
1550
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0,
|
|
1551
|
-
/* @__PURE__ */ (0,
|
|
1581
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1582
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: endRef })
|
|
1552
1583
|
]
|
|
1553
1584
|
}
|
|
1554
1585
|
);
|
|
1555
1586
|
}
|
|
1556
1587
|
|
|
1557
1588
|
// src/components/ChatInput.tsx
|
|
1558
|
-
var
|
|
1559
|
-
var
|
|
1589
|
+
var import_react11 = require("react");
|
|
1590
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1560
1591
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1561
|
-
const [value, setValue] = (0,
|
|
1592
|
+
const [value, setValue] = (0, import_react11.useState)("");
|
|
1562
1593
|
const submit = () => {
|
|
1563
1594
|
const t = value.trim();
|
|
1564
1595
|
if (!t) return;
|
|
@@ -1571,18 +1602,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1571
1602
|
submit();
|
|
1572
1603
|
}
|
|
1573
1604
|
};
|
|
1574
|
-
return /* @__PURE__ */ (0,
|
|
1575
|
-
/* @__PURE__ */ (0,
|
|
1576
|
-
streaming ? /* @__PURE__ */ (0,
|
|
1605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "ss-w-input", children: [
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1607
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendIcon, {}) })
|
|
1577
1608
|
] });
|
|
1578
1609
|
}
|
|
1579
1610
|
|
|
1580
1611
|
// src/components/ChatPanel.tsx
|
|
1581
|
-
var
|
|
1612
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1582
1613
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1583
1614
|
function useIsModal() {
|
|
1584
|
-
const [modal, setModal] = (0,
|
|
1585
|
-
(0,
|
|
1615
|
+
const [modal, setModal] = (0, import_react12.useState)(false);
|
|
1616
|
+
(0, import_react12.useEffect)(() => {
|
|
1586
1617
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1587
1618
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1588
1619
|
const sync = () => setModal(mql.matches);
|
|
@@ -1595,17 +1626,17 @@ function useIsModal() {
|
|
|
1595
1626
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
1596
1627
|
const { state, close, stop, send } = controller;
|
|
1597
1628
|
const isModal = useIsModal();
|
|
1598
|
-
(0,
|
|
1629
|
+
(0, import_react12.useEffect)(() => {
|
|
1599
1630
|
const onKey = (e) => {
|
|
1600
1631
|
if (e.key === "Escape") close();
|
|
1601
1632
|
};
|
|
1602
1633
|
window.addEventListener("keydown", onKey);
|
|
1603
1634
|
return () => window.removeEventListener("keydown", onKey);
|
|
1604
1635
|
}, [close]);
|
|
1605
|
-
return /* @__PURE__ */ (0,
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1607
|
-
/* @__PURE__ */ (0,
|
|
1608
|
-
/* @__PURE__ */ (0,
|
|
1636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1637
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1609
1640
|
] });
|
|
1610
1641
|
}
|
|
1611
1642
|
|
|
@@ -1653,7 +1684,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1653
1684
|
.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }
|
|
1654
1685
|
|
|
1655
1686
|
/* panel */
|
|
1656
|
-
.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(
|
|
1687
|
+
.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(460px, calc(100vw - 40px)); height: min(640px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }
|
|
1657
1688
|
.ss-w-root[data-ss-w-pos="right"] .ss-w-panel { right: var(--ss-w-offset-x); }
|
|
1658
1689
|
.ss-w-root[data-ss-w-pos="left"] .ss-w-panel { left: var(--ss-w-offset-x); }
|
|
1659
1690
|
@media (max-width: 639px) {
|
|
@@ -1756,9 +1787,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1756
1787
|
.ss-w-bi-floor { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; align-self: flex-start; flex: none; }
|
|
1757
1788
|
|
|
1758
1789
|
/* crests -- CSS background-image on a span, never <img> (matches .ss-w-ecard-crest precedent) */
|
|
1759
|
-
.ss-w-bi-comp-logo { width:
|
|
1760
|
-
.ss-w-bi-crest { width:
|
|
1761
|
-
.ss-w-bi-crest-mono { display: grid; place-items: center; font-size:
|
|
1790
|
+
.ss-w-bi-comp-logo { width: 16px; height: 16px; flex: none; display: block; border-radius: 50%; object-fit: contain; }
|
|
1791
|
+
.ss-w-bi-crest { width: 24px; height: 24px; flex: none; display: block; border-radius: 50%; object-fit: contain; }
|
|
1792
|
+
.ss-w-bi-crest-mono { display: grid; place-items: center; font-size: 10px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
|
|
1762
1793
|
|
|
1763
1794
|
/* row 2: crest-flanked fixture on the left, boxed action panel on the right */
|
|
1764
1795
|
.ss-w-bi-body { display: flex; align-items: center; gap: 10px; }
|
|
@@ -1766,16 +1797,16 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1766
1797
|
.ss-w-bi-team { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1767
1798
|
.ss-w-bi-vs { font-size: 10px; font-weight: 600; color: var(--ss-w-faint); flex: none; }
|
|
1768
1799
|
.ss-w-bi-fixture-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1769
|
-
.ss-w-bi-action { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items:
|
|
1770
|
-
.ss-w-bi-action .ss-w-slip
|
|
1800
|
+
.ss-w-bi-action { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; min-width: 0; }
|
|
1801
|
+
.ss-w-bi-action .ss-w-slip { width: 100%; }
|
|
1802
|
+
.ss-w-bi-action .ss-w-slip > button { flex: 1; width: 100%; text-align: center; border-radius: 8px; }
|
|
1771
1803
|
/* The action column is narrow; let its toast size to its own text and anchor to the card's right edge instead of being clipped to the button width. */
|
|
1772
1804
|
.ss-w-bi-action .ss-w-toast { left: auto; right: 0; width: max-content; max-width: 210px; white-space: normal; }
|
|
1773
|
-
.ss-w-bi-mkt { display: flex; flex-direction: column; gap:
|
|
1774
|
-
.ss-w-bi-market { font-size:
|
|
1775
|
-
.ss-w-bi-sel { font-size:
|
|
1776
|
-
.ss-w-bi-odds { flex: none; display: flex;
|
|
1777
|
-
.ss-w-bi-odds
|
|
1778
|
-
.ss-w-bi-odds b { font-size: 19px; font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.1; }
|
|
1805
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; gap: 1px; min-width: 0; align-items: flex-end; text-align: right; }
|
|
1806
|
+
.ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.2; color: var(--ss-w-faint); white-space: nowrap; }
|
|
1807
|
+
.ss-w-bi-sel { font-size: 11px; line-height: 1.25; color: var(--ss-w-faint); }
|
|
1808
|
+
.ss-w-bi-odds { flex: none; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }
|
|
1809
|
+
.ss-w-bi-odds b { font-size: 23px; font-family: ui-monospace, monospace; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.05; }
|
|
1779
1810
|
.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }
|
|
1780
1811
|
|
|
1781
1812
|
/* row 3: bar-chart glyph + reasoning prose + stats-expander chevron, in a subtle strip */
|
|
@@ -1789,11 +1820,11 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1789
1820
|
}
|
|
1790
1821
|
.ss-w-bi-reason-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex: 1; }
|
|
1791
1822
|
.ss-w-bi-text { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); }
|
|
1792
|
-
.ss-w-bi-
|
|
1793
|
-
.ss-w-bi-
|
|
1794
|
-
.ss-w-bi-
|
|
1795
|
-
.ss-w-bi-
|
|
1796
|
-
.ss-w-bi-
|
|
1823
|
+
.ss-w-bi-text-clamp { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
1824
|
+
.ss-w-bi-expand { flex: none; align-self: center; display: grid; place-items: center; width: 22px; height: 22px; margin: -2px -4px -2px 0; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; }
|
|
1825
|
+
.ss-w-bi-expand:hover { color: var(--ss-w-ink); }
|
|
1826
|
+
.ss-w-bi-arrow { width: 7px; height: 7px; border-right: 1.6px solid currentColor; border-top: 1.6px solid currentColor; transform: rotate(45deg); transition: transform .15s ease; }
|
|
1827
|
+
.ss-w-bi-arrow-open { transform: rotate(135deg); }
|
|
1797
1828
|
.ss-w-bi-rows { display: flex; flex-direction: column; }
|
|
1798
1829
|
.ss-w-bi-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--ss-w-line); }
|
|
1799
1830
|
.ss-w-bi-row:first-child { border-top: none; }
|
|
@@ -1808,11 +1839,13 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1808
1839
|
/* market odds card */
|
|
1809
1840
|
.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }
|
|
1810
1841
|
.ss-w-mocard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }
|
|
1811
|
-
.ss-w-mo-
|
|
1812
|
-
.ss-w-mo-
|
|
1813
|
-
.ss-w-mo-
|
|
1814
|
-
.ss-w-mo-
|
|
1815
|
-
.ss-w-mo-
|
|
1842
|
+
.ss-w-mo-sub { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
|
|
1843
|
+
.ss-w-mo-teams { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1844
|
+
.ss-w-mo-market { font-size: 11.5px; font-weight: 600; color: var(--ss-w-faint); }
|
|
1845
|
+
.ss-w-mo-more { align-self: flex-start; display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11.5px; font-weight: 600; padding: 2px 0; cursor: pointer; }
|
|
1846
|
+
.ss-w-mo-more:hover { text-decoration: underline; }
|
|
1847
|
+
.ss-w-mo-more-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }
|
|
1848
|
+
.ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }
|
|
1816
1849
|
.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
1817
1850
|
.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
|
|
1818
1851
|
.ss-w-mo-row:last-child { border-bottom: none; }
|
|
@@ -1998,7 +2031,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1998
2031
|
`;
|
|
1999
2032
|
|
|
2000
2033
|
// src/StatsWidget.tsx
|
|
2001
|
-
var
|
|
2034
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2002
2035
|
function buildClient(props) {
|
|
2003
2036
|
try {
|
|
2004
2037
|
if ("client" in props && props.client) {
|
|
@@ -2023,11 +2056,11 @@ function injectStyles(root) {
|
|
|
2023
2056
|
function StatsWidget(props) {
|
|
2024
2057
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
2025
2058
|
const cfg = props.config;
|
|
2026
|
-
const built = (0,
|
|
2027
|
-
const ui = (0,
|
|
2028
|
-
const rootRef = (0,
|
|
2059
|
+
const built = (0, import_react13.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
2060
|
+
const ui = (0, import_react13.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
2061
|
+
const rootRef = (0, import_react13.useRef)(null);
|
|
2029
2062
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
2030
|
-
const slip = (0,
|
|
2063
|
+
const slip = (0, import_react13.useMemo)(
|
|
2031
2064
|
() => ({
|
|
2032
2065
|
onAddToSlip: props.config?.onAddToSlip,
|
|
2033
2066
|
conversationId: controller.state.conversationId ?? void 0,
|
|
@@ -2040,18 +2073,18 @@ function StatsWidget(props) {
|
|
|
2040
2073
|
}),
|
|
2041
2074
|
[props.config?.onAddToSlip, controller.state.conversationId, built]
|
|
2042
2075
|
);
|
|
2043
|
-
const onDashboardTap = (0,
|
|
2076
|
+
const onDashboardTap = (0, import_react13.useMemo)(
|
|
2044
2077
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
2045
2078
|
[built]
|
|
2046
2079
|
);
|
|
2047
|
-
(0,
|
|
2080
|
+
(0, import_react13.useEffect)(() => {
|
|
2048
2081
|
if (!built || !ui.injectStyles) return;
|
|
2049
2082
|
const node = rootRef.current?.getRootNode();
|
|
2050
2083
|
if (node) injectStyles(node);
|
|
2051
2084
|
}, [built, ui.injectStyles]);
|
|
2052
2085
|
if (!built) return null;
|
|
2053
2086
|
const attrs = themeAttrs(ui);
|
|
2054
|
-
return /* @__PURE__ */ (0,
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.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_runtime29.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2055
2088
|
ChatFab,
|
|
2056
2089
|
{
|
|
2057
2090
|
label: ui.launcherLabel,
|