@sensiblestats/widget-react 0.28.0 → 0.29.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 +50 -0
- package/dist/index.cjs +472 -135
- 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 +471 -134
- package/dist/index.js.map +1 -1
- package/dist/styles.css +82 -22
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/StatsWidget.tsx
|
|
39
|
-
var
|
|
39
|
+
var import_react17 = require("react");
|
|
40
40
|
var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/kickoff.ts
|
|
@@ -608,7 +608,14 @@ function reducer(state, action) {
|
|
|
608
608
|
return {
|
|
609
609
|
...state,
|
|
610
610
|
messages: state.messages.map(
|
|
611
|
-
(m) => m.role === "assistant" && m.id === action.messageId && m.clubFanDashboard ? { ...m, clubFanDashboard: { ...m.clubFanDashboard, cards: action.cards } } : m
|
|
611
|
+
(m) => m.role === "assistant" && m.id === action.messageId && m.clubFanDashboard ? { ...m, clubFanDashboard: { ...m.clubFanDashboard, cards: action.cards, greeting: action.greeting ?? m.clubFanDashboard.greeting } } : m
|
|
612
|
+
)
|
|
613
|
+
};
|
|
614
|
+
case "LIVE_TRANSITION":
|
|
615
|
+
return {
|
|
616
|
+
...state,
|
|
617
|
+
messages: state.messages.map(
|
|
618
|
+
(m) => m.role === "assistant" && m.id === action.messageId && m.clubFanDashboard ? { ...m, clubFanDashboard: action.dashboard } : m
|
|
612
619
|
)
|
|
613
620
|
};
|
|
614
621
|
}
|
|
@@ -617,26 +624,74 @@ function reducer(state, action) {
|
|
|
617
624
|
// src/useLiveDashboardPoll.ts
|
|
618
625
|
var import_react = require("react");
|
|
619
626
|
var POLL_INTERVAL_MS = 6e4;
|
|
620
|
-
|
|
627
|
+
var LEAD_MS = 12e4;
|
|
628
|
+
var GIVE_UP_MS = 30 * 6e4;
|
|
629
|
+
function extractKickoffMs(dashboard) {
|
|
630
|
+
const countdown = dashboard.cards.find((c) => c.cardType === "countdown");
|
|
631
|
+
if (countdown) return countdown.data.kickoffUnix * 1e3;
|
|
632
|
+
for (const c of dashboard.cards) {
|
|
633
|
+
const d = c.data;
|
|
634
|
+
if (typeof d?.kickoffUnix === "number") return d.kickoffUnix * 1e3;
|
|
635
|
+
}
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
function findAnchor(messages) {
|
|
639
|
+
const now = Date.now();
|
|
621
640
|
for (const m of messages.slice().reverse()) {
|
|
622
|
-
if (m.role
|
|
641
|
+
if (m.role !== "assistant" || !m.clubFanDashboard) continue;
|
|
642
|
+
const { phase } = m.clubFanDashboard;
|
|
643
|
+
if (phase === "live") return { messageId: m.id, kind: "live" };
|
|
644
|
+
if (phase === "preMatch") {
|
|
645
|
+
const kickoffMs = extractKickoffMs(m.clubFanDashboard);
|
|
646
|
+
if (kickoffMs === null) continue;
|
|
647
|
+
if (now >= kickoffMs - LEAD_MS && now <= kickoffMs + GIVE_UP_MS) {
|
|
648
|
+
return { messageId: m.id, kind: "preMatch", kickoffMs };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
623
651
|
}
|
|
624
652
|
return null;
|
|
625
653
|
}
|
|
654
|
+
function findEarliestWakeupMs(messages) {
|
|
655
|
+
const now = Date.now();
|
|
656
|
+
let earliest = null;
|
|
657
|
+
for (const m of messages) {
|
|
658
|
+
if (m.role !== "assistant" || m.clubFanDashboard?.phase !== "preMatch") continue;
|
|
659
|
+
const kickoffMs = extractKickoffMs(m.clubFanDashboard);
|
|
660
|
+
if (kickoffMs === null) continue;
|
|
661
|
+
const wakeAt = kickoffMs - LEAD_MS;
|
|
662
|
+
if (wakeAt > now && (earliest === null || wakeAt < earliest)) earliest = wakeAt;
|
|
663
|
+
}
|
|
664
|
+
return earliest;
|
|
665
|
+
}
|
|
626
666
|
function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
627
|
-
const
|
|
667
|
+
const [, forceUpdate] = (0, import_react.useReducer)((x) => x + 1, 0);
|
|
668
|
+
const anchor = findAnchor(messages);
|
|
669
|
+
const anchorRef = (0, import_react.useRef)(anchor);
|
|
670
|
+
anchorRef.current = anchor;
|
|
628
671
|
const inFlightRef = (0, import_react.useRef)(false);
|
|
672
|
+
const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null;
|
|
629
673
|
(0, import_react.useEffect)(() => {
|
|
630
|
-
if (!
|
|
674
|
+
if (!anchorKey || !anchorRef.current) return;
|
|
631
675
|
const tick = async () => {
|
|
632
676
|
if (inFlightRef.current) return;
|
|
633
677
|
inFlightRef.current = true;
|
|
634
678
|
try {
|
|
635
679
|
const payload = await getLiveDashboard();
|
|
636
|
-
|
|
637
|
-
|
|
680
|
+
const current = anchorRef.current;
|
|
681
|
+
if (!current) return;
|
|
682
|
+
if (payload?.phase === "live") {
|
|
683
|
+
if (current.kind === "preMatch") {
|
|
684
|
+
dispatch({ kind: "LIVE_TRANSITION", messageId: current.messageId, dashboard: payload });
|
|
685
|
+
window.clearInterval(id);
|
|
686
|
+
} else {
|
|
687
|
+
dispatch({ kind: "LIVE_REFRESH", messageId: current.messageId, cards: payload.cards, greeting: payload.greeting });
|
|
688
|
+
}
|
|
638
689
|
} else {
|
|
639
|
-
|
|
690
|
+
if (current.kind === "live") {
|
|
691
|
+
window.clearInterval(id);
|
|
692
|
+
} else if (Date.now() > current.kickoffMs + GIVE_UP_MS) {
|
|
693
|
+
window.clearInterval(id);
|
|
694
|
+
}
|
|
640
695
|
}
|
|
641
696
|
} catch {
|
|
642
697
|
} finally {
|
|
@@ -647,7 +702,16 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
|
647
702
|
void tick();
|
|
648
703
|
}, POLL_INTERVAL_MS);
|
|
649
704
|
return () => window.clearInterval(id);
|
|
650
|
-
}, [
|
|
705
|
+
}, [anchorKey, dispatch, getLiveDashboard]);
|
|
706
|
+
(0, import_react.useEffect)(() => {
|
|
707
|
+
if (anchorKey !== null) return;
|
|
708
|
+
const wakeAt = findEarliestWakeupMs(messages);
|
|
709
|
+
if (wakeAt === null) return;
|
|
710
|
+
const delay = wakeAt - Date.now();
|
|
711
|
+
if (delay <= 0) return;
|
|
712
|
+
const id = window.setTimeout(forceUpdate, delay);
|
|
713
|
+
return () => window.clearTimeout(id);
|
|
714
|
+
}, [anchorKey, messages, forceUpdate]);
|
|
651
715
|
}
|
|
652
716
|
|
|
653
717
|
// src/useChatStream.ts
|
|
@@ -812,7 +876,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
812
876
|
}
|
|
813
877
|
|
|
814
878
|
// src/components/ChatPanel.tsx
|
|
815
|
-
var
|
|
879
|
+
var import_react16 = require("react");
|
|
816
880
|
|
|
817
881
|
// src/components/ChatHeader.tsx
|
|
818
882
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -825,7 +889,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
825
889
|
}
|
|
826
890
|
|
|
827
891
|
// src/components/MessageList.tsx
|
|
828
|
-
var
|
|
892
|
+
var import_react14 = require("react");
|
|
829
893
|
|
|
830
894
|
// src/components/Markdown.tsx
|
|
831
895
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -1755,139 +1819,352 @@ function RestingFormCard({ card }) {
|
|
|
1755
1819
|
] });
|
|
1756
1820
|
}
|
|
1757
1821
|
|
|
1822
|
+
// src/components/dashboard/LiveScoreCard.tsx
|
|
1823
|
+
var import_react11 = require("react");
|
|
1824
|
+
|
|
1825
|
+
// src/useLiveClock.ts
|
|
1826
|
+
var import_react10 = require("react");
|
|
1827
|
+
var TICK_MS = 6e4;
|
|
1828
|
+
var MAX_LIVE_TICK_MINUTES = 15;
|
|
1829
|
+
function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
1830
|
+
if (!clockRunning) return minute;
|
|
1831
|
+
const elapsedMinutes = Math.floor((Date.now() - receivedAtMs) / TICK_MS);
|
|
1832
|
+
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
1833
|
+
}
|
|
1834
|
+
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
1835
|
+
const [displayMinute, setDisplayMinute] = (0, import_react10.useState)(
|
|
1836
|
+
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
1837
|
+
);
|
|
1838
|
+
(0, import_react10.useEffect)(() => {
|
|
1839
|
+
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
1840
|
+
if (!clockRunning) return;
|
|
1841
|
+
const id = window.setInterval(() => {
|
|
1842
|
+
setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
|
|
1843
|
+
}, TICK_MS);
|
|
1844
|
+
return () => window.clearInterval(id);
|
|
1845
|
+
}, [minute, clockRunning, receivedAtMs]);
|
|
1846
|
+
return displayMinute;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1758
1849
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
1759
1850
|
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1760
|
-
function
|
|
1851
|
+
function initials3(name) {
|
|
1852
|
+
return name.trim().slice(0, 3).toUpperCase();
|
|
1853
|
+
}
|
|
1854
|
+
function LiveCrest({ url, name, side }) {
|
|
1855
|
+
const [failed, setFailed] = (0, import_react11.useState)(false);
|
|
1856
|
+
const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
|
|
1857
|
+
if (url && !failed) {
|
|
1858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
|
|
1859
|
+
}
|
|
1860
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: `${cls} ss-w-fandash-live-crest--fallback`, "aria-hidden": "true", children: initials3(name) });
|
|
1861
|
+
}
|
|
1862
|
+
function scorersLine(goalEvents) {
|
|
1863
|
+
if (!goalEvents || goalEvents.length === 0) return null;
|
|
1864
|
+
const named = goalEvents.filter((e) => e.type === "goal" && e.player);
|
|
1865
|
+
if (named.length === 0) return null;
|
|
1866
|
+
return named.slice().sort((a, b) => a.minute - b.minute).map((e) => `${e.player} ${e.minuteLabel}`).join(", ");
|
|
1867
|
+
}
|
|
1868
|
+
function LiveScoreCard({
|
|
1869
|
+
card,
|
|
1870
|
+
goalEvents
|
|
1871
|
+
}) {
|
|
1761
1872
|
const { data } = card;
|
|
1873
|
+
const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
|
|
1874
|
+
const seedRef = (0, import_react11.useRef)(null);
|
|
1875
|
+
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
1876
|
+
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
1877
|
+
}
|
|
1878
|
+
const displayMinute = useLiveClock(data.minute, data.clockRunning, seedRef.current.receivedAtMs);
|
|
1879
|
+
const minuteSuffix = data.minuteLabel.replace(/^\d+/, "");
|
|
1880
|
+
const scorers = scorersLine(goalEvents);
|
|
1762
1881
|
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-score", children: [
|
|
1763
1882
|
card.title ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1764
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-
|
|
1765
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-
|
|
1770
|
-
] }),
|
|
1771
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-meta", children: [
|
|
1772
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-minute", children: data.minuteLabel }),
|
|
1773
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-status", children: data.statusLabel }),
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-top", children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "ss-w-fandash-live-pill", children: [
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
|
|
1886
|
+
data.statusLabel
|
|
1887
|
+
] }),
|
|
1888
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-minute", children: `${displayMinute}${minuteSuffix}` }),
|
|
1774
1889
|
data.competition ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-competition", children: data.competition }) : null
|
|
1775
|
-
] })
|
|
1890
|
+
] }),
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-main", children: [
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-side ss-w-fandash-live-side--home", children: [
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(LiveCrest, { url: data.homeCrestUrl, name: data.homeName, side: "home" }),
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-team-name", children: data.homeName })
|
|
1895
|
+
] }),
|
|
1896
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-score-main", children: [
|
|
1897
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-score-value", children: data.homeScore }),
|
|
1898
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-score-sep", children: "\u2013" }),
|
|
1899
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-score-value", children: data.awayScore })
|
|
1900
|
+
] }),
|
|
1901
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-side ss-w-fandash-live-side--away", children: [
|
|
1902
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(LiveCrest, { url: data.awayCrestUrl, name: data.awayName, side: "away" }),
|
|
1903
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-team-name", children: data.awayName })
|
|
1904
|
+
] })
|
|
1905
|
+
] }),
|
|
1906
|
+
scorers ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-scorers", children: [
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-scorers-icon", "aria-hidden": "true", children: "\u26BD" }),
|
|
1908
|
+
scorers
|
|
1909
|
+
] }) : null
|
|
1776
1910
|
] });
|
|
1777
1911
|
}
|
|
1778
1912
|
|
|
1779
1913
|
// src/components/dashboard/LiveTimelineCard.tsx
|
|
1914
|
+
var import_react12 = require("react");
|
|
1780
1915
|
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1781
|
-
|
|
1916
|
+
var SHOWN = 3;
|
|
1917
|
+
function EventIcon({ type }) {
|
|
1918
|
+
if (type === "goal") {
|
|
1919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-ico ss-w-fandash-live-tl-ico--goal", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-ball" }) });
|
|
1920
|
+
}
|
|
1921
|
+
if (type === "yellow" || type === "red") {
|
|
1922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-ico", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: `ss-w-fandash-live-tl-card ss-w-fandash-live-tl-card--${type}` }) });
|
|
1923
|
+
}
|
|
1924
|
+
if (type === "sub") {
|
|
1925
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-ico", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-subarrows", children: "\u21C5" }) });
|
|
1926
|
+
}
|
|
1927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-ico", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-dot" }) });
|
|
1928
|
+
}
|
|
1929
|
+
function EventLabel({ e }) {
|
|
1930
|
+
if (e.type === "sub") {
|
|
1931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ss-w-fandash-live-tl-who", children: [
|
|
1932
|
+
e.player ?? e.text,
|
|
1933
|
+
e.playerOff ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ss-w-fandash-live-tl-off", children: [
|
|
1934
|
+
" for ",
|
|
1935
|
+
e.playerOff
|
|
1936
|
+
] }) : null
|
|
1937
|
+
] });
|
|
1938
|
+
}
|
|
1939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-who", children: e.player ?? e.text });
|
|
1940
|
+
}
|
|
1941
|
+
function EventRow({ e }) {
|
|
1942
|
+
const cls = [
|
|
1943
|
+
"ss-w-fandash-live-tl-ev",
|
|
1944
|
+
e.side === "home" ? "ss-w-fandash-live-tl-ev--home" : "ss-w-fandash-live-tl-ev--away",
|
|
1945
|
+
e.type === "goal" ? "ss-w-fandash-live-tl-ev--goal" : ""
|
|
1946
|
+
].filter(Boolean).join(" ");
|
|
1947
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cls, children: [
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ss-w-fandash-live-tl-txt", children: [
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(EventLabel, { e }),
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(EventIcon, { type: e.type })
|
|
1951
|
+
] }),
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-tl-badge", children: e.minuteLabel })
|
|
1953
|
+
] });
|
|
1954
|
+
}
|
|
1955
|
+
function LiveTimelineCard({ card, ui }) {
|
|
1956
|
+
const [expanded, setExpanded] = (0, import_react12.useState)(false);
|
|
1957
|
+
const events = card.data.events;
|
|
1958
|
+
if (!events || events.length === 0) return null;
|
|
1959
|
+
const sorted = [...events].sort((a, b) => b.minute - a.minute);
|
|
1960
|
+
const rest = sorted.length - SHOWN;
|
|
1961
|
+
const shown = expanded ? sorted : sorted.slice(0, SHOWN);
|
|
1962
|
+
const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
|
|
1963
|
+
const showLess = ui?.showLess ?? "Show less";
|
|
1782
1964
|
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-timeline", children: [
|
|
1783
1965
|
card.title ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
1784
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1966
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "ss-w-fandash-live-tl", children: shown.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(EventRow, { e }, `${e.minute}-${e.side}-${e.type}-${i}`)) }),
|
|
1967
|
+
rest > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1968
|
+
"button",
|
|
1969
|
+
{
|
|
1970
|
+
type: "button",
|
|
1971
|
+
className: "ss-w-fandash-live-tl-more",
|
|
1972
|
+
"aria-expanded": expanded,
|
|
1973
|
+
onClick: () => setExpanded((v) => !v),
|
|
1974
|
+
children: expanded ? showLess : showMore(rest)
|
|
1975
|
+
}
|
|
1976
|
+
) : null
|
|
1788
1977
|
] });
|
|
1789
1978
|
}
|
|
1790
1979
|
|
|
1791
|
-
// src/components/dashboard/
|
|
1980
|
+
// src/components/dashboard/MomentumWave.tsx
|
|
1981
|
+
var import_react13 = require("react");
|
|
1792
1982
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1983
|
+
var WIDTH = 270;
|
|
1984
|
+
var HEIGHT = 56;
|
|
1985
|
+
var BASELINE = HEIGHT / 2;
|
|
1986
|
+
var SCALE = 0.26;
|
|
1987
|
+
function buildPaths(points) {
|
|
1988
|
+
const lastIndex = points.length - 1;
|
|
1989
|
+
const px = (i) => lastIndex === 0 ? 0 : i / lastIndex * WIDTH;
|
|
1990
|
+
const py = (v) => BASELINE - v * SCALE;
|
|
1991
|
+
const linePts = points.map((p, i) => `${px(i).toFixed(1)},${py(p.value).toFixed(1)}`);
|
|
1992
|
+
const area = `M0,${BASELINE} L${linePts.join(" L")} L${WIDTH},${BASELINE} Z`;
|
|
1993
|
+
const line = `M${linePts.join(" L")}`;
|
|
1994
|
+
const lastValue = points[lastIndex]?.value ?? 0;
|
|
1995
|
+
return { area, line, lastX: px(lastIndex).toFixed(1), lastY: py(lastValue).toFixed(1) };
|
|
1996
|
+
}
|
|
1997
|
+
function MomentumWave({
|
|
1998
|
+
points,
|
|
1999
|
+
caption,
|
|
2000
|
+
clubIsHome
|
|
2001
|
+
}) {
|
|
2002
|
+
if (points.length === 0) return null;
|
|
2003
|
+
const { area, line, lastX, lastY } = buildPaths(points);
|
|
2004
|
+
const clipId = (0, import_react13.useId)();
|
|
2005
|
+
const topClipId = `${clipId}-top`;
|
|
2006
|
+
const bottomClipId = `${clipId}-bottom`;
|
|
2007
|
+
const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
|
|
2008
|
+
const bottomClass = clubIsHome ? "ss-w-fandash-live-mom-away" : "ss-w-fandash-live-mom-home";
|
|
2009
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "ss-w-fandash-live-mom", children: [
|
|
2010
|
+
caption ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-live-mom-caption", children: caption }) : null,
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
2012
|
+
"svg",
|
|
2013
|
+
{
|
|
2014
|
+
className: "ss-w-fandash-live-mom-svg",
|
|
2015
|
+
viewBox: `0 0 ${WIDTH} ${HEIGHT}`,
|
|
2016
|
+
preserveAspectRatio: "none",
|
|
2017
|
+
role: "img",
|
|
2018
|
+
"aria-label": caption ?? "Momentum",
|
|
2019
|
+
children: [
|
|
2020
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("defs", { children: [
|
|
2021
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("clipPath", { id: topClipId, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("rect", { x: 0, y: 0, width: WIDTH, height: BASELINE }) }),
|
|
2022
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("clipPath", { id: bottomClipId, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("rect", { x: 0, y: BASELINE, width: WIDTH, height: HEIGHT - BASELINE }) })
|
|
2023
|
+
] }),
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: area, className: topClass, clipPath: `url(#${topClipId})` }),
|
|
2025
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: area, className: bottomClass, clipPath: `url(#${bottomClipId})` }),
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("line", { x1: 0, y1: BASELINE, x2: WIDTH, y2: BASELINE, className: "ss-w-fandash-live-mom-base" }),
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: line, className: "ss-w-fandash-live-mom-line", vectorEffect: "non-scaling-stroke" }),
|
|
2028
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("circle", { cx: lastX, cy: lastY, r: 3.2, className: "ss-w-fandash-live-mom-now", vectorEffect: "non-scaling-stroke" })
|
|
2029
|
+
]
|
|
2030
|
+
}
|
|
2031
|
+
)
|
|
2032
|
+
] });
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
// src/components/dashboard/LiveStatsCard.tsx
|
|
2036
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2037
|
+
function splitWidths(homeNum, awayNum) {
|
|
2038
|
+
const total = homeNum + awayNum;
|
|
2039
|
+
if (total <= 0) return { home: "50%", away: "50%" };
|
|
2040
|
+
const homePct = Math.round(homeNum / total * 1e3) / 10;
|
|
2041
|
+
return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` };
|
|
2042
|
+
}
|
|
1793
2043
|
function LiveStatsCard({ card }) {
|
|
1794
2044
|
const { data } = card;
|
|
1795
|
-
return /* @__PURE__ */ (0,
|
|
1796
|
-
card.title ? /* @__PURE__ */ (0,
|
|
1797
|
-
/* @__PURE__ */ (0,
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
2045
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-stats", children: [
|
|
2046
|
+
card.title ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
|
|
2047
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "ss-w-fandash-live-stat-rows", children: data.rows.map((r, i) => {
|
|
2048
|
+
const homeValue = data.clubIsHome ? r.clubValue : r.oppValue;
|
|
2049
|
+
const awayValue = data.clubIsHome ? r.oppValue : r.clubValue;
|
|
2050
|
+
const homeNum = data.clubIsHome ? r.clubNum : r.oppNum;
|
|
2051
|
+
const awayNum = data.clubIsHome ? r.oppNum : r.clubNum;
|
|
2052
|
+
const { home, away } = splitWidths(homeNum, awayNum);
|
|
2053
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash-live-stat", children: [
|
|
2054
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash-live-stat-row", children: [
|
|
2055
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--home", children: homeValue }),
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-stat-label", children: r.label }),
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--away", children: awayValue })
|
|
2058
|
+
] }),
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash-live-bar", children: [
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-bar-home", style: { width: home } }),
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-bar-away", style: { width: away } })
|
|
2062
|
+
] })
|
|
2063
|
+
] }, `${r.label}-${i}`);
|
|
2064
|
+
}) }),
|
|
2065
|
+
data.momentum.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MomentumWave, { points: data.momentum, caption: data.momentumLabel, clubIsHome: data.clubIsHome }) : data.momentumLabel ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-live-momentum", children: data.momentumLabel }) : null,
|
|
2066
|
+
data.rows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash-live-legend", children: [
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "ss-w-fandash-live-legend-item", children: [
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("i", { className: "ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--home" }),
|
|
2069
|
+
data.homeName
|
|
2070
|
+
] }),
|
|
2071
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "ss-w-fandash-live-legend-item", children: [
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("i", { className: "ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--away" }),
|
|
2073
|
+
data.awayName
|
|
2074
|
+
] })
|
|
2075
|
+
] }) : null
|
|
1803
2076
|
] });
|
|
1804
2077
|
}
|
|
1805
2078
|
|
|
1806
2079
|
// src/components/dashboard/ClubFanDashboard.tsx
|
|
1807
|
-
var
|
|
2080
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1808
2081
|
function ClubFanDashboard({ dashboard, onTap, ui }) {
|
|
1809
2082
|
const orderedCards = [
|
|
1810
2083
|
...dashboard.cards.filter((c) => c.cardType === "countdown"),
|
|
1811
2084
|
...dashboard.cards.filter((c) => c.cardType !== "countdown")
|
|
1812
2085
|
];
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2086
|
+
const timelineCard = dashboard.cards.find(
|
|
2087
|
+
(c) => c.cardType === "liveTimeline"
|
|
2088
|
+
);
|
|
2089
|
+
const goalEvents = timelineCard?.data.events.filter((e) => e.type === "goal");
|
|
2090
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "ss-w-fandash", children: [
|
|
2091
|
+
dashboard.greeting ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
|
|
2092
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FanDashboardCard, { card, onTap, ui, goalEvents }, `${card.cardType}-${i}`)) })
|
|
1816
2093
|
] });
|
|
1817
2094
|
}
|
|
1818
|
-
function FanDashboardCard({ card, onTap, ui }) {
|
|
2095
|
+
function FanDashboardCard({ card, onTap, ui, goalEvents }) {
|
|
1819
2096
|
switch (card.cardType) {
|
|
1820
2097
|
case "fixture":
|
|
1821
|
-
return /* @__PURE__ */ (0,
|
|
2098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FixtureCard, { card, onTap });
|
|
1822
2099
|
case "countdown":
|
|
1823
|
-
return /* @__PURE__ */ (0,
|
|
2100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CountdownCard, { card });
|
|
1824
2101
|
case "injuries":
|
|
1825
|
-
return /* @__PURE__ */ (0,
|
|
2102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(InjuriesCard, { card });
|
|
1826
2103
|
case "reasonToBet":
|
|
1827
|
-
return /* @__PURE__ */ (0,
|
|
2104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReasonToBetCard, { card });
|
|
1828
2105
|
case "whereToWatch":
|
|
1829
|
-
return /* @__PURE__ */ (0,
|
|
2106
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(WhereToWatchCard, { card });
|
|
1830
2107
|
case "congestedWeek":
|
|
1831
|
-
return /* @__PURE__ */ (0,
|
|
2108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CongestedWeekCard, { card, onTap });
|
|
1832
2109
|
case "transfers":
|
|
1833
|
-
return /* @__PURE__ */ (0,
|
|
2110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(TransfersCard, { card });
|
|
1834
2111
|
case "links":
|
|
1835
|
-
return /* @__PURE__ */ (0,
|
|
2112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LinksCard, { card });
|
|
1836
2113
|
case "postMatchResult":
|
|
1837
|
-
return /* @__PURE__ */ (0,
|
|
2114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PostMatchResultCard, { card });
|
|
1838
2115
|
case "postMatchGoals":
|
|
1839
|
-
return /* @__PURE__ */ (0,
|
|
2116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PostMatchGoalsCard, { card, onTap });
|
|
1840
2117
|
case "postMatchStats":
|
|
1841
|
-
return /* @__PURE__ */ (0,
|
|
2118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PostMatchStatsCard, { card, onTap });
|
|
1842
2119
|
case "postMatchTopPerformer":
|
|
1843
|
-
return /* @__PURE__ */ (0,
|
|
2120
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PostMatchTopPerformerCard, { card, onTap });
|
|
1844
2121
|
case "postMatchNext":
|
|
1845
|
-
return /* @__PURE__ */ (0,
|
|
2122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PostMatchNextCard, { card });
|
|
1846
2123
|
case "restingNext":
|
|
1847
|
-
return /* @__PURE__ */ (0,
|
|
2124
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RestingNextCard, { card, onTap });
|
|
1848
2125
|
case "restingStandings":
|
|
1849
|
-
return /* @__PURE__ */ (0,
|
|
2126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RestingStandingsCard, { card, onTap });
|
|
1850
2127
|
case "restingSeason":
|
|
1851
|
-
return /* @__PURE__ */ (0,
|
|
2128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RestingSeasonCard, { card, onTap });
|
|
1852
2129
|
case "restingForm":
|
|
1853
|
-
return /* @__PURE__ */ (0,
|
|
2130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RestingFormCard, { card });
|
|
1854
2131
|
case "liveScore":
|
|
1855
|
-
return /* @__PURE__ */ (0,
|
|
2132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LiveScoreCard, { card, goalEvents });
|
|
1856
2133
|
case "liveTimeline":
|
|
1857
|
-
return /* @__PURE__ */ (0,
|
|
2134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LiveTimelineCard, { card, ui });
|
|
1858
2135
|
case "liveStats":
|
|
1859
|
-
return /* @__PURE__ */ (0,
|
|
2136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LiveStatsCard, { card });
|
|
1860
2137
|
default:
|
|
1861
2138
|
return null;
|
|
1862
2139
|
}
|
|
1863
2140
|
}
|
|
1864
2141
|
|
|
1865
2142
|
// src/components/ChatMessage.tsx
|
|
1866
|
-
var
|
|
2143
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1867
2144
|
function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
|
|
1868
2145
|
if (message.role === "user") {
|
|
1869
|
-
return /* @__PURE__ */ (0,
|
|
2146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "ss-w-msg ss-w-user", "data-msg-id": message.id, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1870
2147
|
}
|
|
1871
2148
|
const onFanDashboardTap = (card) => {
|
|
1872
2149
|
onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || "" });
|
|
1873
2150
|
};
|
|
1874
|
-
return /* @__PURE__ */ (0,
|
|
1875
|
-
message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0,
|
|
1876
|
-
message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0,
|
|
1877
|
-
message.clubFanDashboard ? /* @__PURE__ */ (0,
|
|
1878
|
-
/* @__PURE__ */ (0,
|
|
1879
|
-
/* @__PURE__ */ (0,
|
|
1880
|
-
/* @__PURE__ */ (0,
|
|
1881
|
-
/* @__PURE__ */ (0,
|
|
1882
|
-
/* @__PURE__ */ (0,
|
|
2151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "ss-w-msg ss-w-bot", "data-msg-id": message.id, children: [
|
|
2152
|
+
message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Markdown, { text: message.text }) : null,
|
|
2153
|
+
message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
2154
|
+
message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
2156
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
2157
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
2158
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1883
2160
|
] });
|
|
1884
2161
|
}
|
|
1885
2162
|
|
|
1886
2163
|
// src/components/IntentChips.tsx
|
|
1887
|
-
var
|
|
2164
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1888
2165
|
function IntentChips({ chips, onPick }) {
|
|
1889
2166
|
if (chips.length === 0) return null;
|
|
1890
|
-
return /* @__PURE__ */ (0,
|
|
2167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1891
2168
|
}
|
|
1892
2169
|
|
|
1893
2170
|
// src/scroll.ts
|
|
@@ -1897,7 +2174,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1897
2174
|
}
|
|
1898
2175
|
|
|
1899
2176
|
// src/components/MessageList.tsx
|
|
1900
|
-
var
|
|
2177
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
1901
2178
|
function turnAnchor(messages) {
|
|
1902
2179
|
const last = messages[messages.length - 1];
|
|
1903
2180
|
if (!last || last.role !== "assistant") return null;
|
|
@@ -1906,11 +2183,11 @@ function turnAnchor(messages) {
|
|
|
1906
2183
|
}
|
|
1907
2184
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1908
2185
|
const { state, send } = controller;
|
|
1909
|
-
const listRef = (0,
|
|
1910
|
-
const endRef = (0,
|
|
1911
|
-
const pinnedRef = (0,
|
|
1912
|
-
const anchoredTurnRef = (0,
|
|
1913
|
-
(0,
|
|
2186
|
+
const listRef = (0, import_react14.useRef)(null);
|
|
2187
|
+
const endRef = (0, import_react14.useRef)(null);
|
|
2188
|
+
const pinnedRef = (0, import_react14.useRef)(true);
|
|
2189
|
+
const anchoredTurnRef = (0, import_react14.useRef)(null);
|
|
2190
|
+
(0, import_react14.useEffect)(() => {
|
|
1914
2191
|
const anchor = turnAnchor(state.messages);
|
|
1915
2192
|
const list = listRef.current;
|
|
1916
2193
|
if (anchor && anchor.turnId !== anchoredTurnRef.current) {
|
|
@@ -1925,7 +2202,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1925
2202
|
}, [state.messages, state.status, state.isStreaming]);
|
|
1926
2203
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1927
2204
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
|
|
1928
|
-
return /* @__PURE__ */ (0,
|
|
2205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
1929
2206
|
"div",
|
|
1930
2207
|
{
|
|
1931
2208
|
className: "ss-w-list",
|
|
@@ -1935,7 +2212,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1935
2212
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1936
2213
|
},
|
|
1937
2214
|
children: [
|
|
1938
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
2215
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1939
2216
|
ChatMessage,
|
|
1940
2217
|
{
|
|
1941
2218
|
message: m,
|
|
@@ -1950,25 +2227,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1950
2227
|
},
|
|
1951
2228
|
m.id
|
|
1952
2229
|
)),
|
|
1953
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
2230
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1954
2231
|
} }) : null,
|
|
1955
|
-
state.status ? /* @__PURE__ */ (0,
|
|
1956
|
-
state.error ? /* @__PURE__ */ (0,
|
|
1957
|
-
/* @__PURE__ */ (0,
|
|
1958
|
-
/* @__PURE__ */ (0,
|
|
2232
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
2233
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1959
2236
|
] }) : null,
|
|
1960
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0,
|
|
1961
|
-
/* @__PURE__ */ (0,
|
|
2237
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ref: endRef, className: "ss-w-turn-spacer", "aria-hidden": "true" })
|
|
1962
2239
|
]
|
|
1963
2240
|
}
|
|
1964
2241
|
);
|
|
1965
2242
|
}
|
|
1966
2243
|
|
|
1967
2244
|
// src/components/ChatInput.tsx
|
|
1968
|
-
var
|
|
1969
|
-
var
|
|
2245
|
+
var import_react15 = require("react");
|
|
2246
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
1970
2247
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1971
|
-
const [value, setValue] = (0,
|
|
2248
|
+
const [value, setValue] = (0, import_react15.useState)("");
|
|
1972
2249
|
const submit = () => {
|
|
1973
2250
|
const t = value.trim();
|
|
1974
2251
|
if (!t) return;
|
|
@@ -1981,18 +2258,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1981
2258
|
submit();
|
|
1982
2259
|
}
|
|
1983
2260
|
};
|
|
1984
|
-
return /* @__PURE__ */ (0,
|
|
1985
|
-
/* @__PURE__ */ (0,
|
|
1986
|
-
streaming ? /* @__PURE__ */ (0,
|
|
2261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ss-w-input", children: [
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
2263
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SendIcon, {}) })
|
|
1987
2264
|
] });
|
|
1988
2265
|
}
|
|
1989
2266
|
|
|
1990
2267
|
// src/components/ChatPanel.tsx
|
|
1991
|
-
var
|
|
2268
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
1992
2269
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1993
2270
|
function useIsModal() {
|
|
1994
|
-
const [modal, setModal] = (0,
|
|
1995
|
-
(0,
|
|
2271
|
+
const [modal, setModal] = (0, import_react16.useState)(false);
|
|
2272
|
+
(0, import_react16.useEffect)(() => {
|
|
1996
2273
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
1997
2274
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
1998
2275
|
const sync = () => setModal(mql.matches);
|
|
@@ -2005,17 +2282,17 @@ function useIsModal() {
|
|
|
2005
2282
|
function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
2006
2283
|
const { state, close, stop, send } = controller;
|
|
2007
2284
|
const isModal = useIsModal();
|
|
2008
|
-
(0,
|
|
2285
|
+
(0, import_react16.useEffect)(() => {
|
|
2009
2286
|
const onKey = (e) => {
|
|
2010
2287
|
if (e.key === "Escape") close();
|
|
2011
2288
|
};
|
|
2012
2289
|
window.addEventListener("keydown", onKey);
|
|
2013
2290
|
return () => window.removeEventListener("keydown", onKey);
|
|
2014
2291
|
}, [close]);
|
|
2015
|
-
return /* @__PURE__ */ (0,
|
|
2016
|
-
/* @__PURE__ */ (0,
|
|
2017
|
-
/* @__PURE__ */ (0,
|
|
2018
|
-
/* @__PURE__ */ (0,
|
|
2292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
2293
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
2294
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
2295
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
2019
2296
|
] });
|
|
2020
2297
|
}
|
|
2021
2298
|
|
|
@@ -2028,6 +2305,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2028
2305
|
--ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;
|
|
2029
2306
|
--ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
|
|
2030
2307
|
--ss-w-pos: #1aa563; --ss-w-neg: #e0524b;
|
|
2308
|
+
--ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
|
|
2031
2309
|
--ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;
|
|
2032
2310
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
2033
2311
|
font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);
|
|
@@ -2038,6 +2316,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2038
2316
|
--ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
|
|
2039
2317
|
--ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
|
|
2040
2318
|
--ss-w-pos: #37c891; --ss-w-neg: #f0655d;
|
|
2319
|
+
--ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
|
|
2041
2320
|
}
|
|
2042
2321
|
}
|
|
2043
2322
|
.ss-w-root[data-ss-w-theme="dark"] {
|
|
@@ -2045,11 +2324,13 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2045
2324
|
--ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
|
|
2046
2325
|
--ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
|
|
2047
2326
|
--ss-w-pos: #37c891; --ss-w-neg: #f0655d;
|
|
2327
|
+
--ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
|
|
2048
2328
|
}
|
|
2049
2329
|
.ss-w-root[data-ss-w-theme="light"] {
|
|
2050
2330
|
--ss-w-accent: #17936a; --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;
|
|
2051
2331
|
--ss-w-ink: #14181d; --ss-w-faint: #6b7580;
|
|
2052
2332
|
--ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
|
|
2333
|
+
--ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
|
|
2053
2334
|
}
|
|
2054
2335
|
|
|
2055
2336
|
/* launcher */
|
|
@@ -2538,34 +2819,90 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2538
2819
|
/* resting form: reuses the fixture last-five pill classes (ss-w-fandash-form / -form-pill) */
|
|
2539
2820
|
.ss-w-fandash-resting-form .ss-w-fandash-form { margin-top: 2px; }
|
|
2540
2821
|
|
|
2541
|
-
/* live score:
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
.ss-w-fandash-live-
|
|
2546
|
-
.ss-w-fandash-live-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
.ss-w-fandash-live-
|
|
2551
|
-
|
|
2552
|
-
.ss-w-fandash-live-
|
|
2553
|
-
.ss-w-fandash-live-
|
|
2554
|
-
.ss-w-fandash-live-
|
|
2555
|
-
.ss-w-fandash-live-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
.ss-w-fandash-live-
|
|
2560
|
-
.ss-w-fandash-live-
|
|
2822
|
+
/* live score: pulsing Live pill, crests (real image or a coloured initials fallback), a big
|
|
2823
|
+
tabular score, and an optional scorers line. Also where the shared home/away venue-colour
|
|
2824
|
+
tokens (--ss-w-home / --ss-w-away / --ss-w-track) are defined above -- the timeline and stats
|
|
2825
|
+
cards reuse them. */
|
|
2826
|
+
.ss-w-fandash-live-top { display: flex; align-items: center; gap: 8px; }
|
|
2827
|
+
.ss-w-fandash-live-pill { display: inline-flex; flex: none; align-items: center; gap: 5px; font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: var(--ss-w-neg); border-radius: 6px; padding: 3px 7px; }
|
|
2828
|
+
.ss-w-fandash-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; animation: ss-w-fandash-live-pulse 1.3s ease-in-out infinite; }
|
|
2829
|
+
@keyframes ss-w-fandash-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
|
|
2830
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2831
|
+
.ss-w-fandash-live-dot { animation: none; }
|
|
2832
|
+
}
|
|
2833
|
+
.ss-w-fandash-live-minute { flex: none; font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
|
|
2834
|
+
.ss-w-fandash-live-competition { margin-left: auto; font-size: 11px; font-weight: 650; color: var(--ss-w-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2835
|
+
.ss-w-fandash-live-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; }
|
|
2836
|
+
.ss-w-fandash-live-side { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
2837
|
+
.ss-w-fandash-live-side--away { flex-direction: row-reverse; text-align: right; }
|
|
2838
|
+
.ss-w-fandash-live-crest { width: 30px; height: 30px; border-radius: 8px; flex: none; display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 10.5px; object-fit: cover; }
|
|
2839
|
+
.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--home { background: var(--ss-w-home); }
|
|
2840
|
+
.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--away { background: var(--ss-w-away); }
|
|
2841
|
+
.ss-w-fandash-live-team-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
|
|
2842
|
+
.ss-w-fandash-live-score-main { display: flex; align-items: baseline; justify-content: center; font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; color: var(--ss-w-ink); }
|
|
2843
|
+
.ss-w-fandash-live-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 4px; }
|
|
2844
|
+
.ss-w-fandash-live-scorers { margin-top: 2px; display: flex; justify-content: flex-end; gap: 6px; align-items: center; font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
|
|
2845
|
+
.ss-w-fandash-live-scorers-icon { flex: none; color: var(--ss-w-away); }
|
|
2846
|
+
|
|
2847
|
+
/* live timeline: a compact two-sided event list down a centre spine -- each club's events sit on
|
|
2848
|
+
its own side (home left, away right), most-recent 3 shown with a "See more" toggle for the
|
|
2849
|
+
rest. A 3-column grid (txt | badge | txt) per row; the spine itself is a ::before on the list. */
|
|
2850
|
+
.ss-w-fandash-live-tl { position: relative; display: flex; flex-direction: column; gap: 6px; }
|
|
2851
|
+
.ss-w-fandash-live-tl::before { content: ""; position: absolute; left: 50%; top: 1px; bottom: 1px; width: 2px; background: var(--ss-w-line); transform: translateX(-1px); }
|
|
2852
|
+
.ss-w-fandash-live-tl-ev { display: grid; grid-template-columns: 1fr 32px 1fr; align-items: center; gap: 6px; }
|
|
2853
|
+
.ss-w-fandash-live-tl-txt { display: flex; align-items: center; gap: 6px; font-size: 12.5px; min-width: 0; }
|
|
2854
|
+
.ss-w-fandash-live-tl-ev--home .ss-w-fandash-live-tl-txt { grid-column: 1; justify-content: flex-end; }
|
|
2855
|
+
.ss-w-fandash-live-tl-ev--away .ss-w-fandash-live-tl-txt { grid-column: 3; justify-content: flex-start; flex-direction: row-reverse; }
|
|
2856
|
+
.ss-w-fandash-live-tl-who { font-weight: 650; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
2857
|
+
.ss-w-fandash-live-tl-off { font-weight: 500; color: var(--ss-w-faint); }
|
|
2858
|
+
.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-who { font-weight: 800; }
|
|
2859
|
+
.ss-w-fandash-live-tl-badge { grid-column: 2; justify-self: center; min-width: 27px; height: 18px; padding: 0 4px; border-radius: 6px; display: grid; place-items: center; font-size: 10.5px; font-weight: 800; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); font-variant-numeric: tabular-nums; z-index: 1; }
|
|
2860
|
+
.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-badge { background: var(--ss-w-accent); color: #fff; border-color: transparent; }
|
|
2861
|
+
.ss-w-fandash-live-tl-ico { width: 16px; height: 16px; flex: none; display: grid; place-items: center; }
|
|
2862
|
+
.ss-w-fandash-live-tl-ico--goal { border-radius: 50%; background: color-mix(in srgb, var(--ss-w-away) 16%, transparent); }
|
|
2863
|
+
.ss-w-fandash-live-tl-ball { width: 11px; height: 11px; border-radius: 50%; background: var(--ss-w-ink); border: 1px solid var(--ss-w-ink); }
|
|
2864
|
+
.ss-w-fandash-live-tl-card { width: 8px; height: 11px; border-radius: 2px; display: block; }
|
|
2865
|
+
.ss-w-fandash-live-tl-card--yellow { background: var(--ss-w-cta); }
|
|
2866
|
+
.ss-w-fandash-live-tl-card--red { background: var(--ss-w-away); }
|
|
2867
|
+
.ss-w-fandash-live-tl-subarrows { font-size: 11px; font-weight: 900; line-height: 1; letter-spacing: -1px; color: var(--ss-w-accent); }
|
|
2868
|
+
.ss-w-fandash-live-tl-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ss-w-faint); }
|
|
2869
|
+
.ss-w-fandash-live-tl-more { margin-top: 4px; width: 100%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 7px; font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); cursor: pointer; }
|
|
2870
|
+
.ss-w-fandash-live-tl-more:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }
|
|
2871
|
+
|
|
2872
|
+
/* live stats: club value / stat label / opponent value, each row backed by a home/away split
|
|
2873
|
+
bar, plus an optional momentum wave (or its text fallback) and a club/opponent colour legend.
|
|
2874
|
+
No side signal reaches this card, so the club is always the home token and the opponent is
|
|
2875
|
+
always the away token -- see LiveStatsCard.tsx. */
|
|
2876
|
+
.ss-w-fandash-live-stat-rows { display: flex; flex-direction: column; gap: 14px; }
|
|
2877
|
+
.ss-w-fandash-live-stat { display: flex; flex-direction: column; gap: 6px; }
|
|
2878
|
+
.ss-w-fandash-live-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }
|
|
2561
2879
|
.ss-w-fandash-live-stat-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
|
|
2562
|
-
.ss-w-fandash-live-stat-
|
|
2563
|
-
.ss-w-fandash-live-stat-
|
|
2880
|
+
.ss-w-fandash-live-stat-value--home { color: var(--ss-w-home); }
|
|
2881
|
+
.ss-w-fandash-live-stat-value--away { color: var(--ss-w-away); text-align: right; }
|
|
2882
|
+
.ss-w-fandash-live-stat-label { font-size: 10px; font-weight: 700; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .04em; }
|
|
2883
|
+
.ss-w-fandash-live-bar { position: relative; height: 7px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }
|
|
2884
|
+
.ss-w-fandash-live-bar-home { height: 100%; background: var(--ss-w-home); }
|
|
2885
|
+
.ss-w-fandash-live-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }
|
|
2886
|
+
|
|
2564
2887
|
.ss-w-fandash-live-momentum { font-size: 11.5px; font-weight: 650; color: var(--ss-w-accent); }
|
|
2888
|
+
.ss-w-fandash-live-mom { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); }
|
|
2889
|
+
.ss-w-fandash-live-mom-caption { display: block; margin-bottom: 5px; font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); }
|
|
2890
|
+
.ss-w-fandash-live-mom-svg { width: 100%; height: 50px; display: block; overflow: visible; }
|
|
2891
|
+
.ss-w-fandash-live-mom-home { fill: var(--ss-w-home); fill-opacity: .85; }
|
|
2892
|
+
.ss-w-fandash-live-mom-away { fill: var(--ss-w-away); fill-opacity: .85; }
|
|
2893
|
+
.ss-w-fandash-live-mom-line { fill: none; stroke: color-mix(in srgb, var(--ss-w-ink) 55%, transparent); stroke-width: 1.5; }
|
|
2894
|
+
.ss-w-fandash-live-mom-base { stroke: var(--ss-w-line); stroke-width: 1; stroke-dasharray: 3 3; }
|
|
2895
|
+
.ss-w-fandash-live-mom-now { fill: var(--ss-w-panel); stroke: var(--ss-w-ink); stroke-width: 1.5; }
|
|
2896
|
+
|
|
2897
|
+
.ss-w-fandash-live-legend { display: flex; gap: 14px; margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); font-size: 11px; color: var(--ss-w-faint); }
|
|
2898
|
+
.ss-w-fandash-live-legend-item { display: inline-flex; align-items: center; gap: 6px; }
|
|
2899
|
+
.ss-w-fandash-live-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
|
|
2900
|
+
.ss-w-fandash-live-legend-swatch--home { background: var(--ss-w-home); }
|
|
2901
|
+
.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }
|
|
2565
2902
|
`;
|
|
2566
2903
|
|
|
2567
2904
|
// src/StatsWidget.tsx
|
|
2568
|
-
var
|
|
2905
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2569
2906
|
function buildClient(props) {
|
|
2570
2907
|
try {
|
|
2571
2908
|
if ("client" in props && props.client) {
|
|
@@ -2590,11 +2927,11 @@ function injectStyles(root) {
|
|
|
2590
2927
|
function StatsWidget(props) {
|
|
2591
2928
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
2592
2929
|
const cfg = props.config;
|
|
2593
|
-
const built = (0,
|
|
2594
|
-
const ui = (0,
|
|
2595
|
-
const rootRef = (0,
|
|
2930
|
+
const built = (0, import_react17.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
2931
|
+
const ui = (0, import_react17.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
2932
|
+
const rootRef = (0, import_react17.useRef)(null);
|
|
2596
2933
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
2597
|
-
const slip = (0,
|
|
2934
|
+
const slip = (0, import_react17.useMemo)(
|
|
2598
2935
|
() => ({
|
|
2599
2936
|
onAddToSlip: props.config?.onAddToSlip,
|
|
2600
2937
|
conversationId: controller.state.conversationId ?? void 0,
|
|
@@ -2607,18 +2944,18 @@ function StatsWidget(props) {
|
|
|
2607
2944
|
}),
|
|
2608
2945
|
[props.config?.onAddToSlip, controller.state.conversationId, built]
|
|
2609
2946
|
);
|
|
2610
|
-
const onDashboardTap = (0,
|
|
2947
|
+
const onDashboardTap = (0, import_react17.useMemo)(
|
|
2611
2948
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
|
|
2612
2949
|
[built]
|
|
2613
2950
|
);
|
|
2614
|
-
(0,
|
|
2951
|
+
(0, import_react17.useEffect)(() => {
|
|
2615
2952
|
if (!built || !ui.injectStyles) return;
|
|
2616
2953
|
const node = rootRef.current?.getRootNode();
|
|
2617
2954
|
if (node) injectStyles(node);
|
|
2618
2955
|
}, [built, ui.injectStyles]);
|
|
2619
2956
|
if (!built) return null;
|
|
2620
2957
|
const attrs = themeAttrs(ui);
|
|
2621
|
-
return /* @__PURE__ */ (0,
|
|
2958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.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_runtime44.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2622
2959
|
ChatFab,
|
|
2623
2960
|
{
|
|
2624
2961
|
label: ui.launcherLabel,
|