@sensiblestats/widget-react 0.14.1 → 0.16.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 399d6bf: Label market-floor betting insight cards with a distinct "Market price · not a value pick" pill, so a screenshot of one can never read as a recommendation. Older servers that never send `isMarketFloor` render cards exactly as before.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [399d6bf]
12
+ - @sensiblestats/widget-sdk@0.14.0
13
+
14
+ ## 0.15.0
15
+
16
+ ### Minor Changes
17
+
18
+ - Render the Club Match-Day dashboard (typed blocks: greeting header, fixture hero, form guide, match preview, team DNA, countdown) delivered on `turn_complete.clubDashboard`.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+ - @sensiblestats/widget-sdk@0.13.0
24
+
3
25
  ## 0.14.1
4
26
 
5
27
  ### Patch Changes
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 import_react10 = require("react");
39
+ var import_react12 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/i18n.ts
@@ -57,6 +57,7 @@ var STRINGS = {
57
57
  hideStats: "Hide stats",
58
58
  oddsLabel: "Odds",
59
59
  liveLabel: "Live",
60
+ marketFloorLabel: "Market price \xB7 not a value pick",
60
61
  addToSlip: "Add to slip",
61
62
  marketPrices: "Market prices",
62
63
  moreLines: "More lines",
@@ -79,6 +80,12 @@ var STRINGS = {
79
80
  const drift = direction ? `, ${direction}` : "";
80
81
  return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`;
81
82
  },
83
+ clubMatchPreviewHeading: "Match preview",
84
+ clubTeamDnaHeading: "How they play",
85
+ clubFormHeading: "Recent form",
86
+ clubCountdownLabel: "Countdown to kick-off",
87
+ clubKickoff: (ms) => new Intl.DateTimeFormat("en-GB", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
88
+ clubKickoffAria: (ms) => `Kick-off ${new Intl.DateTimeFormat("en-GB", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
82
89
  inSlip: "In slip",
83
90
  slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
84
91
  slipDuplicate: "Already in your slip",
@@ -104,6 +111,7 @@ var STRINGS = {
104
111
  hideStats: "\u0130statistikleri gizle",
105
112
  oddsLabel: "Oran",
106
113
  liveLabel: "Canl\u0131",
114
+ marketFloorLabel: "Piyasa oran\u0131 \xB7 de\u011Fer bahsi de\u011Fil",
107
115
  addToSlip: "Kupona ekle",
108
116
  marketPrices: "Piyasa fiyatlar\u0131",
109
117
  moreLines: "Di\u011Fer \xE7izgiler",
@@ -126,6 +134,12 @@ var STRINGS = {
126
134
  const drift = direction ? `, ${direction}` : "";
127
135
  return `Son ${span} i\xE7indeki oran hareketi: ${opening} ile a\xE7\u0131ld\u0131, \u015Fu anda ${current}${drift}.`;
128
136
  },
137
+ clubMatchPreviewHeading: "Ma\xE7 \xF6nizlemesi",
138
+ clubTeamDnaHeading: "Nas\u0131l oynuyorlar",
139
+ clubFormHeading: "Son form",
140
+ clubCountdownLabel: "Ba\u015Flama vuru\u015Funa kalan",
141
+ clubKickoff: (ms) => new Intl.DateTimeFormat("tr-TR", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
142
+ clubKickoffAria: (ms) => `Ba\u015Flama vuru\u015Fu ${new Intl.DateTimeFormat("tr-TR", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
129
143
  inSlip: "Kuponda",
130
144
  slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
131
145
  slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
@@ -168,6 +182,7 @@ function normalizeUi(cfg) {
168
182
  hideStats: strings.hideStats,
169
183
  oddsLabel: strings.oddsLabel,
170
184
  liveLabel: strings.liveLabel,
185
+ marketFloorLabel: strings.marketFloorLabel,
171
186
  marketPrices: strings.marketPrices,
172
187
  moreLines: strings.moreLines,
173
188
  hideLines: strings.hideLines,
@@ -185,6 +200,12 @@ function normalizeUi(cfg) {
185
200
  excludedSuspended: strings.excludedSuspended,
186
201
  chartTimeLabel: strings.chartTimeLabel,
187
202
  chartAria: strings.chartAria,
203
+ clubMatchPreviewHeading: strings.clubMatchPreviewHeading,
204
+ clubTeamDnaHeading: strings.clubTeamDnaHeading,
205
+ clubFormHeading: strings.clubFormHeading,
206
+ clubCountdownLabel: strings.clubCountdownLabel,
207
+ clubKickoff: strings.clubKickoff,
208
+ clubKickoffAria: strings.clubKickoffAria,
188
209
  addToSlip: strings.addToSlip,
189
210
  inSlip: strings.inSlip,
190
211
  slipAdded: strings.slipAdded,
@@ -378,6 +399,7 @@ function toInsightVM(insight) {
378
399
  matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
379
400
  matchOddsId,
380
401
  addToSlipEnabled: insight.addToSlipEnabled === true,
402
+ isMarketFloor: insight.isMarketFloor === true,
381
403
  oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
382
404
  quotedAtUtc: str(insight.odds?.quotedAtUtc),
383
405
  previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
@@ -531,7 +553,8 @@ function applyEvent(state, event) {
531
553
  messages: mapActive(state, (t) => ({
532
554
  ...t,
533
555
  done: true,
534
- greetingDashboard: event.data.dashboard ?? void 0
556
+ greetingDashboard: event.data.dashboard ?? void 0,
557
+ clubDashboard: event.data.clubDashboard ?? void 0
535
558
  }))
536
559
  };
537
560
  }
@@ -698,7 +721,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
698
721
  }
699
722
 
700
723
  // src/components/ChatPanel.tsx
701
- var import_react9 = require("react");
724
+ var import_react11 = require("react");
702
725
 
703
726
  // src/components/ChatHeader.tsx
704
727
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -711,7 +734,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
711
734
  }
712
735
 
713
736
  // src/components/MessageList.tsx
714
- var import_react7 = require("react");
737
+ var import_react9 = require("react");
715
738
 
716
739
  // src/components/Markdown.tsx
717
740
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -995,10 +1018,13 @@ function StatsDisclosure({ it, ui }) {
995
1018
  function InsightCard({ it, ui, slip }) {
996
1019
  const live = it.isLive || it.phase === "live";
997
1020
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-binsight", children: [
998
- live ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-bi-status", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-live", children: [
999
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1000
- ui?.liveLabel ?? "Live"
1001
- ] }) }) : null,
1021
+ live || it.isMarketFloor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-status", children: [
1022
+ live ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-live", children: [
1023
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1024
+ ui?.liveLabel ?? "Live"
1025
+ ] }) : null,
1026
+ it.isMarketFloor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-floor", children: ui?.marketFloorLabel ?? "Market price \xB7 not a value pick" }) : null
1027
+ ] }) : null,
1002
1028
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-head", children: [
1003
1029
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-mkt", children: [
1004
1030
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-market", children: it.market }),
@@ -1195,28 +1221,184 @@ function GreetingDashboard({ dashboard, onTap }) {
1195
1221
  ] });
1196
1222
  }
1197
1223
 
1198
- // src/components/ChatMessage.tsx
1224
+ // src/components/club-dashboard/GreetingHeaderBlock.tsx
1199
1225
  var import_jsx_runtime16 = require("react/jsx-runtime");
1200
- function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1226
+ function GreetingHeaderBlock({ block }) {
1227
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ss-w-cdash-greeting", children: [
1228
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ss-w-cdash-greeting-title", children: block.title }),
1229
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ss-w-cdash-greeting-subtitle", children: block.subtitle })
1230
+ ] });
1231
+ }
1232
+
1233
+ // src/components/club-dashboard/FixtureHeroBlock.tsx
1234
+ var import_react7 = require("react");
1235
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1236
+ function initials2(name) {
1237
+ return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
1238
+ }
1239
+ function Crest2({ url, name }) {
1240
+ const [broken, setBroken] = (0, import_react7.useState)(false);
1241
+ if (!url || broken) {
1242
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials2(name) });
1243
+ }
1244
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
1245
+ }
1246
+ function FixtureHeroBlock({
1247
+ block,
1248
+ ui,
1249
+ onAction
1250
+ }) {
1251
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-cdash-fixture", children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-cdash-tie", children: [
1253
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: block.homeCrestUrl, name: block.homeName }),
1254
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-team", children: block.homeName }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-vs", children: "v" }),
1256
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-team", children: block.awayName }),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: block.awayCrestUrl, name: block.awayName })
1258
+ ] }),
1259
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-cdash-fixture-meta", children: [
1260
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-kickoff", children: ui.clubKickoff(block.kickoffUnix * 1e3) }),
1261
+ block.venue ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
1262
+ block.competition ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
1263
+ ] }),
1264
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaActionValue, block.ctaLabel), children: block.ctaLabel })
1265
+ ] });
1266
+ }
1267
+
1268
+ // src/components/club-dashboard/FormGuideBlock.tsx
1269
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1270
+ function FormGuideBlock({ block }) {
1271
+ if (block.rows.length === 0) return null;
1272
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-form-row", children: [
1273
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "ss-w-cdash-form-name", children: [
1274
+ row.name,
1275
+ row.position != null ? ` #${row.position}` : ""
1276
+ ] }),
1277
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-form-pills", children: row.last5.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) })
1278
+ ] }, row.name)) });
1279
+ }
1280
+
1281
+ // src/components/club-dashboard/MatchPreviewBlock.tsx
1282
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1283
+ function MatchPreviewBlock({
1284
+ block,
1285
+ ui,
1286
+ onAction
1287
+ }) {
1288
+ if (block.lines.length === 0) return null;
1289
+ const heading = ui.clubMatchPreviewHeading;
1290
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "ss-w-cdash-lines", onClick: () => onAction(block.actionValue, heading), children: [
1291
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1292
+ block.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: line }, i))
1293
+ ] });
1294
+ }
1295
+
1296
+ // src/components/club-dashboard/TeamDnaBlock.tsx
1297
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1298
+ function TeamDnaBlock({
1299
+ block,
1300
+ ui,
1301
+ onAction
1302
+ }) {
1303
+ if (block.lines.length === 0) return null;
1304
+ const heading = ui.clubTeamDnaHeading;
1305
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { type: "button", className: "ss-w-cdash-lines", onClick: () => onAction(block.actionValue, heading), children: [
1306
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1307
+ block.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: line }, i))
1308
+ ] });
1309
+ }
1310
+
1311
+ // src/components/club-dashboard/CountdownBlock.tsx
1312
+ var import_react8 = require("react");
1313
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1314
+ var DAY_MS = 24 * 3600 * 1e3;
1315
+ function pad2(n) {
1316
+ return String(n).padStart(2, "0");
1317
+ }
1318
+ function splitRemaining(remainingMs) {
1319
+ const totalSeconds = Math.max(0, Math.floor(remainingMs / 1e3));
1320
+ const h = Math.floor(totalSeconds / 3600);
1321
+ const m = Math.floor(totalSeconds % 3600 / 60);
1322
+ const s = totalSeconds % 60;
1323
+ return { h: pad2(h), m: pad2(m), s: pad2(s) };
1324
+ }
1325
+ function CountdownBlock({ block, ui }) {
1326
+ const [remainingMs, setRemainingMs] = (0, import_react8.useState)(() => block.kickoffUnix * 1e3 - Date.now());
1327
+ (0, import_react8.useEffect)(() => {
1328
+ setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1329
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1330
+ const id = setInterval(() => {
1331
+ setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1332
+ }, 1e3);
1333
+ return () => clearInterval(id);
1334
+ }, [block.kickoffUnix]);
1335
+ if (remainingMs <= 0) return null;
1336
+ if (remainingMs > DAY_MS) return null;
1337
+ const { h, m, s } = splitRemaining(remainingMs);
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
1339
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
1340
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-cd-h", children: h }),
1341
+ "h",
1342
+ " ",
1343
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-cd-m", children: m }),
1344
+ "m",
1345
+ " ",
1346
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-cd-s", children: s }),
1347
+ "s"
1348
+ ] }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
1350
+ ] });
1351
+ }
1352
+
1353
+ // src/components/club-dashboard/ClubDashboard.tsx
1354
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1355
+ var CLUB_BLOCK_REGISTRY = {
1356
+ greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GreetingHeaderBlock, { block }) : null,
1357
+ fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FixtureHeroBlock, { block, ui, onAction }) : null,
1358
+ formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FormGuideBlock, { block, ui }) : null,
1359
+ matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MatchPreviewBlock, { block, ui, onAction }) : null,
1360
+ teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TeamDnaBlock, { block, ui, onAction }) : null,
1361
+ countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CountdownBlock, { block, ui }) : null
1362
+ };
1363
+ function ClubDashboard({
1364
+ dashboard,
1365
+ ui,
1366
+ onAction
1367
+ }) {
1368
+ if (!dashboard.blocks.length) return null;
1369
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
1370
+ const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
1371
+ if (!Comp) {
1372
+ console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
1373
+ return null;
1374
+ }
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Comp, { block, ui, onAction }) }, i);
1376
+ }) });
1377
+ }
1378
+
1379
+ // src/components/ChatMessage.tsx
1380
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1381
+ function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
1201
1382
  if (message.role === "user") {
1202
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1383
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1203
1384
  }
1204
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1205
- message.text && !message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Markdown, { text: message.text }) : null,
1206
- message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1207
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1208
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1209
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1211
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1386
+ message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Markdown, { text: message.text }) : null,
1387
+ message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1388
+ message.clubDashboard && ui ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
1389
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1390
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1391
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1392
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1212
1394
  ] });
1213
1395
  }
1214
1396
 
1215
1397
  // src/components/IntentChips.tsx
1216
- var import_jsx_runtime17 = require("react/jsx-runtime");
1398
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1217
1399
  function IntentChips({ chips, onPick }) {
1218
1400
  if (chips.length === 0) return null;
1219
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1401
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1220
1402
  }
1221
1403
 
1222
1404
  // src/scroll.ts
@@ -1226,18 +1408,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1226
1408
  }
1227
1409
 
1228
1410
  // src/components/MessageList.tsx
1229
- var import_jsx_runtime18 = require("react/jsx-runtime");
1411
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1230
1412
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1231
1413
  const { state, send } = controller;
1232
- const listRef = (0, import_react7.useRef)(null);
1233
- const endRef = (0, import_react7.useRef)(null);
1234
- const pinnedRef = (0, import_react7.useRef)(true);
1235
- (0, import_react7.useEffect)(() => {
1414
+ const listRef = (0, import_react9.useRef)(null);
1415
+ const endRef = (0, import_react9.useRef)(null);
1416
+ const pinnedRef = (0, import_react9.useRef)(true);
1417
+ (0, import_react9.useEffect)(() => {
1236
1418
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1237
1419
  }, [state.messages, state.status]);
1238
1420
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1239
1421
  const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
1240
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1422
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1241
1423
  "div",
1242
1424
  {
1243
1425
  className: "ss-w-list",
@@ -1247,7 +1429,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1247
1429
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1248
1430
  },
1249
1431
  children: [
1250
- state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1432
+ state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1251
1433
  ChatMessage,
1252
1434
  {
1253
1435
  message: m,
@@ -1257,30 +1439,31 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1257
1439
  send(tile.actionValue, { displayText: tile.title });
1258
1440
  if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
1259
1441
  },
1442
+ onClubAction: (actionValue, displayText) => send(actionValue, { displayText }),
1260
1443
  ui,
1261
1444
  slip
1262
1445
  },
1263
1446
  m.id
1264
1447
  )),
1265
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1448
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1266
1449
  } }) : null,
1267
- state.status ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1268
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1269
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1270
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1450
+ state.status ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1451
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1453
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1271
1454
  ] }) : null,
1272
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1273
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: endRef })
1455
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1456
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref: endRef })
1274
1457
  ]
1275
1458
  }
1276
1459
  );
1277
1460
  }
1278
1461
 
1279
1462
  // src/components/ChatInput.tsx
1280
- var import_react8 = require("react");
1281
- var import_jsx_runtime19 = require("react/jsx-runtime");
1463
+ var import_react10 = require("react");
1464
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1282
1465
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1283
- const [value, setValue] = (0, import_react8.useState)("");
1466
+ const [value, setValue] = (0, import_react10.useState)("");
1284
1467
  const submit = () => {
1285
1468
  const t = value.trim();
1286
1469
  if (!t) return;
@@ -1293,18 +1476,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1293
1476
  submit();
1294
1477
  }
1295
1478
  };
1296
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-input", children: [
1297
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1298
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SendIcon, {}) })
1479
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-input", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1481
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SendIcon, {}) })
1299
1482
  ] });
1300
1483
  }
1301
1484
 
1302
1485
  // src/components/ChatPanel.tsx
1303
- var import_jsx_runtime20 = require("react/jsx-runtime");
1486
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1304
1487
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1305
1488
  function useIsModal() {
1306
- const [modal, setModal] = (0, import_react9.useState)(false);
1307
- (0, import_react9.useEffect)(() => {
1489
+ const [modal, setModal] = (0, import_react11.useState)(false);
1490
+ (0, import_react11.useEffect)(() => {
1308
1491
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1309
1492
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1310
1493
  const sync = () => setModal(mql.matches);
@@ -1317,17 +1500,17 @@ function useIsModal() {
1317
1500
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1318
1501
  const { state, close, stop, send } = controller;
1319
1502
  const isModal = useIsModal();
1320
- (0, import_react9.useEffect)(() => {
1503
+ (0, import_react11.useEffect)(() => {
1321
1504
  const onKey = (e) => {
1322
1505
  if (e.key === "Escape") close();
1323
1506
  };
1324
1507
  window.addEventListener("keydown", onKey);
1325
1508
  return () => window.removeEventListener("keydown", onKey);
1326
1509
  }, [close]);
1327
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1328
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1329
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1330
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1510
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1511
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1513
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1331
1514
  ] });
1332
1515
  }
1333
1516
 
@@ -1471,6 +1654,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1471
1654
  .ss-w-bi-comp { font-size: 10.5px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1472
1655
  .ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; gap: 4px; flex: none; }
1473
1656
  .ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }
1657
+ .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; flex: none; }
1474
1658
  .ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }
1475
1659
  .ss-w-bi-mkt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
1476
1660
  .ss-w-bi-market { font-size: 15px; font-weight: 700; line-height: 1.25; color: var(--ss-w-ink); }
@@ -1652,10 +1836,46 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1652
1836
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
1653
1837
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
1654
1838
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
1839
+
1840
+ /* club match-day dashboard */
1841
+ .ss-w-cdash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
1842
+ .ss-w-cdash-block { display: flex; flex-direction: column; }
1843
+
1844
+ .ss-w-cdash-greeting { display: flex; flex-direction: column; gap: 2px; }
1845
+ .ss-w-cdash-greeting-title { font-weight: 700; font-size: 14px; color: var(--ss-w-ink); }
1846
+ .ss-w-cdash-greeting-subtitle { font-size: 11.5px; color: var(--ss-w-faint); }
1847
+
1848
+ .ss-w-cdash-fixture { display: flex; flex-direction: column; align-items: center; gap: 8px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 12px; text-align: center; }
1849
+ .ss-w-cdash-tie { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
1850
+ .ss-w-cdash-team { font-weight: 650; font-size: 13px; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
1851
+ .ss-w-cdash-vs { font-size: 11px; color: var(--ss-w-faint); font-weight: 600; }
1852
+ .ss-w-cdash-crest { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; background: var(--ss-w-bubble); }
1853
+ .ss-w-cdash-crest--fallback { display: grid; place-items: center; font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
1854
+ .ss-w-cdash-fixture-meta { display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--ss-w-faint); }
1855
+ .ss-w-cdash-kickoff { font-weight: 700; color: var(--ss-w-ink); }
1856
+ .ss-w-cdash-cta { font: inherit; font-weight: 700; font-size: 12px; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border: none; border-radius: 999px; padding: 8px 18px; cursor: pointer; }
1857
+
1858
+ .ss-w-cdash-form { display: flex; flex-direction: column; gap: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; }
1859
+ .ss-w-cdash-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
1860
+ .ss-w-cdash-form-name { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
1861
+ .ss-w-cdash-form-pills { flex: none; display: flex; align-items: center; gap: 3px; }
1862
+ .ss-w-cdash-pill { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; font-size: 9.5px; font-weight: 700; color: #fff; }
1863
+ .ss-w-cdash-pill--w { background: color-mix(in srgb, var(--ss-w-pos) 88%, black); }
1864
+ .ss-w-cdash-pill--d { background: var(--ss-w-faint); }
1865
+ .ss-w-cdash-pill--l { background: color-mix(in srgb, var(--ss-w-neg) 88%, black); }
1866
+
1867
+ .ss-w-cdash-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: 100%; text-align: left; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-left: 3px solid var(--ss-w-accent); border-radius: 12px; padding: 10px 12px; font: inherit; cursor: pointer; }
1868
+ .ss-w-cdash-lines-heading { font-size: 12px; font-weight: 700; color: var(--ss-w-accent); }
1869
+ .ss-w-cdash-lines p { font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); }
1870
+
1871
+ .ss-w-cdash-cd { display: flex; flex-direction: column; align-items: center; gap: 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; text-align: center; }
1872
+ .ss-w-cdash-cd-clock { display: flex; align-items: baseline; justify-content: center; gap: 2px; font-variant-numeric: tabular-nums; font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-weight: 700; font-size: 18px; color: var(--ss-w-ink); }
1873
+ .ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
1874
+ .ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
1655
1875
  `;
1656
1876
 
1657
1877
  // src/StatsWidget.tsx
1658
- var import_jsx_runtime21 = require("react/jsx-runtime");
1878
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1659
1879
  function buildClient(props) {
1660
1880
  try {
1661
1881
  if ("client" in props && props.client) {
@@ -1680,11 +1900,11 @@ function injectStyles(root) {
1680
1900
  function StatsWidget(props) {
1681
1901
  const injectedClient = "client" in props ? props.client : void 0;
1682
1902
  const cfg = props.config;
1683
- const built = (0, import_react10.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
1684
- const ui = (0, import_react10.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
1685
- const rootRef = (0, import_react10.useRef)(null);
1903
+ const built = (0, import_react12.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
1904
+ const ui = (0, import_react12.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
1905
+ const rootRef = (0, import_react12.useRef)(null);
1686
1906
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
1687
- const slip = (0, import_react10.useMemo)(
1907
+ const slip = (0, import_react12.useMemo)(
1688
1908
  () => ({
1689
1909
  onAddToSlip: props.config?.onAddToSlip,
1690
1910
  conversationId: controller.state.conversationId ?? void 0,
@@ -1697,18 +1917,18 @@ function StatsWidget(props) {
1697
1917
  }),
1698
1918
  [props.config?.onAddToSlip, controller.state.conversationId, built]
1699
1919
  );
1700
- const onDashboardTap = (0, import_react10.useMemo)(
1920
+ const onDashboardTap = (0, import_react12.useMemo)(
1701
1921
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
1702
1922
  [built]
1703
1923
  );
1704
- (0, import_react10.useEffect)(() => {
1924
+ (0, import_react12.useEffect)(() => {
1705
1925
  if (!built || !ui.injectStyles) return;
1706
1926
  const node = rootRef.current?.getRootNode();
1707
1927
  if (node) injectStyles(node);
1708
1928
  }, [built, ui.injectStyles]);
1709
1929
  if (!built) return null;
1710
1930
  const attrs = themeAttrs(ui);
1711
- return /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1931
+ return /* @__PURE__ */ (0, import_jsx_runtime28.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_runtime28.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1712
1932
  ChatFab,
1713
1933
  {
1714
1934
  label: ui.launcherLabel,