@sensiblestats/widget-react 0.18.0 → 0.20.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 +17 -0
- package/dist/index.cjs +348 -285
- 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 +291 -228
- package/dist/index.js.map +1 -1
- package/dist/styles.css +24 -22
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -435,7 +435,13 @@ function toMarketOddsVM(card) {
|
|
|
435
435
|
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
436
436
|
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
437
437
|
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
438
|
+
homeTeamName: home,
|
|
439
|
+
awayTeamName: away,
|
|
440
|
+
homeCrest: str(card.homeTeamImagePath),
|
|
441
|
+
awayCrest: str(card.awayTeamImagePath),
|
|
442
|
+
competitionCrest: str(card.competitionImagePath),
|
|
438
443
|
competition: str(card.competitionName),
|
|
444
|
+
kickoffUtc: str(card.kickoffUtc),
|
|
439
445
|
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
440
446
|
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
441
447
|
isLive: rows.some((r) => r.isLive === true),
|
|
@@ -582,21 +588,42 @@ function reducer(state, action) {
|
|
|
582
588
|
}
|
|
583
589
|
|
|
584
590
|
// src/useChatStream.ts
|
|
591
|
+
var STREAM_FALLBACK_TIMEOUT_MS = 3e4;
|
|
585
592
|
function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
586
593
|
const seed = useMemo(() => initialState(starterTexts.map(chipFromText)), []);
|
|
587
594
|
const [state, dispatch] = useReducer(reducer, seed);
|
|
588
595
|
const idRef = useRef(0);
|
|
589
596
|
const handleRef = useRef(null);
|
|
597
|
+
const fallbackTimerRef = useRef(null);
|
|
590
598
|
const stateRef = useRef(state);
|
|
591
599
|
stateRef.current = state;
|
|
592
600
|
const greetedRef = useRef(false);
|
|
593
601
|
const nextId = () => `m${idRef.current++}`;
|
|
602
|
+
const clearFallbackTimer = useCallback(() => {
|
|
603
|
+
if (fallbackTimerRef.current != null) {
|
|
604
|
+
clearTimeout(fallbackTimerRef.current);
|
|
605
|
+
fallbackTimerRef.current = null;
|
|
606
|
+
}
|
|
607
|
+
}, []);
|
|
608
|
+
const armFallbackTimer = useCallback((onFire) => {
|
|
609
|
+
clearFallbackTimer();
|
|
610
|
+
fallbackTimerRef.current = setTimeout(() => {
|
|
611
|
+
fallbackTimerRef.current = null;
|
|
612
|
+
handleRef.current?.cancel();
|
|
613
|
+
handleRef.current = null;
|
|
614
|
+
onFire();
|
|
615
|
+
}, STREAM_FALLBACK_TIMEOUT_MS);
|
|
616
|
+
}, [clearFallbackTimer]);
|
|
594
617
|
const consume = useCallback((handle, onError) => {
|
|
595
618
|
;
|
|
596
619
|
(async () => {
|
|
597
620
|
try {
|
|
598
|
-
for await (const event of handle)
|
|
621
|
+
for await (const event of handle) {
|
|
622
|
+
dispatch({ kind: "EVENT", event });
|
|
623
|
+
if (event.type === "turn_complete" || event.type === "error") clearFallbackTimer();
|
|
624
|
+
}
|
|
599
625
|
} catch (err) {
|
|
626
|
+
if (handleRef.current === handle) clearFallbackTimer();
|
|
600
627
|
if (err instanceof WidgetSdkError2) onError(err);
|
|
601
628
|
else if (err?.name === "AbortError") {
|
|
602
629
|
} else throw err;
|
|
@@ -604,18 +631,23 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
604
631
|
if (handleRef.current === handle) handleRef.current = null;
|
|
605
632
|
}
|
|
606
633
|
})();
|
|
607
|
-
}, []);
|
|
634
|
+
}, [clearFallbackTimer]);
|
|
608
635
|
const run = useCallback((input, displayText) => {
|
|
609
636
|
handleRef.current?.cancel();
|
|
637
|
+
clearFallbackTimer();
|
|
610
638
|
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
|
|
611
639
|
const handle = conversation.send(input);
|
|
612
640
|
handleRef.current = handle;
|
|
641
|
+
armFallbackTimer(() => {
|
|
642
|
+
dispatch({ kind: "STOP" });
|
|
643
|
+
dispatch({ kind: "STREAM_ERROR", error: new WidgetSdkError2("No response received in time", "timeout") });
|
|
644
|
+
});
|
|
613
645
|
consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
|
|
614
|
-
}, [conversation, consume]);
|
|
646
|
+
}, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
615
647
|
const send = useCallback((text, opts) => {
|
|
616
648
|
const trimmed = text.trim();
|
|
617
649
|
if (!trimmed) return;
|
|
618
|
-
run({ message: trimmed, actionId: opts?.actionId,
|
|
650
|
+
run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText);
|
|
619
651
|
}, [run]);
|
|
620
652
|
const retry = useCallback(() => {
|
|
621
653
|
const last = stateRef.current.lastUserInput;
|
|
@@ -627,25 +659,29 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
627
659
|
greetedRef.current = true;
|
|
628
660
|
try {
|
|
629
661
|
handleRef.current?.cancel();
|
|
662
|
+
clearFallbackTimer();
|
|
630
663
|
dispatch({ kind: "GREETING_SENT", assistantId: nextId() });
|
|
631
664
|
const handle = conversation.send({ message });
|
|
632
665
|
handleRef.current = handle;
|
|
666
|
+
armFallbackTimer(() => dispatch({ kind: "STOP" }));
|
|
633
667
|
consume(handle, () => dispatch({ kind: "STOP" }));
|
|
634
668
|
} catch {
|
|
635
669
|
dispatch({ kind: "STOP" });
|
|
636
670
|
}
|
|
637
|
-
}, [greetingMessage, conversation, consume]);
|
|
671
|
+
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
638
672
|
const open = useCallback(() => dispatch({ kind: "OPEN" }), []);
|
|
639
673
|
const close = useCallback(() => {
|
|
640
674
|
handleRef.current?.cancel();
|
|
641
675
|
handleRef.current = null;
|
|
676
|
+
clearFallbackTimer();
|
|
642
677
|
dispatch({ kind: "CLOSE" });
|
|
643
|
-
}, []);
|
|
678
|
+
}, [clearFallbackTimer]);
|
|
644
679
|
const stop = useCallback(() => {
|
|
645
680
|
handleRef.current?.cancel();
|
|
646
681
|
handleRef.current = null;
|
|
682
|
+
clearFallbackTimer();
|
|
647
683
|
dispatch({ kind: "STOP" });
|
|
648
|
-
}, []);
|
|
684
|
+
}, [clearFallbackTimer]);
|
|
649
685
|
const toggle = useCallback(() => {
|
|
650
686
|
if (stateRef.current.isOpen) close();
|
|
651
687
|
else open();
|
|
@@ -711,7 +747,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
711
747
|
}
|
|
712
748
|
|
|
713
749
|
// src/components/ChatPanel.tsx
|
|
714
|
-
import { useEffect as useEffect5, useState as
|
|
750
|
+
import { useEffect as useEffect5, useState as useState9 } from "react";
|
|
715
751
|
|
|
716
752
|
// src/components/ChatHeader.tsx
|
|
717
753
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -844,7 +880,7 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
844
880
|
}
|
|
845
881
|
|
|
846
882
|
// src/components/BettingInsightList.tsx
|
|
847
|
-
import { useState as
|
|
883
|
+
import { useState as useState4 } from "react";
|
|
848
884
|
|
|
849
885
|
// src/components/AddToSlipButton.tsx
|
|
850
886
|
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
@@ -967,53 +1003,64 @@ function OddsMovementBadge({
|
|
|
967
1003
|
);
|
|
968
1004
|
}
|
|
969
1005
|
|
|
1006
|
+
// src/components/Crest.tsx
|
|
1007
|
+
import { useState as useState3 } from "react";
|
|
1008
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1009
|
+
function initials2(name) {
|
|
1010
|
+
return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
|
|
1011
|
+
}
|
|
1012
|
+
function Crest2({ url, name, kind }) {
|
|
1013
|
+
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
1014
|
+
const [failed, setFailed] = useState3(false);
|
|
1015
|
+
if (url && !failed) {
|
|
1016
|
+
return /* @__PURE__ */ jsx10("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1017
|
+
}
|
|
1018
|
+
return /* @__PURE__ */ jsx10("span", { className: `${cls} ss-w-bi-crest-mono`, "aria-hidden": "true", children: initials2(name) });
|
|
1019
|
+
}
|
|
1020
|
+
|
|
970
1021
|
// src/components/BettingInsightList.tsx
|
|
971
|
-
import { Fragment, jsx as
|
|
1022
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
972
1023
|
function StatRows2({ stats }) {
|
|
973
|
-
return /* @__PURE__ */
|
|
974
|
-
/* @__PURE__ */
|
|
975
|
-
/* @__PURE__ */
|
|
1024
|
+
return /* @__PURE__ */ jsx11("div", { className: "ss-w-bi-rows", children: stats.map((s) => /* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-row", children: [
|
|
1025
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
1026
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
976
1027
|
] }, `${s.label}:${s.value}`)) });
|
|
977
1028
|
}
|
|
978
1029
|
function ScopedStats({ scopes }) {
|
|
979
|
-
const [active, setActive] =
|
|
1030
|
+
const [active, setActive] = useState4(0);
|
|
980
1031
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
981
1032
|
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-scoped", children: [
|
|
982
|
-
/* @__PURE__ */
|
|
983
|
-
/* @__PURE__ */
|
|
1033
|
+
/* @__PURE__ */ jsx11("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx11("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
1034
|
+
/* @__PURE__ */ jsx11(StatRows2, { stats: current.stats }, current.key)
|
|
984
1035
|
] });
|
|
985
1036
|
}
|
|
986
1037
|
function hasStatsContent(it) {
|
|
987
1038
|
return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
|
|
988
1039
|
}
|
|
989
|
-
function
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
function Crest2({ url, name, kind }) {
|
|
993
|
-
const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
|
|
994
|
-
if (url) return /* @__PURE__ */ jsx10("span", { className: cls, style: { backgroundImage: `url(${url})` }, "aria-hidden": "true" });
|
|
995
|
-
return /* @__PURE__ */ jsx10("span", { className: `${cls} ss-w-bi-crest-mono`, "aria-hidden": "true", children: initials2(name) });
|
|
996
|
-
}
|
|
997
|
-
function StatsDisclosure({ it, ui }) {
|
|
998
|
-
const [open, setOpen] = useState3(false);
|
|
1040
|
+
function ReasonStrip({ it, ui }) {
|
|
1041
|
+
const [open, setOpen] = useState4(false);
|
|
999
1042
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
1000
1043
|
const hasStats = hasStatsContent(it);
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1044
|
+
const hasText = !!it.text;
|
|
1045
|
+
if (!hasText && !hasStats) return null;
|
|
1046
|
+
const expandable = hasStats || (it.text?.length ?? 0) > 90;
|
|
1047
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-reason", children: [
|
|
1048
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-chart", "aria-hidden": "true" }),
|
|
1049
|
+
/* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-reason-body", children: [
|
|
1050
|
+
hasText ? /* @__PURE__ */ jsx11("p", { className: `ss-w-bi-text${open ? "" : " ss-w-bi-text-clamp"}`, children: it.text }) : null,
|
|
1051
|
+
open && hasStats ? hasScopes ? /* @__PURE__ */ jsx11(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ jsx11(StatRows2, { stats: it.stats }) : null
|
|
1052
|
+
] }),
|
|
1053
|
+
expandable ? /* @__PURE__ */ jsx11(
|
|
1004
1054
|
"button",
|
|
1005
1055
|
{
|
|
1006
1056
|
type: "button",
|
|
1007
|
-
className: "ss-w-bi-
|
|
1057
|
+
className: "ss-w-bi-expand",
|
|
1008
1058
|
"aria-expanded": open,
|
|
1059
|
+
"aria-label": open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats",
|
|
1009
1060
|
onClick: () => setOpen((v) => !v),
|
|
1010
|
-
children:
|
|
1011
|
-
/* @__PURE__ */ jsx10("span", { children: open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats" }),
|
|
1012
|
-
/* @__PURE__ */ jsx10("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
1013
|
-
]
|
|
1061
|
+
children: /* @__PURE__ */ jsx11("span", { className: `ss-w-bi-arrow${open ? " ss-w-bi-arrow-open" : ""}`, "aria-hidden": "true" })
|
|
1014
1062
|
}
|
|
1015
|
-
)
|
|
1016
|
-
open ? hasScopes ? /* @__PURE__ */ jsx10(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ jsx10(StatRows2, { stats: it.stats }) : null
|
|
1063
|
+
) : null
|
|
1017
1064
|
] });
|
|
1018
1065
|
}
|
|
1019
1066
|
function InsightCard({ it, ui, slip }) {
|
|
@@ -1021,16 +1068,15 @@ function InsightCard({ it, ui, slip }) {
|
|
|
1021
1068
|
const kickoff = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : void 0;
|
|
1022
1069
|
const hasNamedTeams = !!it.homeTeamName && !!it.awayTeamName;
|
|
1023
1070
|
const showHeader = !!it.competition || live || !!kickoff;
|
|
1024
|
-
const showReason = !!it.text || hasStatsContent(it);
|
|
1025
1071
|
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-binsight", children: [
|
|
1026
1072
|
showHeader ? /* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-header", children: [
|
|
1027
|
-
/* @__PURE__ */
|
|
1028
|
-
/* @__PURE__ */
|
|
1029
|
-
/* @__PURE__ */
|
|
1073
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-header-left", children: it.competition ? /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
1074
|
+
/* @__PURE__ */ jsx11(Crest2, { kind: "comp", url: it.competitionCrest, name: it.competition }),
|
|
1075
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-comp", children: it.competition })
|
|
1030
1076
|
] }) : null }),
|
|
1031
1077
|
/* @__PURE__ */ jsxs7("span", { className: "ss-w-bi-header-right", children: [
|
|
1032
1078
|
live ? /* @__PURE__ */ jsxs7("span", { className: "ss-w-bi-live", children: [
|
|
1033
|
-
/* @__PURE__ */
|
|
1079
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1034
1080
|
ui?.liveLabel ?? "Live"
|
|
1035
1081
|
] }) : null,
|
|
1036
1082
|
kickoff ? /* @__PURE__ */ jsxs7("span", { className: "ss-w-bi-kick", children: [
|
|
@@ -1041,85 +1087,100 @@ function InsightCard({ it, ui, slip }) {
|
|
|
1041
1087
|
] })
|
|
1042
1088
|
] }) : null,
|
|
1043
1089
|
/* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-body", children: [
|
|
1044
|
-
/* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1050
|
-
] }) : it.fixture ? /* @__PURE__ */
|
|
1090
|
+
/* @__PURE__ */ jsx11("div", { className: "ss-w-bi-fixture", children: hasNamedTeams ? /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
1091
|
+
/* @__PURE__ */ jsx11(Crest2, { kind: "team", url: it.homeCrest, name: it.homeTeamName }),
|
|
1092
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-team", children: it.homeTeamName }),
|
|
1093
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1094
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-team", children: it.awayTeamName }),
|
|
1095
|
+
/* @__PURE__ */ jsx11(Crest2, { kind: "team", url: it.awayCrest, name: it.awayTeamName })
|
|
1096
|
+
] }) : it.fixture ? /* @__PURE__ */ jsx11("span", { className: "ss-w-bi-fixture-txt", children: it.fixture }) : null }),
|
|
1051
1097
|
/* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-action", children: [
|
|
1052
1098
|
/* @__PURE__ */ jsxs7("span", { className: "ss-w-bi-mkt", children: [
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
it.selection ? /* @__PURE__ */
|
|
1099
|
+
/* @__PURE__ */ jsx11("span", { className: "ss-w-bi-market", children: it.market }),
|
|
1100
|
+
it.selection ? /* @__PURE__ */ jsx11("span", { className: "ss-w-bi-sel", children: it.selection }) : null
|
|
1055
1101
|
] }),
|
|
1056
|
-
it.isMarketFloor ? /* @__PURE__ */
|
|
1102
|
+
it.isMarketFloor ? /* @__PURE__ */ jsx11("span", { className: "ss-w-bi-floor", children: ui?.marketFloorLabel ?? "Market price \xB7 not a value pick" }) : null,
|
|
1057
1103
|
it.odds ? /* @__PURE__ */ jsxs7("span", { className: "ss-w-bi-odds", children: [
|
|
1058
|
-
/* @__PURE__ */
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
it.bookmaker ? /* @__PURE__ */ jsx10("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
1104
|
+
/* @__PURE__ */ jsx11("b", { children: it.odds }),
|
|
1105
|
+
/* @__PURE__ */ jsx11(OddsMovementBadge, { previous: it.previousOdds, current: it.odds, direction: it.movementDirection, ui }),
|
|
1106
|
+
it.bookmaker ? /* @__PURE__ */ jsx11("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
1062
1107
|
] }) : null,
|
|
1063
|
-
/* @__PURE__ */
|
|
1108
|
+
/* @__PURE__ */ jsx11(AddToSlipButton, { it, slip, ui })
|
|
1064
1109
|
] })
|
|
1065
1110
|
] }),
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
/* @__PURE__ */ jsxs7("div", { className: "ss-w-bi-reason-body", children: [
|
|
1069
|
-
it.text ? /* @__PURE__ */ jsx10("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
1070
|
-
/* @__PURE__ */ jsx10(StatsDisclosure, { it, ui })
|
|
1071
|
-
] })
|
|
1072
|
-
] }) : null,
|
|
1073
|
-
it.disclaimer ? /* @__PURE__ */ jsx10("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
1111
|
+
/* @__PURE__ */ jsx11(ReasonStrip, { it, ui }),
|
|
1112
|
+
it.disclaimer ? /* @__PURE__ */ jsx11("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
1074
1113
|
] });
|
|
1075
1114
|
}
|
|
1076
1115
|
function BettingInsightList({ insights, ui, slip }) {
|
|
1077
1116
|
if (!insights || insights.length === 0) return null;
|
|
1078
|
-
return /* @__PURE__ */
|
|
1117
|
+
return /* @__PURE__ */ jsx11("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ jsx11(InsightCard, { it, ui, slip }, it.id)) });
|
|
1079
1118
|
}
|
|
1080
1119
|
|
|
1081
1120
|
// src/components/MarketOddsCardList.tsx
|
|
1082
|
-
import { useState as
|
|
1083
|
-
import { jsx as
|
|
1121
|
+
import { useState as useState5 } from "react";
|
|
1122
|
+
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1084
1123
|
function OddsRow({ vm, row, ui, slip }) {
|
|
1085
1124
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
1086
1125
|
return /* @__PURE__ */ jsxs8("div", { className: "ss-w-mo-row", children: [
|
|
1087
|
-
/* @__PURE__ */
|
|
1088
|
-
/* @__PURE__ */
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1126
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
1127
|
+
/* @__PURE__ */ jsx12(OddsMovementBadge, { previous: row.previousOdds, current: row.odds, direction: row.movementDirection, ui }),
|
|
1128
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
1129
|
+
/* @__PURE__ */ jsx12(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
1091
1130
|
] });
|
|
1092
1131
|
}
|
|
1093
1132
|
function MarketOddsCard({ vm, ui, slip }) {
|
|
1094
|
-
const [open, setOpen] =
|
|
1133
|
+
const [open, setOpen] = useState5(false);
|
|
1134
|
+
const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
|
|
1135
|
+
const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
|
|
1136
|
+
const showHeader = !!vm.competition || vm.isLive || !!kickoff;
|
|
1095
1137
|
return /* @__PURE__ */ jsxs8("div", { className: "ss-w-mocard", children: [
|
|
1096
|
-
/* @__PURE__ */ jsxs8("div", { className: "ss-w-
|
|
1097
|
-
/* @__PURE__ */
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1138
|
+
showHeader ? /* @__PURE__ */ jsxs8("div", { className: "ss-w-bi-header", children: [
|
|
1139
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
1140
|
+
/* @__PURE__ */ jsx12(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
|
|
1141
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-comp", children: vm.competition })
|
|
1142
|
+
] }) : null }),
|
|
1143
|
+
/* @__PURE__ */ jsxs8("span", { className: "ss-w-bi-header-right", children: [
|
|
1144
|
+
vm.isLive ? /* @__PURE__ */ jsxs8("span", { className: "ss-w-bi-live", children: [
|
|
1145
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
1146
|
+
ui?.liveLabel ?? "Live"
|
|
1147
|
+
] }) : null,
|
|
1148
|
+
kickoff ? /* @__PURE__ */ jsxs8("span", { className: "ss-w-bi-kick", children: [
|
|
1149
|
+
kickoff.dayLabel,
|
|
1150
|
+
" ",
|
|
1151
|
+
kickoff.time
|
|
1152
|
+
] }) : null
|
|
1153
|
+
] })
|
|
1154
|
+
] }) : null,
|
|
1155
|
+
hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ jsxs8("div", { className: "ss-w-mo-sub", children: [
|
|
1156
|
+
hasNamedTeams ? /* @__PURE__ */ jsxs8("div", { className: "ss-w-bi-fixture", children: [
|
|
1157
|
+
/* @__PURE__ */ jsx12(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
|
|
1158
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
|
|
1159
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
|
|
1160
|
+
/* @__PURE__ */ jsx12("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
|
|
1161
|
+
/* @__PURE__ */ jsx12(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
|
|
1162
|
+
] }) : vm.fixture ? /* @__PURE__ */ jsx12("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
|
|
1163
|
+
vm.market ? /* @__PURE__ */ jsx12("span", { className: "ss-w-mo-market", children: vm.market }) : null
|
|
1103
1164
|
] }) : null,
|
|
1104
1165
|
/* @__PURE__ */ jsxs8("div", { className: "ss-w-mo-rows", children: [
|
|
1105
|
-
vm.mainRows.map((row) => /* @__PURE__ */
|
|
1106
|
-
open ? vm.moreRows.map((row) => /* @__PURE__ */
|
|
1166
|
+
vm.mainRows.map((row) => /* @__PURE__ */ jsx12(OddsRow, { vm, row, ui, slip }, row.key)),
|
|
1167
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx12(OddsRow, { vm, row, ui, slip }, row.key)) : null
|
|
1107
1168
|
] }),
|
|
1108
|
-
vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs8("button", { type: "button", className: "ss-w-
|
|
1109
|
-
/* @__PURE__ */
|
|
1110
|
-
/* @__PURE__ */
|
|
1169
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs8("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
1170
|
+
/* @__PURE__ */ jsx12("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
1171
|
+
/* @__PURE__ */ jsx12("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
|
|
1111
1172
|
] }) : null,
|
|
1112
|
-
vm.bookmaker ? /* @__PURE__ */
|
|
1113
|
-
vm.disclaimer ? /* @__PURE__ */
|
|
1173
|
+
vm.bookmaker ? /* @__PURE__ */ jsx12("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ jsx12("span", { children: vm.bookmaker }) }) : null,
|
|
1174
|
+
vm.disclaimer ? /* @__PURE__ */ jsx12("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
1114
1175
|
] });
|
|
1115
1176
|
}
|
|
1116
1177
|
function MarketOddsCardList({ cards, ui, slip }) {
|
|
1117
1178
|
if (!cards || cards.length === 0) return null;
|
|
1118
|
-
return /* @__PURE__ */
|
|
1179
|
+
return /* @__PURE__ */ jsx12("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx12(MarketOddsCard, { vm, ui, slip }, vm.id)) });
|
|
1119
1180
|
}
|
|
1120
1181
|
|
|
1121
1182
|
// src/components/OddsMovementCard.tsx
|
|
1122
|
-
import { Fragment as
|
|
1183
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1123
1184
|
function directionWord(vm, ui) {
|
|
1124
1185
|
if (vm.direction === "shortened") return ui?.oddsShortened ?? "shortened";
|
|
1125
1186
|
if (vm.direction === "drifted") return ui?.oddsDrifted ?? "drifted";
|
|
@@ -1131,16 +1192,16 @@ function OddsMovementCard({ vm, ui }) {
|
|
|
1131
1192
|
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}.`;
|
|
1132
1193
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-omcard", children: [
|
|
1133
1194
|
/* @__PURE__ */ jsxs9("div", { className: "ss-w-om-head", children: [
|
|
1134
|
-
/* @__PURE__ */
|
|
1135
|
-
/* @__PURE__ */
|
|
1195
|
+
/* @__PURE__ */ jsx13("span", { className: "ss-w-om-market", children: vm.market }),
|
|
1196
|
+
/* @__PURE__ */ jsx13("span", { className: "ss-w-om-tag", children: ui?.priceMovement ?? "Price movement" })
|
|
1136
1197
|
] }),
|
|
1137
1198
|
vm.fixture ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-om-fixture", children: [
|
|
1138
|
-
/* @__PURE__ */
|
|
1139
|
-
vm.competition ? /* @__PURE__ */
|
|
1199
|
+
/* @__PURE__ */ jsx13("span", { children: vm.fixture }),
|
|
1200
|
+
vm.competition ? /* @__PURE__ */ jsx13("span", { className: "ss-w-om-comp", children: vm.competition }) : null
|
|
1140
1201
|
] }) : null,
|
|
1141
|
-
/* @__PURE__ */
|
|
1142
|
-
/* @__PURE__ */
|
|
1143
|
-
vm.geometry === null ? /* @__PURE__ */
|
|
1202
|
+
/* @__PURE__ */ jsx13("div", { className: "ss-w-om-sel", children: vm.selection }),
|
|
1203
|
+
/* @__PURE__ */ jsx13(OddsMovementBadge, { previous: vm.opening, current: vm.current, direction: vm.direction, ui }),
|
|
1204
|
+
vm.geometry === null ? /* @__PURE__ */ jsx13("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__ */ jsxs9(
|
|
1144
1205
|
"svg",
|
|
1145
1206
|
{
|
|
1146
1207
|
className: "ss-w-om-chart",
|
|
@@ -1150,15 +1211,15 @@ function OddsMovementCard({ vm, ui }) {
|
|
|
1150
1211
|
"aria-label": aria,
|
|
1151
1212
|
children: [
|
|
1152
1213
|
vm.geometry.gridlines.map((g) => /* @__PURE__ */ jsxs9("g", { children: [
|
|
1153
|
-
/* @__PURE__ */
|
|
1154
|
-
/* @__PURE__ */
|
|
1214
|
+
/* @__PURE__ */ jsx13("line", { className: "ss-w-om-grid", x1: 40, y1: g.y, x2: CHART_VIEW_W - 8, y2: g.y }),
|
|
1215
|
+
/* @__PURE__ */ jsx13("text", { className: "ss-w-om-ylab", x: 34, y: g.y + 3, textAnchor: "end", children: g.price.toFixed(2) })
|
|
1155
1216
|
] }, g.price)),
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
vm.geometry.markers.map((m, i) => /* @__PURE__ */
|
|
1158
|
-
ui?.chartTimeLabel ? /* @__PURE__ */ jsxs9(
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1161
|
-
] }) : /* @__PURE__ */
|
|
1217
|
+
/* @__PURE__ */ jsx13("path", { className: "ss-w-om-line", d: vm.geometry.path, fill: "none" }),
|
|
1218
|
+
vm.geometry.markers.map((m, i) => /* @__PURE__ */ jsx13("circle", { className: "ss-w-om-dot", cx: m.x, cy: m.y, r: 2.5 }, i)),
|
|
1219
|
+
ui?.chartTimeLabel ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
1220
|
+
/* @__PURE__ */ jsx13("text", { className: "ss-w-om-xlab", x: 40, y: CHART_VIEW_H - 8, textAnchor: "start", children: ui.chartTimeLabel(vm.geometry.startMs) }),
|
|
1221
|
+
/* @__PURE__ */ jsx13("text", { className: "ss-w-om-xlab", x: CHART_VIEW_W - 8, y: CHART_VIEW_H - 8, textAnchor: "end", children: ui.chartTimeLabel(vm.geometry.endMs) })
|
|
1222
|
+
] }) : /* @__PURE__ */ jsx13("text", { className: "ss-w-om-xlab", x: 40, y: CHART_VIEW_H - 8, children: ui?.movementWindow ? ui.movementWindow(vm.windowHours) : `Last ${vm.windowHours}h` })
|
|
1162
1223
|
]
|
|
1163
1224
|
}
|
|
1164
1225
|
),
|
|
@@ -1166,66 +1227,66 @@ function OddsMovementCard({ vm, ui }) {
|
|
|
1166
1227
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
1167
1228
|
ui?.openingLabel ?? "Opening",
|
|
1168
1229
|
" ",
|
|
1169
|
-
/* @__PURE__ */
|
|
1230
|
+
/* @__PURE__ */ jsx13("b", { children: vm.opening })
|
|
1170
1231
|
] }),
|
|
1171
1232
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
1172
1233
|
ui?.currentLabel ?? "Current",
|
|
1173
1234
|
" ",
|
|
1174
|
-
/* @__PURE__ */
|
|
1235
|
+
/* @__PURE__ */ jsx13("b", { children: vm.current })
|
|
1175
1236
|
] })
|
|
1176
1237
|
] }),
|
|
1177
|
-
vm.bookmaker ? /* @__PURE__ */
|
|
1178
|
-
vm.excludedCount > 0 ? /* @__PURE__ */
|
|
1179
|
-
vm.isSuspended ? /* @__PURE__ */
|
|
1180
|
-
vm.disclaimer ? /* @__PURE__ */
|
|
1238
|
+
vm.bookmaker ? /* @__PURE__ */ jsx13("div", { className: "ss-w-om-foot", children: /* @__PURE__ */ jsx13("span", { children: vm.bookmaker }) }) : null,
|
|
1239
|
+
vm.excludedCount > 0 ? /* @__PURE__ */ jsx13("div", { className: "ss-w-om-excl", children: ui?.excludedSuspended ? ui.excludedSuspended(vm.excludedCount) : `${vm.excludedCount} suspended price(s) excluded from this chart.` }) : null,
|
|
1240
|
+
vm.isSuspended ? /* @__PURE__ */ jsx13("div", { className: "ss-w-om-susp", children: ui?.selectionSuspended ?? "This selection is not currently available to bet." }) : null,
|
|
1241
|
+
vm.disclaimer ? /* @__PURE__ */ jsx13("div", { className: "ss-w-om-disc", children: vm.disclaimer }) : null
|
|
1181
1242
|
] });
|
|
1182
1243
|
}
|
|
1183
1244
|
function OddsMovementCardList({ cards, ui }) {
|
|
1184
1245
|
if (!cards || cards.length === 0) return null;
|
|
1185
|
-
return /* @__PURE__ */
|
|
1246
|
+
return /* @__PURE__ */ jsx13("div", { className: "ss-w-omcards", children: cards.map((vm) => /* @__PURE__ */ jsx13(OddsMovementCard, { vm, ui }, vm.id)) });
|
|
1186
1247
|
}
|
|
1187
1248
|
|
|
1188
1249
|
// src/components/ActionButtons.tsx
|
|
1189
|
-
import { Fragment as
|
|
1250
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1190
1251
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
1191
1252
|
if (actions.length === 0 && !loading) return null;
|
|
1192
1253
|
return /* @__PURE__ */ jsxs10("div", { className: "ss-w-actions", children: [
|
|
1193
|
-
actions.map((a, i) => /* @__PURE__ */
|
|
1194
|
-
actions.length === 0 && loading ? /* @__PURE__ */ jsxs10(
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1254
|
+
actions.map((a, i) => /* @__PURE__ */ jsx14("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
1255
|
+
actions.length === 0 && loading ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
1256
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-abtn-shimmer" }),
|
|
1257
|
+
/* @__PURE__ */ jsx14("span", { className: "ss-w-abtn-shimmer" })
|
|
1197
1258
|
] }) : null
|
|
1198
1259
|
] });
|
|
1199
1260
|
}
|
|
1200
1261
|
|
|
1201
1262
|
// src/components/dashboard/DashboardTile.tsx
|
|
1202
|
-
import { jsx as
|
|
1263
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1203
1264
|
var MAX_CRESTS = 3;
|
|
1204
1265
|
function DashboardTile({ tile, onTap }) {
|
|
1205
1266
|
const spanClass = tile.span === "full" ? "ss-w-dash-tile--full" : "ss-w-dash-tile--half";
|
|
1206
1267
|
const crests = (tile.imageUrls ?? []).slice(0, MAX_CRESTS);
|
|
1207
1268
|
const hasMeta = Boolean(tile.badgeText) || crests.length > 0;
|
|
1208
1269
|
return /* @__PURE__ */ jsxs11("button", { type: "button", className: `ss-w-dash-tile ${spanClass}`, onClick: onTap, children: [
|
|
1209
|
-
/* @__PURE__ */
|
|
1270
|
+
/* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-icon", children: /* @__PURE__ */ jsx15(DashboardIcon, { name: tile.icon }) }),
|
|
1210
1271
|
/* @__PURE__ */ jsxs11("span", { className: "ss-w-dash-tile-body", children: [
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
tile.subtitle ? /* @__PURE__ */
|
|
1272
|
+
/* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-title", children: tile.title }),
|
|
1273
|
+
tile.subtitle ? /* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-subtitle", children: tile.subtitle }) : null,
|
|
1213
1274
|
hasMeta ? (
|
|
1214
1275
|
// Badge + crests sit on their own row, below the title, instead of sharing the
|
|
1215
1276
|
// icon/chevron row -- at the half-span tile's ~180px width a nowrap badge alone
|
|
1216
1277
|
// (~70px) left the title column at ~22px and forced character-by-character wrapping.
|
|
1217
1278
|
/* @__PURE__ */ jsxs11("span", { className: "ss-w-dash-tile-meta", children: [
|
|
1218
|
-
tile.badgeText ? /* @__PURE__ */
|
|
1219
|
-
crests.length > 0 ? /* @__PURE__ */
|
|
1279
|
+
tile.badgeText ? /* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-badge", children: tile.badgeText }) : null,
|
|
1280
|
+
crests.length > 0 ? /* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-crests", children: crests.map((url, i) => /* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-crest", style: { backgroundImage: `url(${url})` }, "aria-hidden": "true" }, `${url}-${i}`)) }) : null
|
|
1220
1281
|
] })
|
|
1221
1282
|
) : null
|
|
1222
1283
|
] }),
|
|
1223
|
-
/* @__PURE__ */
|
|
1284
|
+
/* @__PURE__ */ jsx15("span", { className: "ss-w-dash-tile-chevron", children: /* @__PURE__ */ jsx15(ChevronIcon, {}) })
|
|
1224
1285
|
] });
|
|
1225
1286
|
}
|
|
1226
1287
|
|
|
1227
1288
|
// src/components/dashboard/GreetingDashboard.tsx
|
|
1228
|
-
import { jsx as
|
|
1289
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1229
1290
|
var LAYOUT_CLASSES = {
|
|
1230
1291
|
market: "ss-w-dash--market",
|
|
1231
1292
|
goal: "ss-w-dash--goal",
|
|
@@ -1237,35 +1298,35 @@ function layoutClass(layout) {
|
|
|
1237
1298
|
function GreetingDashboard({ dashboard, onTap }) {
|
|
1238
1299
|
return /* @__PURE__ */ jsxs12("div", { className: `ss-w-dash ${layoutClass(dashboard.layout)}`, children: [
|
|
1239
1300
|
/* @__PURE__ */ jsxs12("div", { className: "ss-w-dash-head", children: [
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
dashboard.subtitle ? /* @__PURE__ */
|
|
1301
|
+
/* @__PURE__ */ jsx16("span", { className: "ss-w-dash-title", children: dashboard.title }),
|
|
1302
|
+
dashboard.subtitle ? /* @__PURE__ */ jsx16("span", { className: "ss-w-dash-subtitle", children: dashboard.subtitle }) : null
|
|
1242
1303
|
] }),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
dashboard.footerTip ? /* @__PURE__ */
|
|
1304
|
+
/* @__PURE__ */ jsx16("div", { className: "ss-w-dash-grid", children: dashboard.tiles.map((t, i) => /* @__PURE__ */ jsx16(DashboardTile, { tile: t, onTap: () => onTap(t, i) }, `${t.title}-${i}`)) }),
|
|
1305
|
+
dashboard.footerTip ? /* @__PURE__ */ jsx16("span", { className: "ss-w-dash-foot", children: dashboard.footerTip }) : null
|
|
1245
1306
|
] });
|
|
1246
1307
|
}
|
|
1247
1308
|
|
|
1248
1309
|
// src/components/club-dashboard/GreetingHeaderBlock.tsx
|
|
1249
|
-
import { jsx as
|
|
1310
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1250
1311
|
function GreetingHeaderBlock({ block }) {
|
|
1251
1312
|
return /* @__PURE__ */ jsxs13("div", { className: "ss-w-cdash-greeting", children: [
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
/* @__PURE__ */
|
|
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 })
|
|
1254
1315
|
] });
|
|
1255
1316
|
}
|
|
1256
1317
|
|
|
1257
1318
|
// src/components/club-dashboard/FixtureHeroBlock.tsx
|
|
1258
|
-
import { useState as
|
|
1259
|
-
import { jsx as
|
|
1319
|
+
import { useState as useState6 } from "react";
|
|
1320
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1260
1321
|
function initials3(name) {
|
|
1261
1322
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
|
|
1262
1323
|
}
|
|
1263
1324
|
function Crest3({ url, name }) {
|
|
1264
|
-
const [broken, setBroken] =
|
|
1325
|
+
const [broken, setBroken] = useState6(false);
|
|
1265
1326
|
if (!url || broken) {
|
|
1266
|
-
return /* @__PURE__ */
|
|
1327
|
+
return /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials3(name) });
|
|
1267
1328
|
}
|
|
1268
|
-
return /* @__PURE__ */
|
|
1329
|
+
return /* @__PURE__ */ jsx18("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
|
|
1269
1330
|
}
|
|
1270
1331
|
function FixtureHeroBlock({
|
|
1271
1332
|
block,
|
|
@@ -1274,36 +1335,36 @@ function FixtureHeroBlock({
|
|
|
1274
1335
|
}) {
|
|
1275
1336
|
return /* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture", children: [
|
|
1276
1337
|
/* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-tie", children: [
|
|
1277
|
-
/* @__PURE__ */
|
|
1278
|
-
/* @__PURE__ */
|
|
1279
|
-
/* @__PURE__ */
|
|
1280
|
-
/* @__PURE__ */
|
|
1281
|
-
/* @__PURE__ */
|
|
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 })
|
|
1282
1343
|
] }),
|
|
1283
1344
|
/* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture-meta", children: [
|
|
1284
|
-
/* @__PURE__ */
|
|
1285
|
-
block.venue ? /* @__PURE__ */
|
|
1286
|
-
block.competition ? /* @__PURE__ */
|
|
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
|
|
1287
1348
|
] }),
|
|
1288
|
-
/* @__PURE__ */
|
|
1349
|
+
/* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
|
|
1289
1350
|
] });
|
|
1290
1351
|
}
|
|
1291
1352
|
|
|
1292
1353
|
// src/components/club-dashboard/FormGuideBlock.tsx
|
|
1293
|
-
import { jsx as
|
|
1354
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1294
1355
|
function FormGuideBlock({ block }) {
|
|
1295
1356
|
if (block.rows.length === 0) return null;
|
|
1296
|
-
return /* @__PURE__ */
|
|
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: [
|
|
1297
1358
|
/* @__PURE__ */ jsxs15("span", { className: "ss-w-cdash-form-name", children: [
|
|
1298
1359
|
row.name,
|
|
1299
1360
|
row.position != null ? ` #${row.position}` : ""
|
|
1300
1361
|
] }),
|
|
1301
|
-
/* @__PURE__ */
|
|
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)) })
|
|
1302
1363
|
] }, row.name)) });
|
|
1303
1364
|
}
|
|
1304
1365
|
|
|
1305
1366
|
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1306
|
-
import { jsx as
|
|
1367
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1307
1368
|
function MatchPreviewBlock({
|
|
1308
1369
|
block,
|
|
1309
1370
|
ui,
|
|
@@ -1312,14 +1373,14 @@ function MatchPreviewBlock({
|
|
|
1312
1373
|
if (block.facts.length === 0) return null;
|
|
1313
1374
|
const heading = ui.clubMatchPreviewHeading;
|
|
1314
1375
|
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-cdash-lines", children: [
|
|
1315
|
-
/* @__PURE__ */
|
|
1376
|
+
/* @__PURE__ */ jsx20("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1316
1377
|
block.facts.map(
|
|
1317
|
-
(f, i) => f.
|
|
1378
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs16(
|
|
1318
1379
|
"button",
|
|
1319
1380
|
{
|
|
1320
1381
|
type: "button",
|
|
1321
1382
|
className: "ss-w-cdash-fact",
|
|
1322
|
-
onClick: () => onAction(f.
|
|
1383
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1323
1384
|
children: [
|
|
1324
1385
|
f.sentence,
|
|
1325
1386
|
f.label ? /* @__PURE__ */ jsxs16("span", { className: "ss-w-cdash-fact-label", children: [
|
|
@@ -1329,13 +1390,13 @@ function MatchPreviewBlock({
|
|
|
1329
1390
|
]
|
|
1330
1391
|
},
|
|
1331
1392
|
i
|
|
1332
|
-
) : /* @__PURE__ */
|
|
1393
|
+
) : /* @__PURE__ */ jsx20("p", { children: f.sentence }, i)
|
|
1333
1394
|
)
|
|
1334
1395
|
] });
|
|
1335
1396
|
}
|
|
1336
1397
|
|
|
1337
1398
|
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1338
|
-
import { jsx as
|
|
1399
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1339
1400
|
function TeamDnaBlock({
|
|
1340
1401
|
block,
|
|
1341
1402
|
ui,
|
|
@@ -1344,14 +1405,14 @@ function TeamDnaBlock({
|
|
|
1344
1405
|
if (block.facts.length === 0) return null;
|
|
1345
1406
|
const heading = ui.clubTeamDnaHeading;
|
|
1346
1407
|
return /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-lines", children: [
|
|
1347
|
-
/* @__PURE__ */
|
|
1408
|
+
/* @__PURE__ */ jsx21("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1348
1409
|
block.facts.map(
|
|
1349
|
-
(f, i) => f.
|
|
1410
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs17(
|
|
1350
1411
|
"button",
|
|
1351
1412
|
{
|
|
1352
1413
|
type: "button",
|
|
1353
1414
|
className: "ss-w-cdash-fact",
|
|
1354
|
-
onClick: () => onAction(f.
|
|
1415
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1355
1416
|
children: [
|
|
1356
1417
|
f.sentence,
|
|
1357
1418
|
f.label ? /* @__PURE__ */ jsxs17("span", { className: "ss-w-cdash-fact-label", children: [
|
|
@@ -1361,14 +1422,14 @@ function TeamDnaBlock({
|
|
|
1361
1422
|
]
|
|
1362
1423
|
},
|
|
1363
1424
|
i
|
|
1364
|
-
) : /* @__PURE__ */
|
|
1425
|
+
) : /* @__PURE__ */ jsx21("p", { children: f.sentence }, i)
|
|
1365
1426
|
)
|
|
1366
1427
|
] });
|
|
1367
1428
|
}
|
|
1368
1429
|
|
|
1369
1430
|
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1370
|
-
import { useEffect as useEffect3, useState as
|
|
1371
|
-
import { jsx as
|
|
1431
|
+
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
1432
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1372
1433
|
var DAY_MS = 24 * 3600 * 1e3;
|
|
1373
1434
|
function pad2(n) {
|
|
1374
1435
|
return String(n).padStart(2, "0");
|
|
@@ -1381,7 +1442,7 @@ function splitRemaining(remainingMs) {
|
|
|
1381
1442
|
return { h: pad2(h), m: pad2(m), s: pad2(s) };
|
|
1382
1443
|
}
|
|
1383
1444
|
function CountdownBlock({ block, ui }) {
|
|
1384
|
-
const [remainingMs, setRemainingMs] =
|
|
1445
|
+
const [remainingMs, setRemainingMs] = useState7(() => block.kickoffUnix * 1e3 - Date.now());
|
|
1385
1446
|
useEffect3(() => {
|
|
1386
1447
|
setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
|
|
1387
1448
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
@@ -1395,28 +1456,28 @@ function CountdownBlock({ block, ui }) {
|
|
|
1395
1456
|
const { h, m, s } = splitRemaining(remainingMs);
|
|
1396
1457
|
return /* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
|
|
1397
1458
|
/* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
|
|
1398
|
-
/* @__PURE__ */
|
|
1459
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-h", children: h }),
|
|
1399
1460
|
"h",
|
|
1400
1461
|
" ",
|
|
1401
|
-
/* @__PURE__ */
|
|
1462
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1402
1463
|
"m",
|
|
1403
1464
|
" ",
|
|
1404
|
-
/* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1405
1466
|
"s"
|
|
1406
1467
|
] }),
|
|
1407
|
-
/* @__PURE__ */
|
|
1468
|
+
/* @__PURE__ */ jsx22("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1408
1469
|
] });
|
|
1409
1470
|
}
|
|
1410
1471
|
|
|
1411
1472
|
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1412
|
-
import { jsx as
|
|
1473
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1413
1474
|
var CLUB_BLOCK_REGISTRY = {
|
|
1414
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */
|
|
1415
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */
|
|
1416
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */
|
|
1417
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */
|
|
1418
|
-
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */
|
|
1419
|
-
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */
|
|
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
|
|
1420
1481
|
};
|
|
1421
1482
|
function ClubDashboard({
|
|
1422
1483
|
dashboard,
|
|
@@ -1424,39 +1485,39 @@ function ClubDashboard({
|
|
|
1424
1485
|
onAction
|
|
1425
1486
|
}) {
|
|
1426
1487
|
if (!dashboard.blocks.length) return null;
|
|
1427
|
-
return /* @__PURE__ */
|
|
1488
|
+
return /* @__PURE__ */ jsx23("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1428
1489
|
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1429
1490
|
if (!Comp) {
|
|
1430
1491
|
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1431
1492
|
return null;
|
|
1432
1493
|
}
|
|
1433
|
-
return /* @__PURE__ */
|
|
1494
|
+
return /* @__PURE__ */ jsx23("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ jsx23(Comp, { block, ui, onAction }) }, i);
|
|
1434
1495
|
}) });
|
|
1435
1496
|
}
|
|
1436
1497
|
|
|
1437
1498
|
// src/components/ChatMessage.tsx
|
|
1438
|
-
import { jsx as
|
|
1499
|
+
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1439
1500
|
function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
|
|
1440
1501
|
if (message.role === "user") {
|
|
1441
|
-
return /* @__PURE__ */
|
|
1502
|
+
return /* @__PURE__ */ jsx24("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx24("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1442
1503
|
}
|
|
1443
1504
|
return /* @__PURE__ */ jsxs19("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1444
|
-
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */
|
|
1445
|
-
message.greetingDashboard ? /* @__PURE__ */
|
|
1446
|
-
message.clubDashboard && ui ? /* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1451
|
-
/* @__PURE__ */
|
|
1505
|
+
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ jsx24(Markdown, { text: message.text }) : null,
|
|
1506
|
+
message.greetingDashboard ? /* @__PURE__ */ jsx24(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1507
|
+
message.clubDashboard && ui ? /* @__PURE__ */ jsx24(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
|
|
1508
|
+
/* @__PURE__ */ jsx24(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1509
|
+
/* @__PURE__ */ jsx24(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1510
|
+
/* @__PURE__ */ jsx24(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1511
|
+
/* @__PURE__ */ jsx24(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1512
|
+
/* @__PURE__ */ jsx24(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1452
1513
|
] });
|
|
1453
1514
|
}
|
|
1454
1515
|
|
|
1455
1516
|
// src/components/IntentChips.tsx
|
|
1456
|
-
import { jsx as
|
|
1517
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1457
1518
|
function IntentChips({ chips, onPick }) {
|
|
1458
1519
|
if (chips.length === 0) return null;
|
|
1459
|
-
return /* @__PURE__ */
|
|
1520
|
+
return /* @__PURE__ */ jsx25("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx25("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1460
1521
|
}
|
|
1461
1522
|
|
|
1462
1523
|
// src/scroll.ts
|
|
@@ -1466,7 +1527,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1466
1527
|
}
|
|
1467
1528
|
|
|
1468
1529
|
// src/components/MessageList.tsx
|
|
1469
|
-
import { jsx as
|
|
1530
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1470
1531
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1471
1532
|
const { state, send } = controller;
|
|
1472
1533
|
const listRef = useRef2(null);
|
|
@@ -1487,7 +1548,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1487
1548
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1488
1549
|
},
|
|
1489
1550
|
children: [
|
|
1490
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
1551
|
+
state.messages.map((m) => /* @__PURE__ */ jsx26(
|
|
1491
1552
|
ChatMessage,
|
|
1492
1553
|
{
|
|
1493
1554
|
message: m,
|
|
@@ -1497,31 +1558,31 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1497
1558
|
send(tile.actionValue, { displayText: tile.title });
|
|
1498
1559
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1499
1560
|
},
|
|
1500
|
-
onClubAction: (
|
|
1561
|
+
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1501
1562
|
ui,
|
|
1502
1563
|
slip
|
|
1503
1564
|
},
|
|
1504
1565
|
m.id
|
|
1505
1566
|
)),
|
|
1506
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
1567
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx26(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1507
1568
|
} }) : null,
|
|
1508
|
-
state.status ? /* @__PURE__ */
|
|
1569
|
+
state.status ? /* @__PURE__ */ jsx26("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1509
1570
|
state.error ? /* @__PURE__ */ jsxs20("div", { className: "ss-w-error", role: "alert", children: [
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1571
|
+
/* @__PURE__ */ jsx26("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1572
|
+
/* @__PURE__ */ jsx26("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1512
1573
|
] }) : null,
|
|
1513
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */
|
|
1514
|
-
/* @__PURE__ */
|
|
1574
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx26(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1575
|
+
/* @__PURE__ */ jsx26("div", { ref: endRef })
|
|
1515
1576
|
]
|
|
1516
1577
|
}
|
|
1517
1578
|
);
|
|
1518
1579
|
}
|
|
1519
1580
|
|
|
1520
1581
|
// src/components/ChatInput.tsx
|
|
1521
|
-
import { useState as
|
|
1522
|
-
import { jsx as
|
|
1582
|
+
import { useState as useState8 } from "react";
|
|
1583
|
+
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1523
1584
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1524
|
-
const [value, setValue] =
|
|
1585
|
+
const [value, setValue] = useState8("");
|
|
1525
1586
|
const submit = () => {
|
|
1526
1587
|
const t = value.trim();
|
|
1527
1588
|
if (!t) return;
|
|
@@ -1535,16 +1596,16 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1535
1596
|
}
|
|
1536
1597
|
};
|
|
1537
1598
|
return /* @__PURE__ */ jsxs21("div", { className: "ss-w-input", children: [
|
|
1538
|
-
/* @__PURE__ */
|
|
1539
|
-
streaming ? /* @__PURE__ */
|
|
1599
|
+
/* @__PURE__ */ jsx27("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1600
|
+
streaming ? /* @__PURE__ */ jsx27("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx27("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx27("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx27(SendIcon, {}) })
|
|
1540
1601
|
] });
|
|
1541
1602
|
}
|
|
1542
1603
|
|
|
1543
1604
|
// src/components/ChatPanel.tsx
|
|
1544
|
-
import { jsx as
|
|
1605
|
+
import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1545
1606
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1546
1607
|
function useIsModal() {
|
|
1547
|
-
const [modal, setModal] =
|
|
1608
|
+
const [modal, setModal] = useState9(false);
|
|
1548
1609
|
useEffect5(() => {
|
|
1549
1610
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1550
1611
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
@@ -1566,9 +1627,9 @@ function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
|
1566
1627
|
return () => window.removeEventListener("keydown", onKey);
|
|
1567
1628
|
}, [close]);
|
|
1568
1629
|
return /* @__PURE__ */ jsxs22("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1569
|
-
/* @__PURE__ */
|
|
1570
|
-
/* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
1630
|
+
/* @__PURE__ */ jsx28(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1631
|
+
/* @__PURE__ */ jsx28(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1632
|
+
/* @__PURE__ */ jsx28(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1572
1633
|
] });
|
|
1573
1634
|
}
|
|
1574
1635
|
|
|
@@ -1616,7 +1677,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1616
1677
|
.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; }
|
|
1617
1678
|
|
|
1618
1679
|
/* panel */
|
|
1619
|
-
.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(
|
|
1680
|
+
.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); }
|
|
1620
1681
|
.ss-w-root[data-ss-w-pos="right"] .ss-w-panel { right: var(--ss-w-offset-x); }
|
|
1621
1682
|
.ss-w-root[data-ss-w-pos="left"] .ss-w-panel { left: var(--ss-w-offset-x); }
|
|
1622
1683
|
@media (max-width: 639px) {
|
|
@@ -1719,9 +1780,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1719
1780
|
.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; }
|
|
1720
1781
|
|
|
1721
1782
|
/* crests -- CSS background-image on a span, never <img> (matches .ss-w-ecard-crest precedent) */
|
|
1722
|
-
.ss-w-bi-comp-logo { width:
|
|
1723
|
-
.ss-w-bi-crest { width:
|
|
1724
|
-
.ss-w-bi-crest-mono { display: grid; place-items: center; font-size:
|
|
1783
|
+
.ss-w-bi-comp-logo { width: 16px; height: 16px; flex: none; display: block; border-radius: 50%; object-fit: contain; }
|
|
1784
|
+
.ss-w-bi-crest { width: 24px; height: 24px; flex: none; display: block; border-radius: 50%; object-fit: contain; }
|
|
1785
|
+
.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)); }
|
|
1725
1786
|
|
|
1726
1787
|
/* row 2: crest-flanked fixture on the left, boxed action panel on the right */
|
|
1727
1788
|
.ss-w-bi-body { display: flex; align-items: center; gap: 10px; }
|
|
@@ -1729,16 +1790,16 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1729
1790
|
.ss-w-bi-team { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1730
1791
|
.ss-w-bi-vs { font-size: 10px; font-weight: 600; color: var(--ss-w-faint); flex: none; }
|
|
1731
1792
|
.ss-w-bi-fixture-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1732
|
-
.ss-w-bi-action { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items:
|
|
1733
|
-
.ss-w-bi-action .ss-w-slip
|
|
1793
|
+
.ss-w-bi-action { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; min-width: 0; }
|
|
1794
|
+
.ss-w-bi-action .ss-w-slip { width: 100%; }
|
|
1795
|
+
.ss-w-bi-action .ss-w-slip > button { flex: 1; width: 100%; text-align: center; border-radius: 8px; }
|
|
1734
1796
|
/* 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. */
|
|
1735
1797
|
.ss-w-bi-action .ss-w-toast { left: auto; right: 0; width: max-content; max-width: 210px; white-space: normal; }
|
|
1736
|
-
.ss-w-bi-mkt { display: flex; flex-direction: column; gap:
|
|
1737
|
-
.ss-w-bi-market { font-size:
|
|
1738
|
-
.ss-w-bi-sel { font-size:
|
|
1739
|
-
.ss-w-bi-odds { flex: none; display: flex;
|
|
1740
|
-
.ss-w-bi-odds
|
|
1741
|
-
.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; }
|
|
1798
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; gap: 1px; min-width: 0; align-items: flex-end; text-align: right; }
|
|
1799
|
+
.ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.2; color: var(--ss-w-faint); white-space: nowrap; }
|
|
1800
|
+
.ss-w-bi-sel { font-size: 11px; line-height: 1.25; color: var(--ss-w-faint); }
|
|
1801
|
+
.ss-w-bi-odds { flex: none; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }
|
|
1802
|
+
.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; }
|
|
1742
1803
|
.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }
|
|
1743
1804
|
|
|
1744
1805
|
/* row 3: bar-chart glyph + reasoning prose + stats-expander chevron, in a subtle strip */
|
|
@@ -1752,11 +1813,11 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1752
1813
|
}
|
|
1753
1814
|
.ss-w-bi-reason-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex: 1; }
|
|
1754
1815
|
.ss-w-bi-text { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); }
|
|
1755
|
-
.ss-w-bi-
|
|
1756
|
-
.ss-w-bi-
|
|
1757
|
-
.ss-w-bi-
|
|
1758
|
-
.ss-w-bi-
|
|
1759
|
-
.ss-w-bi-
|
|
1816
|
+
.ss-w-bi-text-clamp { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
1817
|
+
.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; }
|
|
1818
|
+
.ss-w-bi-expand:hover { color: var(--ss-w-ink); }
|
|
1819
|
+
.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; }
|
|
1820
|
+
.ss-w-bi-arrow-open { transform: rotate(135deg); }
|
|
1760
1821
|
.ss-w-bi-rows { display: flex; flex-direction: column; }
|
|
1761
1822
|
.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); }
|
|
1762
1823
|
.ss-w-bi-row:first-child { border-top: none; }
|
|
@@ -1771,11 +1832,13 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1771
1832
|
/* market odds card */
|
|
1772
1833
|
.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }
|
|
1773
1834
|
.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; }
|
|
1774
|
-
.ss-w-mo-
|
|
1775
|
-
.ss-w-mo-
|
|
1776
|
-
.ss-w-mo-
|
|
1777
|
-
.ss-w-mo-
|
|
1778
|
-
.ss-w-mo-
|
|
1835
|
+
.ss-w-mo-sub { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
|
|
1836
|
+
.ss-w-mo-teams { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1837
|
+
.ss-w-mo-market { font-size: 11.5px; font-weight: 600; color: var(--ss-w-faint); }
|
|
1838
|
+
.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; }
|
|
1839
|
+
.ss-w-mo-more:hover { text-decoration: underline; }
|
|
1840
|
+
.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; }
|
|
1841
|
+
.ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }
|
|
1779
1842
|
.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
1780
1843
|
.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
|
|
1781
1844
|
.ss-w-mo-row:last-child { border-bottom: none; }
|
|
@@ -1961,7 +2024,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1961
2024
|
`;
|
|
1962
2025
|
|
|
1963
2026
|
// src/StatsWidget.tsx
|
|
1964
|
-
import { jsx as
|
|
2027
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1965
2028
|
function buildClient(props) {
|
|
1966
2029
|
try {
|
|
1967
2030
|
if ("client" in props && props.client) {
|
|
@@ -2014,7 +2077,7 @@ function StatsWidget(props) {
|
|
|
2014
2077
|
}, [built, ui.injectStyles]);
|
|
2015
2078
|
if (!built) return null;
|
|
2016
2079
|
const attrs = themeAttrs(ui);
|
|
2017
|
-
return /* @__PURE__ */
|
|
2080
|
+
return /* @__PURE__ */ jsx29("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__ */ jsx29(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx29(
|
|
2018
2081
|
ChatFab,
|
|
2019
2082
|
{
|
|
2020
2083
|
label: ui.launcherLabel,
|