@sensiblestats/widget-react 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.cjs +107 -40
- 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 +107 -40
- package/dist/index.js.map +1 -1
- package/dist/styles.css +17 -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-head { display: flex; align-items: flex-start; gap: 10px; }\n.ss-w-bi-mkt { display: flex; flex-direction: column; min-width: 0; }\n.ss-w-bi-market { 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-bi-sel { font-weight: 660; }\n.ss-w-bi-odds { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }\n.ss-w-bi-odds b { font-size: 15px; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); }\n.ss-w-bi-book { font-size: 10px; color: var(--ss-w-faint); }\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; }\n.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }\n.ss-w-bi-stats { display: flex; flex-wrap: wrap; gap: 12px; }\n.ss-w-bi-stat b { display: block; font-variant-numeric: tabular-nums; font-weight: 660; }\n.ss-w-bi-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }\n.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\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
|
@@ -95,16 +95,19 @@ function str(v) {
|
|
|
95
95
|
function num(v) {
|
|
96
96
|
return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
|
|
97
97
|
}
|
|
98
|
-
function
|
|
99
|
-
if (!Array.isArray(
|
|
98
|
+
function readStatCells(raw) {
|
|
99
|
+
if (!Array.isArray(raw)) return [];
|
|
100
100
|
const cells = [];
|
|
101
|
-
for (const entry of
|
|
101
|
+
for (const entry of raw) {
|
|
102
102
|
const label = str(entry.label);
|
|
103
103
|
const value = num(entry.value) ?? str(entry.value);
|
|
104
104
|
if (label !== void 0 && value !== void 0) cells.push({ label, value });
|
|
105
105
|
}
|
|
106
106
|
return cells;
|
|
107
107
|
}
|
|
108
|
+
function readStats(card) {
|
|
109
|
+
return readStatCells(card.stats);
|
|
110
|
+
}
|
|
108
111
|
function toCardVM(card) {
|
|
109
112
|
const entityType = str(card.entityType)?.toLowerCase();
|
|
110
113
|
const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
|
|
@@ -130,6 +133,24 @@ function toChipVM(intent) {
|
|
|
130
133
|
function chipFromText(text) {
|
|
131
134
|
return { text };
|
|
132
135
|
}
|
|
136
|
+
function toInsightVM(insight) {
|
|
137
|
+
const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
|
|
138
|
+
const selection = [str(insight.selectionLabel), str(insight.line)].filter(Boolean).join(" ") || void 0;
|
|
139
|
+
const value = insight.odds?.value;
|
|
140
|
+
const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
|
|
141
|
+
return {
|
|
142
|
+
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
143
|
+
market,
|
|
144
|
+
selection,
|
|
145
|
+
odds,
|
|
146
|
+
// The wire payload carries bookmakerId (not a name); render a name only if one is present.
|
|
147
|
+
bookmaker: str(insight.odds?.bookmakerName),
|
|
148
|
+
isLive: insight.odds?.isLive === true,
|
|
149
|
+
text: str(insight.text) ?? "",
|
|
150
|
+
stats: readStatCells(insight.stats),
|
|
151
|
+
disclaimer: str(insight.disclaimer)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
133
154
|
|
|
134
155
|
// src/reducer.ts
|
|
135
156
|
var POPUP_MAX = 160;
|
|
@@ -156,6 +177,8 @@ function applyEvent(state, event) {
|
|
|
156
177
|
return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, toCardVM(event.data.card)] })) };
|
|
157
178
|
case "action_button":
|
|
158
179
|
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
180
|
+
case "betting_insight":
|
|
181
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) };
|
|
159
182
|
case "intent_chip": {
|
|
160
183
|
const chip = toChipVM(event.data.intent);
|
|
161
184
|
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
@@ -173,6 +196,7 @@ function applyEvent(state, event) {
|
|
|
173
196
|
return { ...state, error: suppress ? state.error : event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
174
197
|
}
|
|
175
198
|
}
|
|
199
|
+
return state;
|
|
176
200
|
}
|
|
177
201
|
function reducer(state, action) {
|
|
178
202
|
switch (action.kind) {
|
|
@@ -182,11 +206,11 @@ function reducer(state, action) {
|
|
|
182
206
|
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
183
207
|
case "USER_SENT": {
|
|
184
208
|
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 };
|
|
209
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false };
|
|
186
210
|
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null };
|
|
187
211
|
}
|
|
188
212
|
case "GREETING_SENT": {
|
|
189
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false, isGreeting: true };
|
|
213
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false, isGreeting: true };
|
|
190
214
|
return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null };
|
|
191
215
|
}
|
|
192
216
|
case "DISMISS_POPUP":
|
|
@@ -374,37 +398,63 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
|
|
|
374
398
|
] });
|
|
375
399
|
}
|
|
376
400
|
|
|
401
|
+
// src/components/BettingInsightList.tsx
|
|
402
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
403
|
+
function BettingInsightList({ insights }) {
|
|
404
|
+
if (!insights || insights.length === 0) return null;
|
|
405
|
+
return /* @__PURE__ */ jsx7("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ jsxs5("div", { className: "ss-w-binsight", children: [
|
|
406
|
+
/* @__PURE__ */ jsxs5("div", { className: "ss-w-bi-head", children: [
|
|
407
|
+
/* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-mkt", children: [
|
|
408
|
+
/* @__PURE__ */ jsx7("span", { className: "ss-w-bi-market", children: it.market }),
|
|
409
|
+
it.selection ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-sel", children: it.selection }) : null
|
|
410
|
+
] }),
|
|
411
|
+
it.odds ? /* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-odds", children: [
|
|
412
|
+
it.isLive ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-live", children: "Live" }) : null,
|
|
413
|
+
/* @__PURE__ */ jsx7("b", { children: it.odds }),
|
|
414
|
+
it.bookmaker ? /* @__PURE__ */ jsx7("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
415
|
+
] }) : null
|
|
416
|
+
] }),
|
|
417
|
+
it.text ? /* @__PURE__ */ jsx7("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
418
|
+
it.stats.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "ss-w-bi-stats", children: it.stats.map((s) => /* @__PURE__ */ jsxs5("span", { className: "ss-w-bi-stat", children: [
|
|
419
|
+
/* @__PURE__ */ jsx7("b", { children: s.value }),
|
|
420
|
+
/* @__PURE__ */ jsx7("span", { children: s.label })
|
|
421
|
+
] }, `${s.label}:${s.value}`)) }) : null,
|
|
422
|
+
it.disclaimer ? /* @__PURE__ */ jsx7("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
423
|
+
] }, it.id)) });
|
|
424
|
+
}
|
|
425
|
+
|
|
377
426
|
// src/components/ActionButtons.tsx
|
|
378
|
-
import { Fragment, jsx as
|
|
427
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
379
428
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
380
429
|
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__ */
|
|
430
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ss-w-actions", children: [
|
|
431
|
+
actions.map((a, i) => /* @__PURE__ */ jsx8("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
432
|
+
actions.length === 0 && loading ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
433
|
+
/* @__PURE__ */ jsx8("span", { className: "ss-w-abtn-shimmer" }),
|
|
434
|
+
/* @__PURE__ */ jsx8("span", { className: "ss-w-abtn-shimmer" })
|
|
386
435
|
] }) : null
|
|
387
436
|
] });
|
|
388
437
|
}
|
|
389
438
|
|
|
390
439
|
// src/components/ChatMessage.tsx
|
|
391
|
-
import { jsx as
|
|
440
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
392
441
|
function ChatMessage({ message, disabled, onAct, ui }) {
|
|
393
442
|
if (message.role === "user") {
|
|
394
|
-
return /* @__PURE__ */
|
|
443
|
+
return /* @__PURE__ */ jsx9("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx9("div", { className: "ss-w-bubble", children: message.text }) });
|
|
395
444
|
}
|
|
396
|
-
return /* @__PURE__ */
|
|
397
|
-
message.text ? /* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
445
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
446
|
+
message.text ? /* @__PURE__ */ jsx9(Markdown, { text: message.text }) : null,
|
|
447
|
+
/* @__PURE__ */ jsx9(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
448
|
+
/* @__PURE__ */ jsx9(BettingInsightList, { insights: message.insights }),
|
|
449
|
+
/* @__PURE__ */ jsx9(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
400
450
|
] });
|
|
401
451
|
}
|
|
402
452
|
|
|
403
453
|
// src/components/IntentChips.tsx
|
|
404
|
-
import { jsx as
|
|
454
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
405
455
|
function IntentChips({ chips, onPick }) {
|
|
406
456
|
if (chips.length === 0) return null;
|
|
407
|
-
return /* @__PURE__ */
|
|
457
|
+
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
458
|
}
|
|
409
459
|
|
|
410
460
|
// src/scroll.ts
|
|
@@ -414,7 +464,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
414
464
|
}
|
|
415
465
|
|
|
416
466
|
// src/components/MessageList.tsx
|
|
417
|
-
import { jsx as
|
|
467
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
418
468
|
function MessageList({ controller, ui }) {
|
|
419
469
|
const { state, send } = controller;
|
|
420
470
|
const listRef = useRef2(null);
|
|
@@ -424,7 +474,7 @@ function MessageList({ controller, ui }) {
|
|
|
424
474
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
425
475
|
}, [state.messages, state.status]);
|
|
426
476
|
const empty = state.messages.length === 0;
|
|
427
|
-
return /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs8(
|
|
428
478
|
"div",
|
|
429
479
|
{
|
|
430
480
|
className: "ss-w-list",
|
|
@@ -434,7 +484,7 @@ function MessageList({ controller, ui }) {
|
|
|
434
484
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
435
485
|
},
|
|
436
486
|
children: [
|
|
437
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
487
|
+
state.messages.map((m) => /* @__PURE__ */ jsx11(
|
|
438
488
|
ChatMessage,
|
|
439
489
|
{
|
|
440
490
|
message: m,
|
|
@@ -444,15 +494,15 @@ function MessageList({ controller, ui }) {
|
|
|
444
494
|
},
|
|
445
495
|
m.id
|
|
446
496
|
)),
|
|
447
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
497
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx11(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
448
498
|
} }) : null,
|
|
449
|
-
state.status ? /* @__PURE__ */
|
|
450
|
-
state.error ? /* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
452
|
-
/* @__PURE__ */
|
|
499
|
+
state.status ? /* @__PURE__ */ jsx11("div", { className: "ss-w-status", children: state.status }) : null,
|
|
500
|
+
state.error ? /* @__PURE__ */ jsxs8("div", { className: "ss-w-error", role: "alert", children: [
|
|
501
|
+
/* @__PURE__ */ jsx11("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
502
|
+
/* @__PURE__ */ jsx11("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
453
503
|
] }) : null,
|
|
454
|
-
empty ? /* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
504
|
+
empty ? /* @__PURE__ */ jsx11(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
505
|
+
/* @__PURE__ */ jsx11("div", { ref: endRef })
|
|
456
506
|
]
|
|
457
507
|
}
|
|
458
508
|
);
|
|
@@ -460,7 +510,7 @@ function MessageList({ controller, ui }) {
|
|
|
460
510
|
|
|
461
511
|
// src/components/ChatInput.tsx
|
|
462
512
|
import { useState as useState2 } from "react";
|
|
463
|
-
import { jsx as
|
|
513
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
464
514
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
465
515
|
const [value, setValue] = useState2("");
|
|
466
516
|
const submit = () => {
|
|
@@ -475,14 +525,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
475
525
|
submit();
|
|
476
526
|
}
|
|
477
527
|
};
|
|
478
|
-
return /* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
480
|
-
streaming ? /* @__PURE__ */
|
|
528
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-input", children: [
|
|
529
|
+
/* @__PURE__ */ jsx12("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
530
|
+
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
531
|
] });
|
|
482
532
|
}
|
|
483
533
|
|
|
484
534
|
// src/components/ChatPanel.tsx
|
|
485
|
-
import { jsx as
|
|
535
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
486
536
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
487
537
|
function useIsModal() {
|
|
488
538
|
const [modal, setModal] = useState3(false);
|
|
@@ -506,10 +556,10 @@ function ChatPanel({ controller, ui }) {
|
|
|
506
556
|
window.addEventListener("keydown", onKey);
|
|
507
557
|
return () => window.removeEventListener("keydown", onKey);
|
|
508
558
|
}, [close]);
|
|
509
|
-
return /* @__PURE__ */
|
|
510
|
-
/* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
559
|
+
return /* @__PURE__ */ jsxs10("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
560
|
+
/* @__PURE__ */ jsx13(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
561
|
+
/* @__PURE__ */ jsx13(MessageList, { controller, ui }),
|
|
562
|
+
/* @__PURE__ */ jsx13(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
513
563
|
] });
|
|
514
564
|
}
|
|
515
565
|
|
|
@@ -608,6 +658,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
608
658
|
.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }
|
|
609
659
|
.ss-w-cards-more:disabled { opacity: .5; cursor: default; }
|
|
610
660
|
|
|
661
|
+
/* betting insights */
|
|
662
|
+
.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }
|
|
663
|
+
.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; }
|
|
664
|
+
.ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }
|
|
665
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; min-width: 0; }
|
|
666
|
+
.ss-w-bi-market { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }
|
|
667
|
+
.ss-w-bi-sel { font-weight: 660; }
|
|
668
|
+
.ss-w-bi-odds { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }
|
|
669
|
+
.ss-w-bi-odds b { font-size: 15px; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); }
|
|
670
|
+
.ss-w-bi-book { font-size: 10px; color: var(--ss-w-faint); }
|
|
671
|
+
.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; }
|
|
672
|
+
.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }
|
|
673
|
+
.ss-w-bi-stats { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
674
|
+
.ss-w-bi-stat b { display: block; font-variant-numeric: tabular-nums; font-weight: 660; }
|
|
675
|
+
.ss-w-bi-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
676
|
+
.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }
|
|
677
|
+
|
|
611
678
|
/* action buttons */
|
|
612
679
|
.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
613
680
|
.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 +704,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
637
704
|
`;
|
|
638
705
|
|
|
639
706
|
// src/StatsWidget.tsx
|
|
640
|
-
import { jsx as
|
|
707
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
641
708
|
function buildClient(props) {
|
|
642
709
|
try {
|
|
643
710
|
if ("client" in props && props.client) {
|
|
@@ -673,7 +740,7 @@ function StatsWidget(props) {
|
|
|
673
740
|
}, [built, ui.injectStyles]);
|
|
674
741
|
if (!built) return null;
|
|
675
742
|
const attrs = themeAttrs(ui);
|
|
676
|
-
return /* @__PURE__ */
|
|
743
|
+
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
744
|
ChatFab,
|
|
678
745
|
{
|
|
679
746
|
label: ui.launcherLabel,
|