@sensiblestats/widget-react 0.3.0 → 0.5.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 +21 -0
- package/dist/index.cjs +183 -59
- 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 +171 -47
- package/dist/index.js.map +1 -1
- package/dist/styles.css +30 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,6 @@ type StatsWidgetProps = {
|
|
|
33
33
|
};
|
|
34
34
|
declare function StatsWidget(props: StatsWidgetProps): JSX.Element | null;
|
|
35
35
|
|
|
36
|
-
declare const WIDGET_CSS = ".ss-w-root { all: revert; }\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\n.ss-w-root {\n --ss-w-accent: #17936a;\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\n}\n@media (prefers-color-scheme: dark) {\n .ss-w-root[data-ss-w-theme=\"auto\"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n }\n}\n.ss-w-root[data-ss-w-theme=\"dark\"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n}\n.ss-w-root[data-ss-w-theme=\"light\"] {\n --ss-w-accent: #17936a; --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n}\n\n/* launcher */\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\n.ss-w-root[data-ss-w-pos=\"right\"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos=\"left\"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\n.ss-w-fab-mark { width: 30px; height: 30px; display: block; }\n.ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\n.ss-w-greeting-body { flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }\n.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }\n\n/* panel */\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(400px, calc(100vw - 40px)); height: min(620px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\n.ss-w-root[data-ss-w-pos=\"right\"] .ss-w-panel { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos=\"left\"] .ss-w-panel { left: var(--ss-w-offset-x); }\n@media (max-width: 639px) {\n /* Fill via inset with no explicit height (like the site's working panel) so the\n input stays visible when the mobile keyboard/URL-bar shrinks the viewport. The\n position-specific selectors override the right/left offsets set above. */\n .ss-w-root[data-ss-w-pos=\"right\"] .ss-w-panel,\n .ss-w-root[data-ss-w-pos=\"left\"] .ss-w-panel { inset: 0; width: auto; height: auto; border: none; border-radius: 0; }\n}\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\n.ss-w-header-mark { width: 18px; height: 18px; display: block; }\n.ss-w-header-title { font-weight: 660; }\n.ss-w-close { margin-left: auto; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\n\n/* messages */\n.ss-w-list { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }\n.ss-w-msg { display: flex; }\n.ss-w-user { justify-content: flex-end; }\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\n.ss-w-bot { flex-direction: column; gap: 8px; }\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\n\n/* markdown */\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\n.ss-w-md > *:first-child { margin-top: 0; }\n.ss-w-md > *:last-child { margin-bottom: 0; }\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\n.ss-w-table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }\n.ss-w-md-table { border-collapse: collapse; width: max-content; min-width: 100%; font-variant-numeric: tabular-nums; }\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; white-space: nowrap; }\n.ss-w-md-table th { background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); font-weight: 700; }\n.ss-w-md-table tbody tr:nth-child(even) { background: var(--ss-w-bubble); }\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\n\n/* entity cards */\n.ss-w-cards { display: flex; flex-direction: column; gap: 7px; }\n.ss-w-ecard { display: flex; align-items: center; gap: 11px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; }\n.ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }\n.ss-w-thumb.ss-w-team { border-radius: 10px; }\n.ss-w-ecard[data-kind=\"player\"] .ss-w-thumb { background-color: var(--ss-w-accent); }\n.ss-w-meta { display: flex; flex-direction: column; min-width: 0; }\n.ss-w-kind { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }\n.ss-w-nm { font-weight: 660; }\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }\n.ss-w-stat { margin-left: auto; text-align: center; }\n.ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }\n.ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }\n.ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }\n.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }\n.ss-w-cards-more:disabled { opacity: .5; cursor: default; }\n\n/* action buttons */\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }\n.ss-w-abtn:disabled { opacity: .5; cursor: default; }\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\n\n/* intent chips */\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\n\n/* input */\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\n.ss-w-textarea:disabled { opacity: .55; cursor: not-allowed; }\n/* iOS Safari zooms the page when a focused field's font-size is < 16px. Bump it\n on touch devices only, so the desktop 13px design is unchanged. */\n@media (pointer: coarse) {\n .ss-w-textarea { font-size: 16px; }\n}\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\n\n@media (prefers-reduced-motion: reduce) {\n .ss-w-abtn-shimmer { animation: none; }\n}\n";
|
|
36
|
+
declare const WIDGET_CSS = ".ss-w-root { all: revert; }\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\n.ss-w-root {\n --ss-w-accent: #17936a;\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\n}\n@media (prefers-color-scheme: dark) {\n .ss-w-root[data-ss-w-theme=\"auto\"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n }\n}\n.ss-w-root[data-ss-w-theme=\"dark\"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n}\n.ss-w-root[data-ss-w-theme=\"light\"] {\n --ss-w-accent: #17936a; --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n}\n\n/* launcher */\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\n.ss-w-root[data-ss-w-pos=\"right\"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos=\"left\"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\n.ss-w-fab-mark { width: 30px; height: 30px; display: block; }\n.ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\n.ss-w-greeting-body { flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }\n.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }\n\n/* panel */\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(400px, calc(100vw - 40px)); height: min(620px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\n.ss-w-root[data-ss-w-pos=\"right\"] .ss-w-panel { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos=\"left\"] .ss-w-panel { left: var(--ss-w-offset-x); }\n@media (max-width: 639px) {\n /* Fill via inset with no explicit height (like the site's working panel) so the\n input stays visible when the mobile keyboard/URL-bar shrinks the viewport. The\n position-specific selectors override the right/left offsets set above. */\n .ss-w-root[data-ss-w-pos=\"right\"] .ss-w-panel,\n .ss-w-root[data-ss-w-pos=\"left\"] .ss-w-panel { inset: 0; width: auto; height: auto; border: none; border-radius: 0; }\n}\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\n.ss-w-header-mark { width: 18px; height: 18px; display: block; }\n.ss-w-header-title { font-weight: 660; }\n.ss-w-close { margin-left: auto; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\n\n/* messages */\n.ss-w-list { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }\n.ss-w-msg { display: flex; }\n.ss-w-user { justify-content: flex-end; }\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\n.ss-w-bot { flex-direction: column; gap: 8px; }\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\n\n/* markdown */\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\n.ss-w-md > *:first-child { margin-top: 0; }\n.ss-w-md > *:last-child { margin-bottom: 0; }\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\n.ss-w-table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }\n.ss-w-md-table { border-collapse: collapse; width: max-content; min-width: 100%; font-variant-numeric: tabular-nums; }\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; white-space: nowrap; }\n.ss-w-md-table th { background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); font-weight: 700; }\n.ss-w-md-table tbody tr:nth-child(even) { background: var(--ss-w-bubble); }\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\n\n/* entity cards */\n.ss-w-cards { display: flex; flex-direction: column; gap: 7px; }\n.ss-w-ecard { display: flex; align-items: center; gap: 11px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; }\n.ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }\n.ss-w-thumb.ss-w-team { border-radius: 10px; }\n.ss-w-ecard[data-kind=\"player\"] .ss-w-thumb { background-color: var(--ss-w-accent); }\n.ss-w-meta { display: flex; flex-direction: column; min-width: 0; }\n.ss-w-kind { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }\n.ss-w-nm { font-weight: 660; }\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }\n.ss-w-stat { margin-left: auto; text-align: center; }\n.ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }\n.ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }\n.ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }\n.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }\n.ss-w-cards-more:disabled { opacity: .5; cursor: default; }\n\n/* betting insights */\n.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }\n.ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }\n.ss-w-bi-status { display: flex; align-items: center; gap: 6px; min-width: 0; }\n.ss-w-bi-fixture { font-size: 11px; color: var(--ss-w-ink); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.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; }\n.ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }\n.ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }\n.ss-w-bi-mkt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }\n.ss-w-bi-market { font-size: 13px; font-weight: 660; line-height: 1.3; color: var(--ss-w-ink); }\n.ss-w-bi-sel { font-size: 11px; line-height: 1.3; color: var(--ss-w-faint); }\n.ss-w-bi-odds { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 24%, var(--ss-w-line)); border-radius: 8px; padding: 3px 9px; min-width: 56px; }\n.ss-w-bi-odds-cap { font-size: 8px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ss-w-faint); }\n.ss-w-bi-odds b { font-size: 15px; font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.15; }\n.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }\n.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }\n.ss-w-bi-rows { display: flex; flex-direction: column; }\n.ss-w-bi-row { display: flex; align-items: baseline; gap: 8px; padding: 4px 0; border-top: 1px solid var(--ss-w-line); }\n.ss-w-bi-row:first-child { border-top: none; }\n.ss-w-bi-row-lbl { font-size: 11px; color: var(--ss-w-faint); min-width: 0; }\n.ss-w-bi-row-dots { flex: 1; border-bottom: 1px dotted var(--ss-w-line); transform: translateY(-3px); min-width: 12px; }\n.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 12.5px; flex: none; color: var(--ss-w-ink); }\n.ss-w-bi-more { align-self: flex-start; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11px; font-weight: 560; padding: 2px 0; cursor: pointer; }\n.ss-w-bi-more:hover { text-decoration: underline; }\n.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\n.ss-w-bi-scoped { display: flex; flex-direction: column; gap: 6px; }\n.ss-w-bi-scopes { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }\n.ss-w-bi-chip { font-size: 11px; font-weight: 550; border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 3px 10px; color: var(--ss-w-ink); background: var(--ss-w-bubble); cursor: pointer; }\n.ss-w-bi-chip[aria-pressed=\"true\"] { color: #fff; background: var(--ss-w-accent); border-color: var(--ss-w-accent); }\n\n/* action buttons */\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }\n.ss-w-abtn:disabled { opacity: .5; cursor: default; }\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\n\n/* intent chips */\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\n\n/* input */\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\n.ss-w-textarea:disabled { opacity: .55; cursor: not-allowed; }\n/* iOS Safari zooms the page when a focused field's font-size is < 16px. Bump it\n on touch devices only, so the desktop 13px design is unchanged. */\n@media (pointer: coarse) {\n .ss-w-textarea { font-size: 16px; }\n}\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\n\n@media (prefers-reduced-motion: reduce) {\n .ss-w-abtn-shimmer { animation: none; }\n}\n";
|
|
37
37
|
|
|
38
38
|
export { StatsWidget, type StatsWidgetConfig, type StatsWidgetProps, WIDGET_CSS };
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,9 @@ var STRINGS = {
|
|
|
15
15
|
somethingWentWrong: "Something went wrong.",
|
|
16
16
|
retry: "Retry",
|
|
17
17
|
showLess: "Show less",
|
|
18
|
-
showMore: (n) => `Show ${n} more
|
|
18
|
+
showMore: (n) => `Show ${n} more`,
|
|
19
|
+
oddsLabel: "Odds",
|
|
20
|
+
liveLabel: "Live"
|
|
19
21
|
},
|
|
20
22
|
tr: {
|
|
21
23
|
launcherLabel: "SensibleStats ile sohbet et",
|
|
@@ -28,7 +30,9 @@ var STRINGS = {
|
|
|
28
30
|
somethingWentWrong: "Bir \u015Feyler ters gitti.",
|
|
29
31
|
retry: "Tekrar dene",
|
|
30
32
|
showLess: "Daha az g\xF6ster",
|
|
31
|
-
showMore: (n) => `${n} tane daha g\xF6ster
|
|
33
|
+
showMore: (n) => `${n} tane daha g\xF6ster`,
|
|
34
|
+
oddsLabel: "Oran",
|
|
35
|
+
liveLabel: "Canl\u0131"
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
38
|
function resolveLocaleStrings(locale) {
|
|
@@ -58,7 +62,9 @@ function normalizeUi(cfg) {
|
|
|
58
62
|
somethingWentWrong: strings.somethingWentWrong,
|
|
59
63
|
retry: strings.retry,
|
|
60
64
|
showLess: strings.showLess,
|
|
61
|
-
showMore: strings.showMore
|
|
65
|
+
showMore: strings.showMore,
|
|
66
|
+
oddsLabel: strings.oddsLabel,
|
|
67
|
+
liveLabel: strings.liveLabel
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
70
|
function toClientOptions(cfg) {
|
|
@@ -95,16 +101,19 @@ function str(v) {
|
|
|
95
101
|
function num(v) {
|
|
96
102
|
return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
|
|
97
103
|
}
|
|
98
|
-
function
|
|
99
|
-
if (!Array.isArray(
|
|
104
|
+
function readStatCells(raw) {
|
|
105
|
+
if (!Array.isArray(raw)) return [];
|
|
100
106
|
const cells = [];
|
|
101
|
-
for (const entry of
|
|
107
|
+
for (const entry of raw) {
|
|
102
108
|
const label = str(entry.label);
|
|
103
109
|
const value = num(entry.value) ?? str(entry.value);
|
|
104
110
|
if (label !== void 0 && value !== void 0) cells.push({ label, value });
|
|
105
111
|
}
|
|
106
112
|
return cells;
|
|
107
113
|
}
|
|
114
|
+
function readStats(card) {
|
|
115
|
+
return readStatCells(card.stats);
|
|
116
|
+
}
|
|
108
117
|
function toCardVM(card) {
|
|
109
118
|
const entityType = str(card.entityType)?.toLowerCase();
|
|
110
119
|
const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
|
|
@@ -130,6 +139,31 @@ function toChipVM(intent) {
|
|
|
130
139
|
function chipFromText(text) {
|
|
131
140
|
return { text };
|
|
132
141
|
}
|
|
142
|
+
function toInsightVM(insight) {
|
|
143
|
+
const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
|
|
144
|
+
const selection = [str(insight.selectionLabel), str(insight.line)].filter(Boolean).join(" ") || void 0;
|
|
145
|
+
const value = insight.odds?.value;
|
|
146
|
+
const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
|
|
147
|
+
const home = str(insight.homeTeamName);
|
|
148
|
+
const away = str(insight.awayTeamName);
|
|
149
|
+
const fixture = home && away ? `${home} vs ${away}` : void 0;
|
|
150
|
+
const scopes = Array.isArray(insight.scopes) ? insight.scopes.map((s) => ({ key: str(s.key), label: str(s.label), stats: readStatCells(s.stats) })).filter((s) => !!s.key && !!s.label) : void 0;
|
|
151
|
+
return {
|
|
152
|
+
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
153
|
+
market,
|
|
154
|
+
selection,
|
|
155
|
+
odds,
|
|
156
|
+
// The wire payload carries bookmakerId (not a name); render a name only if one is present.
|
|
157
|
+
bookmaker: str(insight.odds?.bookmakerName),
|
|
158
|
+
isLive: insight.odds?.isLive === true,
|
|
159
|
+
phase: str(insight.phase),
|
|
160
|
+
fixture,
|
|
161
|
+
scopes,
|
|
162
|
+
text: str(insight.text) ?? "",
|
|
163
|
+
stats: readStatCells(insight.stats),
|
|
164
|
+
disclaimer: str(insight.disclaimer)
|
|
165
|
+
};
|
|
166
|
+
}
|
|
133
167
|
|
|
134
168
|
// src/reducer.ts
|
|
135
169
|
var POPUP_MAX = 160;
|
|
@@ -156,6 +190,8 @@ function applyEvent(state, event) {
|
|
|
156
190
|
return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, toCardVM(event.data.card)] })) };
|
|
157
191
|
case "action_button":
|
|
158
192
|
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
193
|
+
case "betting_insight":
|
|
194
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) };
|
|
159
195
|
case "intent_chip": {
|
|
160
196
|
const chip = toChipVM(event.data.intent);
|
|
161
197
|
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
@@ -173,6 +209,7 @@ function applyEvent(state, event) {
|
|
|
173
209
|
return { ...state, error: suppress ? state.error : event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
174
210
|
}
|
|
175
211
|
}
|
|
212
|
+
return state;
|
|
176
213
|
}
|
|
177
214
|
function reducer(state, action) {
|
|
178
215
|
switch (action.kind) {
|
|
@@ -182,11 +219,11 @@ function reducer(state, action) {
|
|
|
182
219
|
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
183
220
|
case "USER_SENT": {
|
|
184
221
|
const user = { role: "user", id: action.userId, text: action.displayText ?? action.input.message };
|
|
185
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false };
|
|
222
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false };
|
|
186
223
|
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null };
|
|
187
224
|
}
|
|
188
225
|
case "GREETING_SENT": {
|
|
189
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false, isGreeting: true };
|
|
226
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false, isGreeting: true };
|
|
190
227
|
return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null };
|
|
191
228
|
}
|
|
192
229
|
case "DISMISS_POPUP":
|
|
@@ -308,7 +345,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
308
345
|
}
|
|
309
346
|
|
|
310
347
|
// src/components/ChatPanel.tsx
|
|
311
|
-
import { useEffect as useEffect3, useState as
|
|
348
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
312
349
|
|
|
313
350
|
// src/components/ChatHeader.tsx
|
|
314
351
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -374,37 +411,94 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
374
411
|
] });
|
|
375
412
|
}
|
|
376
413
|
|
|
414
|
+
// src/components/BettingInsightList.tsx
|
|
415
|
+
import { useState as useState2 } from "react";
|
|
416
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
417
|
+
var MAX_ROWS = 3;
|
|
418
|
+
function StatRows({ stats, ui }) {
|
|
419
|
+
const [expanded, setExpanded] = useState2(false);
|
|
420
|
+
const shown = expanded ? stats : stats.slice(0, MAX_ROWS);
|
|
421
|
+
const overflow = stats.length - MAX_ROWS;
|
|
422
|
+
return /* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-rows", children: [
|
|
423
|
+
shown.map((s) => /* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-row", children: [
|
|
424
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
425
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-row-dots", "aria-hidden": "true" }),
|
|
426
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
427
|
+
] }, `${s.label}:${s.value}`)),
|
|
428
|
+
overflow > 0 ? /* @__PURE__ */ jsx7("button", { type: "button", className: "ss-w-bi-more", onClick: () => setExpanded((v) => !v), children: expanded ? ui?.showLess ?? "Show less" : (ui?.showMore ?? ((n) => `Show ${n} more`))(overflow) }) : null
|
|
429
|
+
] });
|
|
430
|
+
}
|
|
431
|
+
function ScopedStats({ scopes, ui }) {
|
|
432
|
+
const [active, setActive] = useState2(0);
|
|
433
|
+
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
434
|
+
return /* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-scoped", children: [
|
|
435
|
+
/* @__PURE__ */ jsx7("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx7("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
436
|
+
/* @__PURE__ */ jsx7(StatRows, { stats: current.stats, ui }, current.key)
|
|
437
|
+
] });
|
|
438
|
+
}
|
|
439
|
+
function InsightCard({ it, ui }) {
|
|
440
|
+
const live = it.isLive || it.phase === "live";
|
|
441
|
+
return /* @__PURE__ */ jsxs5("div", { className: "ss-w-binsight", children: [
|
|
442
|
+
live || it.fixture ? /* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-status", children: [
|
|
443
|
+
live ? /* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-live", children: [
|
|
444
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
445
|
+
ui?.liveLabel ?? "Live"
|
|
446
|
+
] }) : null,
|
|
447
|
+
it.fixture ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-fixture", children: it.fixture }) : null
|
|
448
|
+
] }) : null,
|
|
449
|
+
/* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-head", children: [
|
|
450
|
+
/* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-mkt", children: [
|
|
451
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-market", children: it.market }),
|
|
452
|
+
it.selection ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-sel", children: it.selection }) : null
|
|
453
|
+
] }),
|
|
454
|
+
it.odds ? /* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-odds", children: [
|
|
455
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-odds-cap", children: ui?.oddsLabel ?? "Odds" }),
|
|
456
|
+
/* @__PURE__ */ jsx7("b", { children: it.odds }),
|
|
457
|
+
it.bookmaker ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
458
|
+
] }) : null
|
|
459
|
+
] }),
|
|
460
|
+
it.text ? /* @__PURE__ */ jsx7("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
461
|
+
it.scopes && it.scopes.length >= 2 ? /* @__PURE__ */ jsx7(ScopedStats, { scopes: it.scopes, ui }) : it.stats.length > 0 ? /* @__PURE__ */ jsx7(StatRows, { stats: it.stats, ui }) : null,
|
|
462
|
+
it.disclaimer ? /* @__PURE__ */ jsx7("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
463
|
+
] });
|
|
464
|
+
}
|
|
465
|
+
function BettingInsightList({ insights, ui }) {
|
|
466
|
+
if (!insights || insights.length === 0) return null;
|
|
467
|
+
return /* @__PURE__ */ jsx7("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ jsx7(InsightCard, { it, ui }, it.id)) });
|
|
468
|
+
}
|
|
469
|
+
|
|
377
470
|
// src/components/ActionButtons.tsx
|
|
378
|
-
import { Fragment, jsx as
|
|
471
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
379
472
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
380
473
|
if (actions.length === 0 && !loading) return null;
|
|
381
|
-
return /* @__PURE__ */
|
|
382
|
-
actions.map((a, i) => /* @__PURE__ */
|
|
383
|
-
actions.length === 0 && loading ? /* @__PURE__ */
|
|
384
|
-
/* @__PURE__ */
|
|
385
|
-
/* @__PURE__ */
|
|
474
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ss-w-actions", children: [
|
|
475
|
+
actions.map((a, i) => /* @__PURE__ */ jsx8("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
476
|
+
actions.length === 0 && loading ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
477
|
+
/* @__PURE__ */ jsx8("span", { className: "ss-w-abtn-shimmer" }),
|
|
478
|
+
/* @__PURE__ */ jsx8("span", { className: "ss-w-abtn-shimmer" })
|
|
386
479
|
] }) : null
|
|
387
480
|
] });
|
|
388
481
|
}
|
|
389
482
|
|
|
390
483
|
// src/components/ChatMessage.tsx
|
|
391
|
-
import { jsx as
|
|
484
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
392
485
|
function ChatMessage({ message, disabled, onAct, ui }) {
|
|
393
486
|
if (message.role === "user") {
|
|
394
|
-
return /* @__PURE__ */
|
|
487
|
+
return /* @__PURE__ */ jsx9("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx9("div", { className: "ss-w-bubble", children: message.text }) });
|
|
395
488
|
}
|
|
396
|
-
return /* @__PURE__ */
|
|
397
|
-
message.text ? /* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
489
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
490
|
+
message.text ? /* @__PURE__ */ jsx9(Markdown, { text: message.text }) : null,
|
|
491
|
+
/* @__PURE__ */ jsx9(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
492
|
+
/* @__PURE__ */ jsx9(BettingInsightList, { insights: message.insights, ui }),
|
|
493
|
+
/* @__PURE__ */ jsx9(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
400
494
|
] });
|
|
401
495
|
}
|
|
402
496
|
|
|
403
497
|
// src/components/IntentChips.tsx
|
|
404
|
-
import { jsx as
|
|
498
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
405
499
|
function IntentChips({ chips, onPick }) {
|
|
406
500
|
if (chips.length === 0) return null;
|
|
407
|
-
return /* @__PURE__ */
|
|
501
|
+
return /* @__PURE__ */ jsx10("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx10("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
408
502
|
}
|
|
409
503
|
|
|
410
504
|
// src/scroll.ts
|
|
@@ -414,7 +508,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
414
508
|
}
|
|
415
509
|
|
|
416
510
|
// src/components/MessageList.tsx
|
|
417
|
-
import { jsx as
|
|
511
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
418
512
|
function MessageList({ controller, ui }) {
|
|
419
513
|
const { state, send } = controller;
|
|
420
514
|
const listRef = useRef2(null);
|
|
@@ -424,7 +518,7 @@ function MessageList({ controller, ui }) {
|
|
|
424
518
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
425
519
|
}, [state.messages, state.status]);
|
|
426
520
|
const empty = state.messages.length === 0;
|
|
427
|
-
return /* @__PURE__ */
|
|
521
|
+
return /* @__PURE__ */ jsxs8(
|
|
428
522
|
"div",
|
|
429
523
|
{
|
|
430
524
|
className: "ss-w-list",
|
|
@@ -434,7 +528,7 @@ function MessageList({ controller, ui }) {
|
|
|
434
528
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
435
529
|
},
|
|
436
530
|
children: [
|
|
437
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
531
|
+
state.messages.map((m) => /* @__PURE__ */ jsx11(
|
|
438
532
|
ChatMessage,
|
|
439
533
|
{
|
|
440
534
|
message: m,
|
|
@@ -444,25 +538,25 @@ function MessageList({ controller, ui }) {
|
|
|
444
538
|
},
|
|
445
539
|
m.id
|
|
446
540
|
)),
|
|
447
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
541
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx11(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
448
542
|
} }) : null,
|
|
449
|
-
state.status ? /* @__PURE__ */
|
|
450
|
-
state.error ? /* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
452
|
-
/* @__PURE__ */
|
|
543
|
+
state.status ? /* @__PURE__ */ jsx11("div", { className: "ss-w-status", children: state.status }) : null,
|
|
544
|
+
state.error ? /* @__PURE__ */ jsxs8("div", { className: "ss-w-error", role: "alert", children: [
|
|
545
|
+
/* @__PURE__ */ jsx11("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
546
|
+
/* @__PURE__ */ jsx11("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
453
547
|
] }) : null,
|
|
454
|
-
empty ? /* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
548
|
+
empty ? /* @__PURE__ */ jsx11(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
549
|
+
/* @__PURE__ */ jsx11("div", { ref: endRef })
|
|
456
550
|
]
|
|
457
551
|
}
|
|
458
552
|
);
|
|
459
553
|
}
|
|
460
554
|
|
|
461
555
|
// src/components/ChatInput.tsx
|
|
462
|
-
import { useState as
|
|
463
|
-
import { jsx as
|
|
556
|
+
import { useState as useState3 } from "react";
|
|
557
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
464
558
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
465
|
-
const [value, setValue] =
|
|
559
|
+
const [value, setValue] = useState3("");
|
|
466
560
|
const submit = () => {
|
|
467
561
|
const t = value.trim();
|
|
468
562
|
if (!t) return;
|
|
@@ -475,17 +569,17 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
475
569
|
submit();
|
|
476
570
|
}
|
|
477
571
|
};
|
|
478
|
-
return /* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
480
|
-
streaming ? /* @__PURE__ */
|
|
572
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-input", children: [
|
|
573
|
+
/* @__PURE__ */ jsx12("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
574
|
+
streaming ? /* @__PURE__ */ jsx12("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx12("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx12("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx12(SendIcon, {}) })
|
|
481
575
|
] });
|
|
482
576
|
}
|
|
483
577
|
|
|
484
578
|
// src/components/ChatPanel.tsx
|
|
485
|
-
import { jsx as
|
|
579
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
486
580
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
487
581
|
function useIsModal() {
|
|
488
|
-
const [modal, setModal] =
|
|
582
|
+
const [modal, setModal] = useState4(false);
|
|
489
583
|
useEffect3(() => {
|
|
490
584
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
491
585
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
@@ -506,10 +600,10 @@ function ChatPanel({ controller, ui }) {
|
|
|
506
600
|
window.addEventListener("keydown", onKey);
|
|
507
601
|
return () => window.removeEventListener("keydown", onKey);
|
|
508
602
|
}, [close]);
|
|
509
|
-
return /* @__PURE__ */
|
|
510
|
-
/* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
603
|
+
return /* @__PURE__ */ jsxs10("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
604
|
+
/* @__PURE__ */ jsx13(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
605
|
+
/* @__PURE__ */ jsx13(MessageList, { controller, ui }),
|
|
606
|
+
/* @__PURE__ */ jsx13(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
513
607
|
] });
|
|
514
608
|
}
|
|
515
609
|
|
|
@@ -608,6 +702,36 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
608
702
|
.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }
|
|
609
703
|
.ss-w-cards-more:disabled { opacity: .5; cursor: default; }
|
|
610
704
|
|
|
705
|
+
/* betting insights */
|
|
706
|
+
.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }
|
|
707
|
+
.ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }
|
|
708
|
+
.ss-w-bi-status { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
709
|
+
.ss-w-bi-fixture { font-size: 11px; color: var(--ss-w-ink); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
710
|
+
.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; }
|
|
711
|
+
.ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }
|
|
712
|
+
.ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }
|
|
713
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
|
714
|
+
.ss-w-bi-market { font-size: 13px; font-weight: 660; line-height: 1.3; color: var(--ss-w-ink); }
|
|
715
|
+
.ss-w-bi-sel { font-size: 11px; line-height: 1.3; color: var(--ss-w-faint); }
|
|
716
|
+
.ss-w-bi-odds { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 24%, var(--ss-w-line)); border-radius: 8px; padding: 3px 9px; min-width: 56px; }
|
|
717
|
+
.ss-w-bi-odds-cap { font-size: 8px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
718
|
+
.ss-w-bi-odds b { font-size: 15px; font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.15; }
|
|
719
|
+
.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }
|
|
720
|
+
.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }
|
|
721
|
+
.ss-w-bi-rows { display: flex; flex-direction: column; }
|
|
722
|
+
.ss-w-bi-row { display: flex; align-items: baseline; gap: 8px; padding: 4px 0; border-top: 1px solid var(--ss-w-line); }
|
|
723
|
+
.ss-w-bi-row:first-child { border-top: none; }
|
|
724
|
+
.ss-w-bi-row-lbl { font-size: 11px; color: var(--ss-w-faint); min-width: 0; }
|
|
725
|
+
.ss-w-bi-row-dots { flex: 1; border-bottom: 1px dotted var(--ss-w-line); transform: translateY(-3px); min-width: 12px; }
|
|
726
|
+
.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 12.5px; flex: none; color: var(--ss-w-ink); }
|
|
727
|
+
.ss-w-bi-more { align-self: flex-start; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11px; font-weight: 560; padding: 2px 0; cursor: pointer; }
|
|
728
|
+
.ss-w-bi-more:hover { text-decoration: underline; }
|
|
729
|
+
.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }
|
|
730
|
+
.ss-w-bi-scoped { display: flex; flex-direction: column; gap: 6px; }
|
|
731
|
+
.ss-w-bi-scopes { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
|
|
732
|
+
.ss-w-bi-chip { font-size: 11px; font-weight: 550; border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 3px 10px; color: var(--ss-w-ink); background: var(--ss-w-bubble); cursor: pointer; }
|
|
733
|
+
.ss-w-bi-chip[aria-pressed="true"] { color: #fff; background: var(--ss-w-accent); border-color: var(--ss-w-accent); }
|
|
734
|
+
|
|
611
735
|
/* action buttons */
|
|
612
736
|
.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
613
737
|
.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }
|
|
@@ -637,7 +761,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
637
761
|
`;
|
|
638
762
|
|
|
639
763
|
// src/StatsWidget.tsx
|
|
640
|
-
import { jsx as
|
|
764
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
641
765
|
function buildClient(props) {
|
|
642
766
|
try {
|
|
643
767
|
if ("client" in props && props.client) {
|
|
@@ -673,7 +797,7 @@ function StatsWidget(props) {
|
|
|
673
797
|
}, [built, ui.injectStyles]);
|
|
674
798
|
if (!built) return null;
|
|
675
799
|
const attrs = themeAttrs(ui);
|
|
676
|
-
return /* @__PURE__ */
|
|
800
|
+
return /* @__PURE__ */ jsx14("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__ */ jsx14(ChatPanel, { controller, ui }) : /* @__PURE__ */ jsx14(
|
|
677
801
|
ChatFab,
|
|
678
802
|
{
|
|
679
803
|
label: ui.launcherLabel,
|