@aparte/plugin-cards 0.0.0-stage → 0.29.1
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/LICENSE +21 -0
- package/README.md +151 -2
- package/dist/carousel-DwgHvriV.js +63 -0
- package/dist/carousel-DwgHvriV.js.map +1 -0
- package/dist/controls-BYUm4aRV.js +62 -0
- package/dist/controls-BYUm4aRV.js.map +1 -0
- package/dist/format-BFq79ydr.js +728 -0
- package/dist/format-BFq79ydr.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/items/icons.d.ts +12 -0
- package/dist/items/icons.d.ts.map +1 -0
- package/dist/items/index.d.ts +100 -0
- package/dist/items/index.d.ts.map +1 -0
- package/dist/items.js +698 -0
- package/dist/items.js.map +1 -0
- package/dist/kit/carousel.d.ts +17 -0
- package/dist/kit/carousel.d.ts.map +1 -0
- package/dist/kit/controls.d.ts +51 -0
- package/dist/kit/controls.d.ts.map +1 -0
- package/dist/kit/define.d.ts +201 -0
- package/dist/kit/define.d.ts.map +1 -0
- package/dist/kit/dom.d.ts +40 -0
- package/dist/kit/dom.d.ts.map +1 -0
- package/dist/kit/fence.d.ts +39 -0
- package/dist/kit/fence.d.ts.map +1 -0
- package/dist/kit/format.d.ts +49 -0
- package/dist/kit/format.d.ts.map +1 -0
- package/dist/kit/rating.d.ts +19 -0
- package/dist/kit/rating.d.ts.map +1 -0
- package/dist/kit/sparkline.d.ts +19 -0
- package/dist/kit/sparkline.d.ts.map +1 -0
- package/dist/kit/strings.d.ts +139 -0
- package/dist/kit/strings.d.ts.map +1 -0
- package/dist/link/icons.d.ts +16 -0
- package/dist/link/icons.d.ts.map +1 -0
- package/dist/link/index.d.ts +98 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link.js +387 -0
- package/dist/link.js.map +1 -0
- package/dist/media/icons.d.ts +28 -0
- package/dist/media/icons.d.ts.map +1 -0
- package/dist/media/index.d.ts +107 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media.js +610 -0
- package/dist/media.js.map +1 -0
- package/dist/order/icons.d.ts +49 -0
- package/dist/order/icons.d.ts.map +1 -0
- package/dist/order/index.d.ts +204 -0
- package/dist/order/index.d.ts.map +1 -0
- package/dist/order.js +1843 -0
- package/dist/order.js.map +1 -0
- package/dist/place/icons.d.ts +18 -0
- package/dist/place/icons.d.ts.map +1 -0
- package/dist/place/index.d.ts +207 -0
- package/dist/place/index.d.ts.map +1 -0
- package/dist/place.js +1456 -0
- package/dist/place.js.map +1 -0
- package/dist/plan/icons.d.ts +25 -0
- package/dist/plan/icons.d.ts.map +1 -0
- package/dist/plan/index.d.ts +153 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan.js +1191 -0
- package/dist/plan.js.map +1 -0
- package/dist/product/icons.d.ts +16 -0
- package/dist/product/icons.d.ts.map +1 -0
- package/dist/product/index.d.ts +133 -0
- package/dist/product/index.d.ts.map +1 -0
- package/dist/product.js +1245 -0
- package/dist/product.js.map +1 -0
- package/dist/rating-CHVajQ2b.js +35 -0
- package/dist/rating-CHVajQ2b.js.map +1 -0
- package/dist/score/icons.d.ts +35 -0
- package/dist/score/icons.d.ts.map +1 -0
- package/dist/score/index.d.ts +185 -0
- package/dist/score/index.d.ts.map +1 -0
- package/dist/score.js +1843 -0
- package/dist/score.js.map +1 -0
- package/dist/sparkline-C-cA9obz.js +56 -0
- package/dist/sparkline-C-cA9obz.js.map +1 -0
- package/dist/stats/icons.d.ts +19 -0
- package/dist/stats/icons.d.ts.map +1 -0
- package/dist/stats/index.d.ts +137 -0
- package/dist/stats/index.d.ts.map +1 -0
- package/dist/stats.js +1085 -0
- package/dist/stats.js.map +1 -0
- package/dist/stock/chart.d.ts +135 -0
- package/dist/stock/chart.d.ts.map +1 -0
- package/dist/stock/icons.d.ts +15 -0
- package/dist/stock/icons.d.ts.map +1 -0
- package/dist/stock/index.d.ts +195 -0
- package/dist/stock/index.d.ts.map +1 -0
- package/dist/stock.js +1013 -0
- package/dist/stock.js.map +1 -0
- package/dist/weather/conditions.d.ts +25 -0
- package/dist/weather/conditions.d.ts.map +1 -0
- package/dist/weather/icons.d.ts +12 -0
- package/dist/weather/icons.d.ts.map +1 -0
- package/dist/weather/index.d.ts +146 -0
- package/dist/weather/index.d.ts.map +1 -0
- package/dist/weather.js +1162 -0
- package/dist/weather.js.map +1 -0
- package/package.json +137 -3
package/dist/score.js
ADDED
|
@@ -0,0 +1,1843 @@
|
|
|
1
|
+
import { b as defineCard, q as str, r as word, e as el, m as glyph, h as formatNumber, t as toDate, w as webUrl, n as intlTag, p as num, f as formatDay, g as formatHour } from "./format-BFq79ydr.js";
|
|
2
|
+
const svg = (body) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">${body}</svg>`;
|
|
3
|
+
const FOOTBALL = svg('<circle cx="12" cy="12" r="9"/><path d="M12 7.6l4.2 3-1.6 4.9H9.4L7.8 10.6z"/><path d="M12 7.6V3.2M16.2 10.6l4.3-1.3M14.6 15.5l2.6 3.7M9.4 15.5l-2.6 3.7M7.8 10.6L3.5 9.3"/>');
|
|
4
|
+
const BASKETBALL = svg('<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3v18"/><path d="M5.7 5.6a9 9 0 0 1 0 12.8M18.3 5.6a9 9 0 0 0 0 12.8"/>');
|
|
5
|
+
const TENNIS = svg('<circle cx="12" cy="12" r="9"/><path d="M5.9 5.2c2.5 1.9 3.9 4.2 3.9 6.8s-1.4 4.9-3.9 6.8"/><path d="M18.1 5.2c-2.5 1.9-3.9 4.2-3.9 6.8s1.4 4.9 3.9 6.8"/>');
|
|
6
|
+
const RUGBY = svg('<ellipse cx="12" cy="12" rx="9.6" ry="5.6" transform="rotate(-45 12 12)"/><path d="M7.2 16.8C10 15.6 15.6 10 16.8 7.2"/>');
|
|
7
|
+
const AMERICAN_FOOTBALL = svg('<ellipse cx="12" cy="12" rx="9.6" ry="5.6" transform="rotate(-45 12 12)"/><path d="M9.6 14.4l4.8-4.8M10.4 11.6l2 2M11.6 10.4l2 2"/>');
|
|
8
|
+
const HOCKEY = svg('<path d="M6.5 3l6.6 14.2a1.4 1.4 0 0 0 1.3.8H20"/><ellipse cx="7.5" cy="18.4" rx="3.2" ry="1.5"/>');
|
|
9
|
+
const BASEBALL = svg('<circle cx="12" cy="12" r="9"/><path d="M7.3 4.3a11 11 0 0 1 0 15.4M16.7 4.3a11 11 0 0 0 0 15.4"/><path d="M8.6 8.2l1.4-.5M9 12h1.5M8.6 15.8l1.4.5M15.4 8.2l-1.4-.5M15 12h-1.5M15.4 15.8l-1.4.5"/>');
|
|
10
|
+
const TROPHY = svg('<path d="M8 4h8v5.2a4 4 0 0 1-8 0z"/><path d="M8 6H5.2a3 3 0 0 0 3 4.2M16 6h2.8a3 3 0 0 1-3 4.2"/><path d="M12 13.2v3.6M8.5 20h7M9.8 16.8h4.4V20H9.8z"/>');
|
|
11
|
+
const SPORT_GLYPHS = {
|
|
12
|
+
football: FOOTBALL,
|
|
13
|
+
basketball: BASKETBALL,
|
|
14
|
+
tennis: TENNIS,
|
|
15
|
+
rugby: RUGBY,
|
|
16
|
+
hockey: HOCKEY,
|
|
17
|
+
baseball: BASEBALL,
|
|
18
|
+
"american-football": AMERICAN_FOOTBALL,
|
|
19
|
+
generic: TROPHY
|
|
20
|
+
};
|
|
21
|
+
const CARD = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="7" y="3.5" width="10" height="16" rx="1.6" fill="currentColor" transform="rotate(8 12 11.5)"/></svg>';
|
|
22
|
+
const SUB = svg('<path d="M7.5 4v13.5M4 14l3.5 3.5L11 14"/><path d="M16.5 20V6.5M13 10l3.5-3.5L20 10"/>');
|
|
23
|
+
const EVENT_GLYPHS = {
|
|
24
|
+
goal: FOOTBALL,
|
|
25
|
+
penalty: FOOTBALL,
|
|
26
|
+
"own-goal": FOOTBALL,
|
|
27
|
+
yellow: CARD,
|
|
28
|
+
red: CARD,
|
|
29
|
+
sub: SUB
|
|
30
|
+
};
|
|
31
|
+
const PIN = svg('<path d="M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0c0 5.4-6.5 11-6.5 11z"/><circle cx="12" cy="10" r="2.3"/>');
|
|
32
|
+
const TV = svg('<rect x="3" y="6.5" width="18" height="12" rx="2"/><path d="M8.5 21h7M9 3l3 3.5L15 3"/>');
|
|
33
|
+
const CHEVRON = svg('<path d="M9.5 6l6 6-6 6"/>');
|
|
34
|
+
const scoreStyles = `/* =========================================
|
|
35
|
+
The score card — @aparte/plugin-cards/score
|
|
36
|
+
=========================================
|
|
37
|
+
Three variants of one card, chosen by \`data-variant\` on its root:
|
|
38
|
+
card the scoreboard: competition over it, the two teams facing each other, the
|
|
39
|
+
score big between them, the state of play under it, venue and channel below.
|
|
40
|
+
compact one row per match: the state or the kick-off in a column, the two teams
|
|
41
|
+
stacked with their scores at the end. Several matches are always rows.
|
|
42
|
+
detail the card's board, then the score by period (a table) and the events,
|
|
43
|
+
each on its team's side of a centre line.
|
|
44
|
+
A team's colour is the tool's, validated as a hex and set as \`--aparte-score-team\`
|
|
45
|
+
(its crest), \`--aparte-score-home\` / \`--aparte-score-away\` (the band and the glow).
|
|
46
|
+
Everything else is a theme token or derived from one, so light and dark follow the chat.
|
|
47
|
+
The winner is told by weight and, on a row, by a mark — never by colour alone; a live
|
|
48
|
+
match says "Live" in a word beside its red dot.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
.aparte-score-card {
|
|
52
|
+
--aparte-score-pad: var(--aparte-space-6);
|
|
53
|
+
--aparte-score-live: var(--aparte-error);
|
|
54
|
+
--aparte-score-live-ink: var(--aparte-error-ink);
|
|
55
|
+
--aparte-score-neutral: color-mix(in oklab, var(--aparte-text) 9%, var(--aparte-surface-1));
|
|
56
|
+
--aparte-score-rule: color-mix(in oklab, var(--aparte-border) 80%, transparent);
|
|
57
|
+
--aparte-score-num-size: calc(2.625rem * var(--aparte-font-scale));
|
|
58
|
+
--aparte-score-crest-lg: 3.25rem;
|
|
59
|
+
--aparte-score-crest-sm: 1.375rem;
|
|
60
|
+
--aparte-score-band-size: 3px;
|
|
61
|
+
/* A football card's colours are the same in daylight and at night: they are the
|
|
62
|
+
referee's, not the theme's. Text on a team's colour is black or white, picked by the
|
|
63
|
+
colour's own luminance — a theme grey would fail on half the clubs. */
|
|
64
|
+
--aparte-score-yellow: #f4c20d;
|
|
65
|
+
--aparte-score-red: #dc2626;
|
|
66
|
+
--aparte-score-ink-light: #ffffff;
|
|
67
|
+
--aparte-score-ink-dark: #15121a;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ── Widths: each variant asks for its own; the bubble's limit caps them all ── */
|
|
71
|
+
|
|
72
|
+
.aparte-score-card[data-variant="card"] { --aparte-rich-card-max-inline-size: 25rem; }
|
|
73
|
+
.aparte-score-card[data-variant="compact"] { --aparte-rich-card-max-inline-size: 24rem; }
|
|
74
|
+
.aparte-score-card[data-variant="detail"] { --aparte-rich-card-max-inline-size: 28rem; }
|
|
75
|
+
.aparte-score-card:has(.aparte-score__board-list) { --aparte-rich-card-max-inline-size: 26rem; }
|
|
76
|
+
|
|
77
|
+
/* ── Visually hidden: said to a reader, not drawn ─────────────────────── */
|
|
78
|
+
|
|
79
|
+
.aparte-score__sr {
|
|
80
|
+
position: absolute;
|
|
81
|
+
inline-size: 1px;
|
|
82
|
+
block-size: 1px;
|
|
83
|
+
padding: 0;
|
|
84
|
+
margin: -1px;
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
clip: rect(0 0 0 0);
|
|
87
|
+
white-space: nowrap;
|
|
88
|
+
border: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ── The match, with its band in the two teams' colours ─────────────────── */
|
|
92
|
+
|
|
93
|
+
.aparte-score {
|
|
94
|
+
/* The board, the table and the events read the match's width, not the window's. */
|
|
95
|
+
container: aparte-score / inline-size;
|
|
96
|
+
position: relative;
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
min-inline-size: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.aparte-score::before {
|
|
103
|
+
content: "";
|
|
104
|
+
display: block;
|
|
105
|
+
block-size: var(--aparte-score-band-size);
|
|
106
|
+
background: linear-gradient(to right,
|
|
107
|
+
var(--aparte-score-home, var(--aparte-score-rule)) 0 50%,
|
|
108
|
+
var(--aparte-score-away, var(--aparte-score-rule)) 50% 100%);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* The home team is at the start of the line, so its colour is too. */
|
|
112
|
+
.aparte-score:dir(rtl)::before {
|
|
113
|
+
background: linear-gradient(to left,
|
|
114
|
+
var(--aparte-score-home, var(--aparte-score-rule)) 0 50%,
|
|
115
|
+
var(--aparte-score-away, var(--aparte-score-rule)) 50% 100%);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* A live match's band is the live red: the state of play, seen from the top of the card. */
|
|
119
|
+
.aparte-score[data-phase="live"]::before {
|
|
120
|
+
background: var(--aparte-score-live);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ── The line over the board: sport, competition, round, day ─────────── */
|
|
124
|
+
|
|
125
|
+
.aparte-score__head,
|
|
126
|
+
.aparte-score__heading {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: var(--aparte-space-3);
|
|
130
|
+
min-inline-size: 0;
|
|
131
|
+
padding: var(--aparte-space-5) var(--aparte-score-pad) 0;
|
|
132
|
+
color: var(--aparte-text-muted);
|
|
133
|
+
font-size: var(--aparte-font-size-sm);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.aparte-score__sport {
|
|
137
|
+
--aparte-rich-card-glyph-size: 1rem;
|
|
138
|
+
color: var(--aparte-text-muted);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.aparte-score__meta {
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-wrap: wrap;
|
|
144
|
+
align-items: baseline;
|
|
145
|
+
gap: 0 var(--aparte-space-2);
|
|
146
|
+
min-inline-size: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.aparte-score__competition {
|
|
150
|
+
color: var(--aparte-text);
|
|
151
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
152
|
+
overflow-wrap: anywhere;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.aparte-score__round { overflow-wrap: anywhere; }
|
|
156
|
+
.aparte-score__dot { color: color-mix(in oklab, var(--aparte-text-muted) 60%, transparent); }
|
|
157
|
+
|
|
158
|
+
.aparte-score__date {
|
|
159
|
+
margin-inline-start: auto;
|
|
160
|
+
white-space: nowrap;
|
|
161
|
+
font-variant-numeric: tabular-nums;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ── The board ───────────────────────────────────────────────────────── */
|
|
165
|
+
|
|
166
|
+
.aparte-score__board {
|
|
167
|
+
display: grid;
|
|
168
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
169
|
+
align-items: start;
|
|
170
|
+
gap: var(--aparte-space-4);
|
|
171
|
+
padding: var(--aparte-space-7) var(--aparte-score-pad) var(--aparte-space-8);
|
|
172
|
+
/* Each team's side is lit faintly in its colour, the way a broadcast frames a fixture. */
|
|
173
|
+
background:
|
|
174
|
+
radial-gradient(60% 90% at 0% 40%, color-mix(in oklab, var(--aparte-score-home, transparent) 11%, transparent), transparent 70%),
|
|
175
|
+
radial-gradient(60% 90% at 100% 40%, color-mix(in oklab, var(--aparte-score-away, transparent) 11%, transparent), transparent 70%);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.aparte-score__board:dir(rtl) {
|
|
179
|
+
background:
|
|
180
|
+
radial-gradient(60% 90% at 100% 40%, color-mix(in oklab, var(--aparte-score-home, transparent) 11%, transparent), transparent 70%),
|
|
181
|
+
radial-gradient(60% 90% at 0% 40%, color-mix(in oklab, var(--aparte-score-away, transparent) 11%, transparent), transparent 70%);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.aparte-score__team {
|
|
185
|
+
display: flex;
|
|
186
|
+
flex-direction: column;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: var(--aparte-space-3);
|
|
189
|
+
min-inline-size: 0;
|
|
190
|
+
text-align: center;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.aparte-score__team-name {
|
|
194
|
+
display: -webkit-box;
|
|
195
|
+
-webkit-box-orient: vertical;
|
|
196
|
+
-webkit-line-clamp: 2;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
max-inline-size: 100%;
|
|
199
|
+
color: var(--aparte-text);
|
|
200
|
+
font-size: var(--aparte-font-size-base);
|
|
201
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
202
|
+
line-height: 1.25;
|
|
203
|
+
overflow-wrap: anywhere;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.aparte-score__team[data-lead="lose"] .aparte-score__team-name { font-weight: var(--aparte-font-weight-medium); }
|
|
207
|
+
|
|
208
|
+
.aparte-score__record {
|
|
209
|
+
margin-block-start: calc(var(--aparte-space-2) * -1);
|
|
210
|
+
color: var(--aparte-text-muted);
|
|
211
|
+
font-size: var(--aparte-font-size-xs);
|
|
212
|
+
font-variant-numeric: tabular-nums;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* ── The crest: a logo over a monogram disc ─────────────────────────────── */
|
|
216
|
+
|
|
217
|
+
.aparte-score__crest {
|
|
218
|
+
position: relative;
|
|
219
|
+
display: inline-grid;
|
|
220
|
+
place-items: center;
|
|
221
|
+
flex: none;
|
|
222
|
+
inline-size: var(--aparte-score-crest-size);
|
|
223
|
+
block-size: var(--aparte-score-crest-size);
|
|
224
|
+
border-radius: var(--aparte-radius-full);
|
|
225
|
+
background: var(--aparte-score-team, var(--aparte-score-neutral));
|
|
226
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--aparte-text) 10%, transparent);
|
|
227
|
+
color: var(--aparte-text);
|
|
228
|
+
overflow: hidden;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.aparte-score__crest--lg {
|
|
232
|
+
--aparte-score-crest-size: var(--aparte-score-crest-lg);
|
|
233
|
+
font-size: calc(var(--aparte-score-crest-lg) * 0.3);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.aparte-score__crest--sm {
|
|
237
|
+
--aparte-score-crest-size: var(--aparte-score-crest-sm);
|
|
238
|
+
font-size: calc(var(--aparte-score-crest-sm) * 0.36);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.aparte-score__crest[data-ink="light"] { color: var(--aparte-score-ink-light); }
|
|
242
|
+
.aparte-score__crest[data-ink="dark"] { color: var(--aparte-score-ink-dark); }
|
|
243
|
+
|
|
244
|
+
.aparte-score__monogram {
|
|
245
|
+
font-weight: var(--aparte-font-weight-bold);
|
|
246
|
+
letter-spacing: -0.02em;
|
|
247
|
+
line-height: 1;
|
|
248
|
+
white-space: nowrap;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* A logo is drawn on the card's own ground: a crest's shape is its own, not a disc's. */
|
|
252
|
+
.aparte-score__crest[data-logo] {
|
|
253
|
+
background: transparent;
|
|
254
|
+
box-shadow: none;
|
|
255
|
+
border-radius: 0;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.aparte-score__crest[data-logo] .aparte-score__monogram { visibility: hidden; }
|
|
259
|
+
|
|
260
|
+
.aparte-score__logo {
|
|
261
|
+
position: absolute;
|
|
262
|
+
inset: 0;
|
|
263
|
+
inline-size: 100%;
|
|
264
|
+
block-size: 100%;
|
|
265
|
+
object-fit: contain;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* ── The middle: score, kick-off, status ───────────────────────────────── */
|
|
269
|
+
|
|
270
|
+
.aparte-score__centre {
|
|
271
|
+
display: flex;
|
|
272
|
+
flex-direction: column;
|
|
273
|
+
align-items: center;
|
|
274
|
+
gap: var(--aparte-space-3);
|
|
275
|
+
min-inline-size: 5.5rem;
|
|
276
|
+
/* The numbers sit level with the crests' middles. */
|
|
277
|
+
padding-block-start: calc((var(--aparte-score-crest-lg) - var(--aparte-score-num-size)) / 2);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.aparte-score__result {
|
|
281
|
+
display: flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
gap: var(--aparte-space-3);
|
|
284
|
+
color: var(--aparte-text);
|
|
285
|
+
font-size: var(--aparte-score-num-size);
|
|
286
|
+
font-weight: var(--aparte-font-weight-bold);
|
|
287
|
+
font-variant-numeric: tabular-nums;
|
|
288
|
+
letter-spacing: -0.03em;
|
|
289
|
+
line-height: 1;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* The loser's number steps back; the winner's keeps its weight. Weight, not colour alone. */
|
|
293
|
+
.aparte-score__num[data-lead="lose"] {
|
|
294
|
+
color: var(--aparte-text-muted);
|
|
295
|
+
font-weight: var(--aparte-font-weight-medium);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.aparte-score__sep {
|
|
299
|
+
color: color-mix(in oklab, var(--aparte-text-muted) 70%, transparent);
|
|
300
|
+
font-weight: var(--aparte-font-weight-normal);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.aparte-score__kickoff {
|
|
304
|
+
display: flex;
|
|
305
|
+
flex-direction: column;
|
|
306
|
+
align-items: center;
|
|
307
|
+
gap: var(--aparte-space-1);
|
|
308
|
+
font-variant-numeric: tabular-nums;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.aparte-score__kickoff .aparte-score__day {
|
|
312
|
+
color: var(--aparte-text-muted);
|
|
313
|
+
font-size: var(--aparte-font-size-xs);
|
|
314
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
315
|
+
letter-spacing: 0.04em;
|
|
316
|
+
text-transform: uppercase;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.aparte-score__kickoff .aparte-score__hour {
|
|
320
|
+
color: var(--aparte-text);
|
|
321
|
+
font-size: var(--aparte-font-size-xl);
|
|
322
|
+
font-weight: var(--aparte-font-weight-bold);
|
|
323
|
+
letter-spacing: -0.01em;
|
|
324
|
+
white-space: nowrap;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* A kick-off that will not happen is struck through — and the pill under it says why. */
|
|
328
|
+
.aparte-score[data-phase="postponed"] .aparte-score__hour,
|
|
329
|
+
.aparte-score[data-phase="cancelled"] .aparte-score__hour,
|
|
330
|
+
.aparte-score__row[data-phase="postponed"] .aparte-score__hour,
|
|
331
|
+
.aparte-score__row[data-phase="cancelled"] .aparte-score__hour {
|
|
332
|
+
color: var(--aparte-text-muted);
|
|
333
|
+
text-decoration: line-through;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.aparte-score__pill {
|
|
337
|
+
display: inline-flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
gap: var(--aparte-space-2);
|
|
340
|
+
padding: var(--aparte-space-1) var(--aparte-space-4);
|
|
341
|
+
border-radius: var(--aparte-radius-full);
|
|
342
|
+
background: var(--aparte-score-neutral);
|
|
343
|
+
color: var(--aparte-text-muted);
|
|
344
|
+
font-size: var(--aparte-font-size-xs);
|
|
345
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
346
|
+
line-height: 1.4;
|
|
347
|
+
white-space: nowrap;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.aparte-score__pill[data-phase="live"] {
|
|
351
|
+
background: color-mix(in oklab, var(--aparte-score-live) 14%, transparent);
|
|
352
|
+
color: var(--aparte-score-live-ink);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.aparte-score__pill[data-phase="live"] .aparte-score__live-word {
|
|
356
|
+
letter-spacing: 0.05em;
|
|
357
|
+
text-transform: uppercase;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.aparte-score__pill[data-phase="halftime"],
|
|
361
|
+
.aparte-score__pill[data-phase="postponed"] {
|
|
362
|
+
background: color-mix(in oklab, var(--aparte-warning) 16%, transparent);
|
|
363
|
+
color: var(--aparte-warning-ink);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.aparte-score__pill[data-phase="cancelled"] {
|
|
367
|
+
background: color-mix(in oklab, var(--aparte-error) 12%, transparent);
|
|
368
|
+
color: var(--aparte-error-ink);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.aparte-score__clock {
|
|
372
|
+
font-variant-numeric: tabular-nums;
|
|
373
|
+
font-weight: var(--aparte-font-weight-bold);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* The red dot of a live match, and the ring that leaves it. Still under reduced motion. */
|
|
377
|
+
.aparte-score__live-dot {
|
|
378
|
+
position: relative;
|
|
379
|
+
flex: none;
|
|
380
|
+
inline-size: 0.45rem;
|
|
381
|
+
block-size: 0.45rem;
|
|
382
|
+
border-radius: var(--aparte-radius-full);
|
|
383
|
+
background: var(--aparte-score-live);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.aparte-score__live-dot::after {
|
|
387
|
+
content: "";
|
|
388
|
+
position: absolute;
|
|
389
|
+
inset: 0;
|
|
390
|
+
border-radius: inherit;
|
|
391
|
+
background: var(--aparte-score-live);
|
|
392
|
+
animation: aparte-score-pulse 1.8s ease-out infinite;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
@keyframes aparte-score-pulse {
|
|
396
|
+
0% { opacity: 0.6; transform: scale(1); }
|
|
397
|
+
70%, 100% { opacity: 0; transform: scale(2.8); }
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* ── The footer: venue, channel, the match's page ──────────────────────── */
|
|
401
|
+
|
|
402
|
+
.aparte-score__foot {
|
|
403
|
+
display: flex;
|
|
404
|
+
flex-wrap: wrap;
|
|
405
|
+
align-items: center;
|
|
406
|
+
gap: var(--aparte-space-2) var(--aparte-space-5);
|
|
407
|
+
padding: var(--aparte-space-4) var(--aparte-score-pad);
|
|
408
|
+
border-block-start: var(--aparte-border-width) solid var(--aparte-score-rule);
|
|
409
|
+
color: var(--aparte-text-muted);
|
|
410
|
+
font-size: var(--aparte-font-size-xs);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.aparte-score__facts {
|
|
414
|
+
display: flex;
|
|
415
|
+
flex-wrap: wrap;
|
|
416
|
+
gap: var(--aparte-space-1) var(--aparte-space-5);
|
|
417
|
+
min-inline-size: 0;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.aparte-score__fact {
|
|
421
|
+
display: inline-flex;
|
|
422
|
+
align-items: center;
|
|
423
|
+
gap: var(--aparte-space-2);
|
|
424
|
+
min-inline-size: 0;
|
|
425
|
+
overflow-wrap: anywhere;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.aparte-score__fact-glyph { --aparte-rich-card-glyph-size: 0.95rem; opacity: 0.8; }
|
|
429
|
+
|
|
430
|
+
.aparte-score__more {
|
|
431
|
+
display: inline-flex;
|
|
432
|
+
align-items: center;
|
|
433
|
+
gap: var(--aparte-space-1);
|
|
434
|
+
margin-inline-start: auto;
|
|
435
|
+
border-radius: var(--aparte-radius-sm);
|
|
436
|
+
color: var(--aparte-primary-ink);
|
|
437
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
438
|
+
text-decoration: none;
|
|
439
|
+
white-space: nowrap;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.aparte-score__more:hover {
|
|
443
|
+
text-decoration: underline;
|
|
444
|
+
text-decoration-thickness: 1px;
|
|
445
|
+
text-underline-offset: 0.18em;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.aparte-score__more:focus-visible {
|
|
449
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
450
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.aparte-score__chevron {
|
|
454
|
+
--aparte-rich-card-glyph-size: 0.9rem;
|
|
455
|
+
transition: translate var(--aparte-duration-base) ease;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.aparte-score__chevron:dir(rtl) { transform: scaleX(-1); }
|
|
459
|
+
.aparte-score__more:hover .aparte-score__chevron { translate: 2px 0; }
|
|
460
|
+
.aparte-score__more:hover .aparte-score__chevron:dir(rtl) { translate: -2px 0; }
|
|
461
|
+
|
|
462
|
+
/* ── detail: the score by period ────────────────────────────────────────── */
|
|
463
|
+
|
|
464
|
+
.aparte-score__section {
|
|
465
|
+
padding: var(--aparte-space-5) var(--aparte-score-pad);
|
|
466
|
+
border-block-start: var(--aparte-border-width) solid var(--aparte-score-rule);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.aparte-score__table-wrap { overflow-x: auto; }
|
|
470
|
+
|
|
471
|
+
.aparte-score__periods {
|
|
472
|
+
inline-size: 100%;
|
|
473
|
+
border-collapse: collapse;
|
|
474
|
+
font-size: var(--aparte-font-size-sm);
|
|
475
|
+
font-variant-numeric: tabular-nums;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.aparte-score__periods th,
|
|
479
|
+
.aparte-score__periods td {
|
|
480
|
+
padding: var(--aparte-space-2) var(--aparte-space-3);
|
|
481
|
+
text-align: center;
|
|
482
|
+
white-space: nowrap;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.aparte-score__periods thead th {
|
|
486
|
+
padding-block-start: 0;
|
|
487
|
+
color: var(--aparte-text-muted);
|
|
488
|
+
font-size: var(--aparte-font-size-xs);
|
|
489
|
+
font-weight: var(--aparte-font-weight-medium);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.aparte-score__periods tbody tr + tr { border-block-start: var(--aparte-border-width) solid var(--aparte-score-rule); }
|
|
493
|
+
.aparte-score__periods td { color: var(--aparte-text); }
|
|
494
|
+
|
|
495
|
+
.aparte-score__periods .aparte-score__corner,
|
|
496
|
+
.aparte-score__row-team {
|
|
497
|
+
inline-size: 100%;
|
|
498
|
+
text-align: start;
|
|
499
|
+
padding-inline-start: 0;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.aparte-score__row-team { font-weight: var(--aparte-font-weight-medium); }
|
|
503
|
+
|
|
504
|
+
.aparte-score__row-label {
|
|
505
|
+
display: flex;
|
|
506
|
+
align-items: center;
|
|
507
|
+
gap: var(--aparte-space-3);
|
|
508
|
+
min-inline-size: 0;
|
|
509
|
+
max-inline-size: 10rem;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.aparte-score__row-name {
|
|
513
|
+
min-inline-size: 0;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
text-overflow: ellipsis;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.aparte-score__periods .aparte-score__total {
|
|
519
|
+
border-radius: var(--aparte-radius-sm);
|
|
520
|
+
background: var(--aparte-score-neutral);
|
|
521
|
+
font-weight: var(--aparte-font-weight-bold);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.aparte-score__periods tbody tr[data-lead="lose"] td,
|
|
525
|
+
.aparte-score__periods tbody tr[data-lead="lose"] .aparte-score__row-team { color: var(--aparte-text-muted); }
|
|
526
|
+
|
|
527
|
+
/* A set won is in bold, as a tennis table writes it. */
|
|
528
|
+
.aparte-score__periods td[data-lead="win"] { font-weight: var(--aparte-font-weight-bold); }
|
|
529
|
+
|
|
530
|
+
/* ── detail: the events, each on its team's side ─────────────────────── */
|
|
531
|
+
|
|
532
|
+
.aparte-score__timeline { container: aparte-score-events / inline-size; }
|
|
533
|
+
|
|
534
|
+
.aparte-score__events {
|
|
535
|
+
--aparte-score-minute-col: 3.25rem;
|
|
536
|
+
position: relative;
|
|
537
|
+
display: flex;
|
|
538
|
+
flex-direction: column;
|
|
539
|
+
gap: var(--aparte-space-2);
|
|
540
|
+
margin: 0;
|
|
541
|
+
padding: 0;
|
|
542
|
+
list-style: none;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/* The centre line the minutes sit on. */
|
|
546
|
+
.aparte-score__events::before {
|
|
547
|
+
content: "";
|
|
548
|
+
position: absolute;
|
|
549
|
+
inset-block: var(--aparte-space-2);
|
|
550
|
+
inset-inline-start: 50%;
|
|
551
|
+
inline-size: 1px;
|
|
552
|
+
background: var(--aparte-score-rule);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.aparte-score__event {
|
|
556
|
+
position: relative;
|
|
557
|
+
display: grid;
|
|
558
|
+
grid-template-columns: minmax(0, 1fr) var(--aparte-score-minute-col) minmax(0, 1fr);
|
|
559
|
+
align-items: center;
|
|
560
|
+
min-block-size: 1.875rem;
|
|
561
|
+
font-size: var(--aparte-font-size-sm);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.aparte-score__minute {
|
|
565
|
+
grid-column: 2;
|
|
566
|
+
grid-row: 1;
|
|
567
|
+
justify-self: center;
|
|
568
|
+
min-inline-size: 2.5rem;
|
|
569
|
+
padding: 1px var(--aparte-space-2);
|
|
570
|
+
border-radius: var(--aparte-radius-full);
|
|
571
|
+
background: var(--aparte-surface-1);
|
|
572
|
+
box-shadow: inset 0 0 0 1px var(--aparte-score-rule);
|
|
573
|
+
color: var(--aparte-text-muted);
|
|
574
|
+
font-size: var(--aparte-font-size-xs);
|
|
575
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
576
|
+
font-variant-numeric: tabular-nums;
|
|
577
|
+
text-align: center;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.aparte-score__minute:empty { visibility: hidden; }
|
|
581
|
+
|
|
582
|
+
.aparte-score__event-body {
|
|
583
|
+
grid-row: 1;
|
|
584
|
+
display: flex;
|
|
585
|
+
align-items: center;
|
|
586
|
+
gap: var(--aparte-space-3);
|
|
587
|
+
min-inline-size: 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* The home team's events lean on the line from the start side, the glyph nearest it. */
|
|
591
|
+
.aparte-score__event[data-team="home"] .aparte-score__event-body {
|
|
592
|
+
grid-column: 1;
|
|
593
|
+
flex-direction: row-reverse;
|
|
594
|
+
justify-self: end;
|
|
595
|
+
text-align: end;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.aparte-score__event[data-team="away"] .aparte-score__event-body {
|
|
599
|
+
grid-column: 3;
|
|
600
|
+
justify-self: start;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.aparte-score__event-text {
|
|
604
|
+
display: flex;
|
|
605
|
+
flex-wrap: wrap;
|
|
606
|
+
align-items: baseline;
|
|
607
|
+
gap: 0 var(--aparte-space-2);
|
|
608
|
+
min-inline-size: 0;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.aparte-score__event[data-team="home"] .aparte-score__event-text { justify-content: flex-end; }
|
|
612
|
+
|
|
613
|
+
.aparte-score__player {
|
|
614
|
+
color: var(--aparte-text);
|
|
615
|
+
font-weight: var(--aparte-font-weight-medium);
|
|
616
|
+
overflow-wrap: anywhere;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.aparte-score__event-detail {
|
|
620
|
+
color: var(--aparte-text-muted);
|
|
621
|
+
font-size: var(--aparte-font-size-xs);
|
|
622
|
+
overflow-wrap: anywhere;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* The kind is said by the glyph for a goal, a card, a change; a penalty and an own goal
|
|
626
|
+
look like a goal, so they also write their word. A reader hears it for every kind. */
|
|
627
|
+
.aparte-score__event-type {
|
|
628
|
+
position: absolute;
|
|
629
|
+
inline-size: 1px;
|
|
630
|
+
block-size: 1px;
|
|
631
|
+
overflow: hidden;
|
|
632
|
+
clip: rect(0 0 0 0);
|
|
633
|
+
white-space: nowrap;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.aparte-score__event[data-type="penalty"] .aparte-score__event-type,
|
|
637
|
+
.aparte-score__event[data-type="own-goal"] .aparte-score__event-type {
|
|
638
|
+
position: static;
|
|
639
|
+
inline-size: auto;
|
|
640
|
+
block-size: auto;
|
|
641
|
+
overflow: visible;
|
|
642
|
+
clip: auto;
|
|
643
|
+
color: var(--aparte-text-muted);
|
|
644
|
+
font-size: var(--aparte-font-size-xs);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.aparte-score__event-glyph {
|
|
648
|
+
--aparte-rich-card-glyph-size: 1rem;
|
|
649
|
+
color: var(--aparte-text);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
.aparte-score__event[data-type="own-goal"] .aparte-score__event-glyph { color: var(--aparte-error-ink); }
|
|
653
|
+
.aparte-score__event[data-type="yellow"] .aparte-score__event-glyph { color: var(--aparte-score-yellow); }
|
|
654
|
+
.aparte-score__event[data-type="red"] .aparte-score__event-glyph { color: var(--aparte-score-red); }
|
|
655
|
+
.aparte-score__event[data-type="sub"] .aparte-score__event-glyph { color: var(--aparte-text-muted); }
|
|
656
|
+
|
|
657
|
+
.aparte-score__event[data-type="sub"] .aparte-score__player { font-weight: var(--aparte-font-weight-normal); }
|
|
658
|
+
|
|
659
|
+
/* The team's name beside each event, for when the side no longer says it (below). */
|
|
660
|
+
.aparte-score__event-team {
|
|
661
|
+
position: absolute;
|
|
662
|
+
inline-size: 1px;
|
|
663
|
+
block-size: 1px;
|
|
664
|
+
overflow: hidden;
|
|
665
|
+
clip: rect(0 0 0 0);
|
|
666
|
+
white-space: nowrap;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/* A narrow card: one column, the minute first, the team written beside each event. */
|
|
670
|
+
@container aparte-score-events (max-width: 22rem) {
|
|
671
|
+
.aparte-score__events::before { inset-inline-start: calc(var(--aparte-score-minute-col) / 2); }
|
|
672
|
+
|
|
673
|
+
.aparte-score__event { grid-template-columns: var(--aparte-score-minute-col) minmax(0, 1fr); }
|
|
674
|
+
.aparte-score__minute { grid-column: 1; }
|
|
675
|
+
|
|
676
|
+
.aparte-score__event[data-team] .aparte-score__event-body {
|
|
677
|
+
grid-column: 2;
|
|
678
|
+
flex-direction: row;
|
|
679
|
+
justify-self: stretch;
|
|
680
|
+
padding-inline-start: var(--aparte-space-3);
|
|
681
|
+
text-align: start;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.aparte-score__event[data-team="home"] .aparte-score__event-text { justify-content: flex-start; }
|
|
685
|
+
|
|
686
|
+
.aparte-score__event-team {
|
|
687
|
+
position: static;
|
|
688
|
+
inline-size: auto;
|
|
689
|
+
block-size: auto;
|
|
690
|
+
overflow: hidden;
|
|
691
|
+
clip: auto;
|
|
692
|
+
flex: none;
|
|
693
|
+
max-inline-size: 6rem;
|
|
694
|
+
margin-inline-start: auto;
|
|
695
|
+
padding: 0 var(--aparte-space-3);
|
|
696
|
+
border-radius: var(--aparte-radius-full);
|
|
697
|
+
background: var(--aparte-score-team, var(--aparte-score-neutral));
|
|
698
|
+
color: var(--aparte-text);
|
|
699
|
+
font-size: var(--aparte-font-size-2xs);
|
|
700
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
701
|
+
line-height: 1.6;
|
|
702
|
+
text-overflow: ellipsis;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.aparte-score__event-team[data-ink="light"] { color: var(--aparte-score-ink-light); }
|
|
706
|
+
.aparte-score__event-team[data-ink="dark"] { color: var(--aparte-score-ink-dark); }
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/* ── compact and several matches: rows ─────────────────────────────────── */
|
|
710
|
+
|
|
711
|
+
.aparte-score__single,
|
|
712
|
+
.aparte-score__board-list {
|
|
713
|
+
display: flex;
|
|
714
|
+
flex-direction: column;
|
|
715
|
+
min-inline-size: 0;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.aparte-score__heading {
|
|
719
|
+
padding-block-end: var(--aparte-space-3);
|
|
720
|
+
color: var(--aparte-text);
|
|
721
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.aparte-score__heading-text { min-inline-size: 0; overflow-wrap: anywhere; }
|
|
725
|
+
|
|
726
|
+
.aparte-score__list {
|
|
727
|
+
margin: 0;
|
|
728
|
+
padding: 0;
|
|
729
|
+
list-style: none;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.aparte-score__row {
|
|
733
|
+
position: relative;
|
|
734
|
+
display: grid;
|
|
735
|
+
grid-template-columns: 4.5rem minmax(0, 1fr);
|
|
736
|
+
align-items: center;
|
|
737
|
+
gap: 0 var(--aparte-space-5);
|
|
738
|
+
padding: var(--aparte-space-4) var(--aparte-score-pad);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
.aparte-score__list .aparte-score__row + .aparte-score__row,
|
|
742
|
+
.aparte-score__single .aparte-score__head + .aparte-score__row {
|
|
743
|
+
border-block-start: var(--aparte-border-width) solid var(--aparte-score-rule);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.aparte-score__single .aparte-score__head { padding-block-end: var(--aparte-space-3); }
|
|
747
|
+
.aparte-score__single .aparte-score__head + .aparte-score__row { margin-block-start: var(--aparte-space-2); }
|
|
748
|
+
|
|
749
|
+
/* A row's band is a short bar at its start, red while the match is live. */
|
|
750
|
+
.aparte-score__row[data-phase="live"]::before {
|
|
751
|
+
content: "";
|
|
752
|
+
position: absolute;
|
|
753
|
+
inset-block: var(--aparte-space-4);
|
|
754
|
+
inset-inline-start: 0;
|
|
755
|
+
inline-size: var(--aparte-score-band-size);
|
|
756
|
+
border-start-end-radius: var(--aparte-radius-full);
|
|
757
|
+
border-end-end-radius: var(--aparte-radius-full);
|
|
758
|
+
background: var(--aparte-score-live);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.aparte-score__when {
|
|
762
|
+
display: flex;
|
|
763
|
+
flex-direction: column;
|
|
764
|
+
align-items: center;
|
|
765
|
+
justify-content: center;
|
|
766
|
+
gap: var(--aparte-space-1);
|
|
767
|
+
align-self: stretch;
|
|
768
|
+
padding-inline-end: var(--aparte-space-4);
|
|
769
|
+
border-inline-end: var(--aparte-border-width) solid var(--aparte-score-rule);
|
|
770
|
+
color: var(--aparte-text-muted);
|
|
771
|
+
font-size: var(--aparte-font-size-xs);
|
|
772
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
773
|
+
font-variant-numeric: tabular-nums;
|
|
774
|
+
line-height: 1.25;
|
|
775
|
+
text-align: center;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.aparte-score__when[data-phase="live"] {
|
|
779
|
+
flex-direction: row;
|
|
780
|
+
gap: var(--aparte-space-2);
|
|
781
|
+
color: var(--aparte-score-live-ink);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.aparte-score__when[data-phase="live"] .aparte-score__clock { font-size: var(--aparte-font-size-sm); }
|
|
785
|
+
.aparte-score__when[data-phase="halftime"],
|
|
786
|
+
.aparte-score__when[data-phase="postponed"] { color: var(--aparte-warning-ink); }
|
|
787
|
+
.aparte-score__when[data-phase="cancelled"] { color: var(--aparte-error-ink); }
|
|
788
|
+
|
|
789
|
+
.aparte-score__kickoff--row .aparte-score__day { font-weight: var(--aparte-font-weight-medium); }
|
|
790
|
+
|
|
791
|
+
.aparte-score__kickoff--row .aparte-score__hour {
|
|
792
|
+
color: var(--aparte-text);
|
|
793
|
+
font-size: var(--aparte-font-size-sm);
|
|
794
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.aparte-score__lines {
|
|
798
|
+
display: flex;
|
|
799
|
+
flex-direction: column;
|
|
800
|
+
gap: var(--aparte-space-2);
|
|
801
|
+
min-inline-size: 0;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.aparte-score__row-meta {
|
|
805
|
+
color: var(--aparte-text-muted);
|
|
806
|
+
font-size: var(--aparte-font-size-2xs);
|
|
807
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
808
|
+
letter-spacing: 0.03em;
|
|
809
|
+
text-transform: uppercase;
|
|
810
|
+
overflow-wrap: anywhere;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.aparte-score__line {
|
|
814
|
+
display: grid;
|
|
815
|
+
grid-template-columns: auto minmax(0, 1fr) auto 0.75rem;
|
|
816
|
+
align-items: center;
|
|
817
|
+
gap: var(--aparte-space-3);
|
|
818
|
+
color: var(--aparte-text);
|
|
819
|
+
font-size: var(--aparte-font-size-md);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.aparte-score__line-name {
|
|
823
|
+
min-inline-size: 0;
|
|
824
|
+
overflow: hidden;
|
|
825
|
+
text-overflow: ellipsis;
|
|
826
|
+
white-space: nowrap;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.aparte-score__line-score {
|
|
830
|
+
grid-column: 3;
|
|
831
|
+
min-inline-size: 1.5ch;
|
|
832
|
+
font-size: var(--aparte-font-size-base);
|
|
833
|
+
font-weight: var(--aparte-font-weight-semibold);
|
|
834
|
+
font-variant-numeric: tabular-nums;
|
|
835
|
+
text-align: end;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.aparte-score__win-mark {
|
|
839
|
+
grid-column: 4;
|
|
840
|
+
color: var(--aparte-text);
|
|
841
|
+
font-size: var(--aparte-font-size-2xs);
|
|
842
|
+
line-height: 1;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.aparte-score__win-mark:dir(rtl) { transform: scaleX(-1); }
|
|
846
|
+
|
|
847
|
+
.aparte-score__line[data-lead="win"] .aparte-score__line-name,
|
|
848
|
+
.aparte-score__line[data-lead="win"] .aparte-score__line-score { font-weight: var(--aparte-font-weight-bold); }
|
|
849
|
+
|
|
850
|
+
.aparte-score__line[data-lead="lose"] { color: var(--aparte-text-muted); }
|
|
851
|
+
|
|
852
|
+
/* A linked row: the whole row is the link; its ring is drawn inside the card's clipped edge. */
|
|
853
|
+
.aparte-score__link::after {
|
|
854
|
+
content: "";
|
|
855
|
+
position: absolute;
|
|
856
|
+
inset: 0;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.aparte-score__link:focus-visible { outline: none; }
|
|
860
|
+
|
|
861
|
+
.aparte-score__row[data-linked] { transition: background var(--aparte-duration-fast) ease; }
|
|
862
|
+
.aparte-score__row[data-linked]:hover { background: var(--aparte-surface-2); }
|
|
863
|
+
|
|
864
|
+
.aparte-score__row:has(.aparte-score__link:focus-visible) {
|
|
865
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
866
|
+
outline-offset: calc(var(--aparte-focus-outline-width) * -1);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/* ── Skeleton: the shapes of what is coming ───────────────────────────── */
|
|
870
|
+
|
|
871
|
+
.aparte-score__sk-meta { inline-size: 9rem; }
|
|
872
|
+
.aparte-score__sk-name { inline-size: 5rem; }
|
|
873
|
+
.aparte-score__team .aparte-score__sk-name { inline-size: 70%; margin-inline: auto; }
|
|
874
|
+
.aparte-score__sk-score { inline-size: 5rem; block-size: var(--aparte-score-num-size); border-radius: var(--aparte-radius-md); }
|
|
875
|
+
.aparte-score__sk-pill { inline-size: 4rem; block-size: 1.25rem; border-radius: var(--aparte-radius-full); }
|
|
876
|
+
.aparte-score__sk-num { inline-size: 1.25rem; block-size: 1rem; border-radius: var(--aparte-radius-sm); grid-column: 3; }
|
|
877
|
+
.aparte-score__sk-when { inline-size: 2.5rem; }
|
|
878
|
+
.aparte-score__sk-lines { display: flex; flex-direction: column; gap: var(--aparte-space-4); }
|
|
879
|
+
.aparte-score__sk-line:nth-child(even) { inline-size: 70%; }
|
|
880
|
+
.aparte-score__crest.aparte-skeleton {
|
|
881
|
+
inline-size: var(--aparte-score-crest-size);
|
|
882
|
+
block-size: var(--aparte-score-crest-size);
|
|
883
|
+
box-shadow: none;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/* ── Narrow: a smaller board, still the same board ──────────────────────── */
|
|
887
|
+
|
|
888
|
+
@container aparte-score (max-width: 20rem) {
|
|
889
|
+
.aparte-score__board { gap: var(--aparte-space-3); padding-inline: var(--aparte-space-4); }
|
|
890
|
+
.aparte-score__team-name { font-size: var(--aparte-font-size-md); }
|
|
891
|
+
.aparte-score__centre { min-inline-size: 4.5rem; }
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
@media (max-width: 380px) {
|
|
895
|
+
.aparte-score-card {
|
|
896
|
+
--aparte-score-pad: var(--aparte-space-5);
|
|
897
|
+
--aparte-score-num-size: calc(2.125rem * var(--aparte-font-scale));
|
|
898
|
+
--aparte-score-crest-lg: 2.75rem;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.aparte-score__row { grid-template-columns: 3.75rem minmax(0, 1fr); gap: 0 var(--aparte-space-4); }
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/* The kit stops every animation and transition under reduced motion; the live dot's ring
|
|
905
|
+
and the chevron's nudge are named here too, so the rule reads where they are drawn. */
|
|
906
|
+
@media (prefers-reduced-motion: reduce) {
|
|
907
|
+
.aparte-score__live-dot::after { animation: none; opacity: 0; }
|
|
908
|
+
.aparte-score__more:hover .aparte-score__chevron,
|
|
909
|
+
.aparte-score__more:hover .aparte-score__chevron:dir(rtl) { translate: none; }
|
|
910
|
+
}
|
|
911
|
+
`;
|
|
912
|
+
const S = {
|
|
913
|
+
cardsScoreTitle: { en: "Match", fr: "Match", de: "Spiel", es: "Partido", it: "Partita", ja: "試合", ko: "경기", pt: "Partida", ru: "Матч", zh: "比赛" },
|
|
914
|
+
cardsScoreCount: { en: "{n} matches", fr: "{n} matchs", de: "{n} Spiele", es: "{n} partidos", it: "{n} partite", ja: "{n}試合", ko: "{n}경기", pt: "{n} partidas", ru: "Матчей: {n}", zh: "{n} 场比赛" },
|
|
915
|
+
cardsScoreVersus: { en: "{home} vs {away}", fr: "{home} – {away}", de: "{home} gegen {away}", es: "{home} vs. {away}", it: "{home} - {away}", ja: "{home} 対 {away}", ko: "{home} 대 {away}", pt: "{home} x {away}", ru: "{home} — {away}", zh: "{home} 对 {away}" },
|
|
916
|
+
cardsScoreLive: { en: "Live", fr: "En direct", de: "Live", es: "En vivo", it: "In diretta", ja: "試合中", ko: "진행 중", pt: "Ao vivo", ru: "Идёт", zh: "进行中" },
|
|
917
|
+
cardsScoreHalfTime: { en: "Half-time", fr: "Mi-temps", de: "Halbzeit", es: "Descanso", it: "Intervallo", ja: "ハーフタイム", ko: "하프타임", pt: "Intervalo", ru: "Перерыв", zh: "中场休息" },
|
|
918
|
+
cardsScoreFullTime: { en: "Full time", fr: "Terminé", de: "Spielende", es: "Final", it: "Finale", ja: "試合終了", ko: "경기 종료", pt: "Encerrado", ru: "Матч завершён", zh: "完场" },
|
|
919
|
+
cardsScoreFinal: { en: "Final", fr: "Terminé", de: "Beendet", es: "Final", it: "Finale", ja: "試合終了", ko: "경기 종료", pt: "Final", ru: "Завершён", zh: "已结束" },
|
|
920
|
+
cardsScoreEnded: { en: "Finished", fr: "Terminé", de: "Beendet", es: "Finalizado", it: "Terminato", ja: "終了", ko: "종료", pt: "Encerrado", ru: "Завершён", zh: "已结束" },
|
|
921
|
+
cardsScorePostponed: { en: "Postponed", fr: "Reporté", de: "Verschoben", es: "Aplazado", it: "Rinviato", ja: "延期", ko: "연기", pt: "Adiado", ru: "Перенесён", zh: "延期" },
|
|
922
|
+
cardsScoreCancelled: { en: "Cancelled", fr: "Annulé", de: "Abgesagt", es: "Cancelado", it: "Annullato", ja: "中止", ko: "취소", pt: "Cancelado", ru: "Отменён", zh: "取消" },
|
|
923
|
+
cardsScoreUpcoming: { en: "Upcoming", fr: "À venir", de: "Demnächst", es: "Próximamente", it: "In programma", ja: "開始前", ko: "예정", pt: "Em breve", ru: "Скоро", zh: "未开始" },
|
|
924
|
+
cardsScoreMatchday: { en: "Matchday {n}", fr: "{n}e journée", de: "{n}. Spieltag", es: "Jornada {n}", it: "{n}ª giornata", ja: "第{n}節", ko: "{n}라운드", pt: "Rodada {n}", ru: "{n}-й тур", zh: "第{n}轮" },
|
|
925
|
+
cardsScoreTeam: { en: "Team", fr: "Équipe", de: "Team", es: "Equipo", it: "Squadra", ja: "チーム", ko: "팀", pt: "Time", ru: "Команда", zh: "球队" },
|
|
926
|
+
cardsScoreTotal: { en: "Total", fr: "Total", de: "Gesamt", es: "Total", it: "Totale", ja: "計", ko: "합계", pt: "Total", ru: "Итог", zh: "总分" },
|
|
927
|
+
cardsScoreSets: { en: "Sets", fr: "Sets", de: "Sätze", es: "Sets", it: "Set", ja: "セット", ko: "세트", pt: "Sets", ru: "Сеты", zh: "盘" },
|
|
928
|
+
cardsScorePeriods: { en: "Score by period", fr: "Score par période", de: "Ergebnis nach Abschnitten", es: "Marcador por periodo", it: "Punteggio per periodo", ja: "ピリオド別スコア", ko: "구간별 점수", pt: "Placar por período", ru: "Счёт по периодам", zh: "分节比分" },
|
|
929
|
+
cardsScoreEvents: { en: "Match events", fr: "Faits du match", de: "Spielereignisse", es: "Incidencias", it: "Eventi della partita", ja: "試合経過", ko: "경기 기록", pt: "Lances da partida", ru: "События матча", zh: "比赛事件" },
|
|
930
|
+
cardsScoreDetails: { en: "Match details", fr: "Détails du match", de: "Spieldetails", es: "Detalles del partido", it: "Dettagli partita", ja: "試合の詳細", ko: "경기 상세", pt: "Detalhes da partida", ru: "Подробнее о матче", zh: "比赛详情" }
|
|
931
|
+
};
|
|
932
|
+
const EVENT_WORDS = {
|
|
933
|
+
goal: { en: "Goal", fr: "But", de: "Tor", es: "Gol", it: "Gol", ja: "ゴール", ko: "골", pt: "Gol", ru: "Гол", zh: "进球" },
|
|
934
|
+
penalty: { en: "Penalty", fr: "Penalty", de: "Elfmeter", es: "Penalti", it: "Rigore", ja: "PK", ko: "페널티킥", pt: "Pênalti", ru: "Пенальти", zh: "点球" },
|
|
935
|
+
"own-goal": { en: "Own goal", fr: "Contre son camp", de: "Eigentor", es: "En propia puerta", it: "Autogol", ja: "オウンゴール", ko: "자책골", pt: "Gol contra", ru: "Автогол", zh: "乌龙球" },
|
|
936
|
+
yellow: { en: "Yellow card", fr: "Carton jaune", de: "Gelbe Karte", es: "Tarjeta amarilla", it: "Cartellino giallo", ja: "イエローカード", ko: "옐로카드", pt: "Cartão amarelo", ru: "Жёлтая карточка", zh: "黄牌" },
|
|
937
|
+
red: { en: "Red card", fr: "Carton rouge", de: "Rote Karte", es: "Tarjeta roja", it: "Cartellino rosso", ja: "レッドカード", ko: "레드카드", pt: "Cartão vermelho", ru: "Красная карточка", zh: "红牌" },
|
|
938
|
+
sub: { en: "Substitution", fr: "Remplacement", de: "Auswechslung", es: "Sustitución", it: "Sostituzione", ja: "選手交代", ko: "선수 교체", pt: "Substituição", ru: "Замена", zh: "换人" }
|
|
939
|
+
};
|
|
940
|
+
const EVENT_KEYS = {
|
|
941
|
+
goal: "cardsScoreGoal",
|
|
942
|
+
penalty: "cardsScorePenalty",
|
|
943
|
+
"own-goal": "cardsScoreOwnGoal",
|
|
944
|
+
yellow: "cardsScoreYellowCard",
|
|
945
|
+
red: "cardsScoreRedCard",
|
|
946
|
+
sub: "cardsScoreSubstitution"
|
|
947
|
+
};
|
|
948
|
+
const MAX_MATCHES = 12;
|
|
949
|
+
const MAX_EVENTS = 30;
|
|
950
|
+
const MAX_PERIODS = 12;
|
|
951
|
+
const MAX_BROADCASTS = 3;
|
|
952
|
+
const isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
953
|
+
function pick(r, keys) {
|
|
954
|
+
if (!r) return void 0;
|
|
955
|
+
for (const key of keys) if (r[key] !== void 0 && r[key] !== null && r[key] !== "") return r[key];
|
|
956
|
+
return void 0;
|
|
957
|
+
}
|
|
958
|
+
function textOf(value) {
|
|
959
|
+
if (isObject(value)) return str(pick(value, ["name", "displayName", "fullName", "title", "shortName", "abbreviation"]));
|
|
960
|
+
return str(value);
|
|
961
|
+
}
|
|
962
|
+
const keyOf = (value) => value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ");
|
|
963
|
+
const STATUS_WORDS = {
|
|
964
|
+
scheduled: ["scheduled", "ns", "tbd", "timed", "not started", "pre", "upcoming", "fixture", "status scheduled", "pre match", "prematch"],
|
|
965
|
+
live: ["live", "in play", "inplay", "in progress", "playing", "ongoing", "started", "1h", "2h", "et", "bt", "p", "in", "status in progress", "status end period", "status first half", "status second half", "first half", "second half", "extra time", "penalty in progress", "end of period"],
|
|
966
|
+
halftime: ["halftime", "half time", "ht", "paused", "status halftime", "interval"],
|
|
967
|
+
final: ["final", "ft", "finished", "full time", "fulltime", "ended", "aet", "pen", "awarded", "awd", "wo", "post", "complete", "completed", "closed", "match finished", "after extra time", "after penalties", "status final", "status full time", "status final aet", "status final pen", "ft pen"],
|
|
968
|
+
postponed: ["postponed", "pst", "status postponed"],
|
|
969
|
+
cancelled: ["cancelled", "canceled", "canc", "status canceled", "status cancelled"]
|
|
970
|
+
};
|
|
971
|
+
const STATUS_BY_WORD = new Map(
|
|
972
|
+
Object.entries(STATUS_WORDS).flatMap(([status, words]) => words.map((w) => [w, status]))
|
|
973
|
+
);
|
|
974
|
+
function statusOf(value) {
|
|
975
|
+
const text = str(value);
|
|
976
|
+
return text ? STATUS_BY_WORD.get(keyOf(text)) : void 0;
|
|
977
|
+
}
|
|
978
|
+
const SPORT_WORDS = [
|
|
979
|
+
["american-football", /^(american[\s_-]?football|nfl|ncaaf|gridiron|football \(american\))$/],
|
|
980
|
+
["football", /^(football|soccer|futbol|fútbol|calcio|fussball|fußball)$/],
|
|
981
|
+
["basketball", /^(basketball|basket|nba|wnba|ncaab|euroleague)$/],
|
|
982
|
+
["tennis", /^(tennis|atp|wta)$/],
|
|
983
|
+
["rugby", /^rugby/],
|
|
984
|
+
["hockey", /^((ice|field)[\s_-]?)?hockey$|^nhl$/],
|
|
985
|
+
["baseball", /^(baseball|mlb|softball)$/]
|
|
986
|
+
];
|
|
987
|
+
function sportOf(value) {
|
|
988
|
+
const text = textOf(value)?.toLowerCase();
|
|
989
|
+
if (!text) return void 0;
|
|
990
|
+
return SPORT_WORDS.find(([, re]) => re.test(text))?.[0];
|
|
991
|
+
}
|
|
992
|
+
const ESPN_SPORTS = { 1: "baseball", 20: "american-football", 40: "basketball", 70: "hockey", 600: "football", 850: "tennis" };
|
|
993
|
+
function espnSport(uid) {
|
|
994
|
+
const id = typeof uid === "string" ? /^s:(\d+)(?:~|$)/.exec(uid.trim())?.[1] : void 0;
|
|
995
|
+
return id ? ESPN_SPORTS[id] : void 0;
|
|
996
|
+
}
|
|
997
|
+
function leagueSport(league) {
|
|
998
|
+
if (!isObject(league)) return sportOf(league);
|
|
999
|
+
return espnSport(league["uid"]) ?? [league["sport"], league["abbreviation"], league["slug"], league["name"]].map(sportOf).find((s) => s !== void 0);
|
|
1000
|
+
}
|
|
1001
|
+
function teamColor(value) {
|
|
1002
|
+
if (typeof value !== "string") return void 0;
|
|
1003
|
+
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
|
|
1004
|
+
if (!match) return void 0;
|
|
1005
|
+
const hex = match[1].toLowerCase();
|
|
1006
|
+
return `#${hex.length === 3 ? [...hex].map((c) => c + c).join("") : hex}`;
|
|
1007
|
+
}
|
|
1008
|
+
function scoreOf(value) {
|
|
1009
|
+
if (isObject(value)) return num(pick(value, ["value", "displayValue", "score", "total"]));
|
|
1010
|
+
return num(value);
|
|
1011
|
+
}
|
|
1012
|
+
function minuteOf(value, extra) {
|
|
1013
|
+
if (isObject(value)) return minuteOf(pick(value, ["elapsed", "minute", "displayValue", "value"]), pick(value, ["extra", "added", "injuryTime"]));
|
|
1014
|
+
const n = num(value);
|
|
1015
|
+
if (n !== void 0) {
|
|
1016
|
+
const plus = num(extra);
|
|
1017
|
+
return `${Math.round(n)}${plus ? `+${Math.round(plus)}` : ""}'`;
|
|
1018
|
+
}
|
|
1019
|
+
return str(value);
|
|
1020
|
+
}
|
|
1021
|
+
const NAME_KEYS = ["displayName", "name", "fullName", "teamName", "team_name", "title", "shortDisplayName"];
|
|
1022
|
+
const SHORT_KEYS = ["shortName", "short_name", "abbreviation", "abbr", "tla", "code", "shortDisplayName"];
|
|
1023
|
+
const LOGO_KEYS = ["logo", "crest", "logoUrl", "logo_url", "badge", "emblem", "image", "imageUrl"];
|
|
1024
|
+
const SCORE_KEYS = ["score", "goals", "points", "pts", "runs"];
|
|
1025
|
+
const COLOR_KEYS = ["color", "colour", "primaryColor", "primary_color", "teamColor"];
|
|
1026
|
+
function readTeam(raw) {
|
|
1027
|
+
if (typeof raw === "string") {
|
|
1028
|
+
const name2 = str(raw);
|
|
1029
|
+
return name2 ? { name: name2 } : null;
|
|
1030
|
+
}
|
|
1031
|
+
if (!isObject(raw)) return null;
|
|
1032
|
+
const inner = isObject(raw["team"]) ? raw["team"] : {};
|
|
1033
|
+
const both = (keys) => pick(raw, keys) ?? pick(inner, keys);
|
|
1034
|
+
const name = str(pick(raw, NAME_KEYS)) ?? (typeof raw["team"] === "string" ? str(raw["team"]) : void 0) ?? str(pick(inner, NAME_KEYS));
|
|
1035
|
+
if (!name) return null;
|
|
1036
|
+
const shortName = str(both(SHORT_KEYS));
|
|
1037
|
+
const logos = both(["logos"]);
|
|
1038
|
+
const logo = webUrl(textOrUrl(both(LOGO_KEYS))) ?? (Array.isArray(logos) ? webUrl(textOrUrl(logos[0])) : null);
|
|
1039
|
+
const score = scoreOf(pick(raw, SCORE_KEYS));
|
|
1040
|
+
const records = raw["records"];
|
|
1041
|
+
const record = str(pick(raw, ["record", "recordSummary", "standing"])) ?? (Array.isArray(records) ? str(isObject(records[0]) ? records[0]["summary"] : records[0]) : void 0);
|
|
1042
|
+
const color = teamColor(both(COLOR_KEYS));
|
|
1043
|
+
const id = str(both(["id", "teamId", "team_id", "idTeam"]));
|
|
1044
|
+
const won = typeof raw["winner"] === "boolean" ? raw["winner"] : void 0;
|
|
1045
|
+
const lines = Array.isArray(raw["linescores"]) ? raw["linescores"] : void 0;
|
|
1046
|
+
return {
|
|
1047
|
+
name,
|
|
1048
|
+
...shortName && shortName !== name ? { shortName } : {},
|
|
1049
|
+
...logo ? { logo } : {},
|
|
1050
|
+
...score !== void 0 ? { score } : {},
|
|
1051
|
+
...record ? { record } : {},
|
|
1052
|
+
...color ? { color } : {},
|
|
1053
|
+
...id ? { id } : {},
|
|
1054
|
+
...won !== void 0 ? { won } : {},
|
|
1055
|
+
...lines ? { lines } : {}
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
function textOrUrl(value) {
|
|
1059
|
+
return isObject(value) ? pick(value, ["href", "url", "src"]) : value;
|
|
1060
|
+
}
|
|
1061
|
+
function looksLikeMatch(value) {
|
|
1062
|
+
if (!isObject(value)) return false;
|
|
1063
|
+
return ["home", "homeTeam", "home_team", "teams", "competitors", "competitions", "strHomeTeam", "participants"].some((key) => value[key] !== void 0);
|
|
1064
|
+
}
|
|
1065
|
+
function sidesOf(m) {
|
|
1066
|
+
const home = pick(m, ["home", "homeTeam", "home_team", "hometeam"]);
|
|
1067
|
+
const away = pick(m, ["away", "awayTeam", "away_team", "awayteam", "visitor", "visitors"]);
|
|
1068
|
+
if (home !== void 0 || away !== void 0) return [home, away];
|
|
1069
|
+
const teams = m["teams"];
|
|
1070
|
+
if (isObject(teams)) return [teams["home"], teams["away"]];
|
|
1071
|
+
const list = [m["competitors"], m["participants"], teams].find(Array.isArray);
|
|
1072
|
+
if (list) {
|
|
1073
|
+
const side2 = (wanted) => list.find((c) => isObject(c) && (c["homeAway"] === wanted || c["qualifier"] === wanted || c["side"] === wanted));
|
|
1074
|
+
return [side2("home") ?? list[0], side2("away") ?? list[1]];
|
|
1075
|
+
}
|
|
1076
|
+
if (m["strHomeTeam"] !== void 0) {
|
|
1077
|
+
return [
|
|
1078
|
+
{ name: m["strHomeTeam"], score: m["intHomeScore"], logo: m["strHomeTeamBadge"] },
|
|
1079
|
+
{ name: m["strAwayTeam"], score: m["intAwayScore"], logo: m["strAwayTeamBadge"] }
|
|
1080
|
+
];
|
|
1081
|
+
}
|
|
1082
|
+
return [void 0, void 0];
|
|
1083
|
+
}
|
|
1084
|
+
function matchScores(m) {
|
|
1085
|
+
const pair = (value) => {
|
|
1086
|
+
if (!isObject(value)) return void 0;
|
|
1087
|
+
const h = scoreOf(value["home"]);
|
|
1088
|
+
const a = scoreOf(value["away"]);
|
|
1089
|
+
return h !== void 0 || a !== void 0 ? [h, a] : void 0;
|
|
1090
|
+
};
|
|
1091
|
+
const score = m["score"];
|
|
1092
|
+
const text = typeof score === "string" ? /^\s*(\d+)\s*[-–:]\s*(\d+)\s*$/.exec(score) : null;
|
|
1093
|
+
return pair(m["goals"]) ?? pair(score) ?? pair(m["scores"]) ?? (isObject(score) ? pair(score["fullTime"]) ?? pair(score["fulltime"]) ?? pair(score["current"]) : void 0) ?? (text ? [Number(text[1]), Number(text[2])] : void 0) ?? [scoreOf(pick(m, ["homeScore", "home_score", "scoreHome"])), scoreOf(pick(m, ["awayScore", "away_score", "scoreAway"]))];
|
|
1094
|
+
}
|
|
1095
|
+
function readState(m, fixture) {
|
|
1096
|
+
const raw = pick(m, ["status", "state", "strStatus", "matchStatus", "match_status"]) ?? fixture["status"];
|
|
1097
|
+
let status;
|
|
1098
|
+
let text;
|
|
1099
|
+
let clock = minuteOf(pick(m, ["clock", "minute", "elapsed", "time_elapsed"]), pick(m, ["injuryTime", "injury_time"]));
|
|
1100
|
+
let period = pick(m, ["period", "currentPeriod"]);
|
|
1101
|
+
if (isObject(raw)) {
|
|
1102
|
+
const type = isObject(raw["type"]) ? raw["type"] : {};
|
|
1103
|
+
const said = [raw["short"], type["name"], type["state"], raw["long"], type["shortDetail"], type["description"], raw["name"], raw["state"], raw["description"]];
|
|
1104
|
+
status = said.map(statusOf).find((s) => s !== void 0);
|
|
1105
|
+
text = str(raw["long"] ?? type["description"] ?? type["detail"] ?? raw["short"] ?? raw["description"]);
|
|
1106
|
+
clock ??= minuteOf(pick(raw, ["elapsed", "minute"]), raw["extra"]) ?? str(raw["displayClock"] ?? raw["clock"]);
|
|
1107
|
+
period ??= pick(raw, ["period"]);
|
|
1108
|
+
} else {
|
|
1109
|
+
status = statusOf(raw);
|
|
1110
|
+
text = str(raw);
|
|
1111
|
+
}
|
|
1112
|
+
const periodNumber = num(period);
|
|
1113
|
+
return {
|
|
1114
|
+
...status ? { status } : text ? { statusText: text } : {},
|
|
1115
|
+
...clock ? { clock } : {},
|
|
1116
|
+
...typeof period === "string" && str(period) ? { period: str(period) } : {},
|
|
1117
|
+
...periodNumber !== void 0 && typeof period !== "string" ? { periodNumber } : {}
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
function periodName(sport, n) {
|
|
1121
|
+
if (sport === "basketball" || sport === "american-football") return `Q${n}`;
|
|
1122
|
+
if (sport === "hockey") return `P${n}`;
|
|
1123
|
+
return void 0;
|
|
1124
|
+
}
|
|
1125
|
+
function readPeriods(m, home, away) {
|
|
1126
|
+
let periods = [];
|
|
1127
|
+
const list = [m["periods"], m["sets"], m["linescores"], m["innings"]].find(Array.isArray);
|
|
1128
|
+
if (list) {
|
|
1129
|
+
periods = list.map((p, i) => {
|
|
1130
|
+
if (Array.isArray(p)) return { label: String(i + 1), ...side("home", num(p[0])), ...side("away", num(p[1])) };
|
|
1131
|
+
if (!isObject(p)) return null;
|
|
1132
|
+
const label2 = str(pick(p, ["label", "name", "period", "set", "number"])) ?? String(i + 1);
|
|
1133
|
+
return { label: label2, ...side("home", scoreOf(pick(p, ["home", "homeScore", "home_score", "h"]))), ...side("away", scoreOf(pick(p, ["away", "awayScore", "away_score", "a"]))) };
|
|
1134
|
+
}).filter((p) => p !== null);
|
|
1135
|
+
} else if (home.lines || away.lines) {
|
|
1136
|
+
const count = Math.max(home.lines?.length ?? 0, away.lines?.length ?? 0);
|
|
1137
|
+
for (let i = 0; i < count; i++) {
|
|
1138
|
+
const at = (lines) => scoreOf(lines?.[i]);
|
|
1139
|
+
const p = home.lines?.[i] ?? away.lines?.[i];
|
|
1140
|
+
const label2 = (isObject(p) ? str(pick(p, ["label", "period"])) : void 0) ?? String(i + 1);
|
|
1141
|
+
periods.push({ label: label2, ...side("home", at(home.lines)), ...side("away", at(away.lines)) });
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
periods = periods.filter((p) => p.home !== void 0 || p.away !== void 0).slice(0, MAX_PERIODS);
|
|
1145
|
+
return periods.length ? periods : void 0;
|
|
1146
|
+
}
|
|
1147
|
+
const side = (key, value) => value !== void 0 ? { [key]: value } : {};
|
|
1148
|
+
function eventType(type, detail, flags) {
|
|
1149
|
+
if (flags["ownGoal"] === true) return "own-goal";
|
|
1150
|
+
if (flags["penaltyKick"] === true && flags["scoringPlay"] !== false) return "penalty";
|
|
1151
|
+
if (flags["redCard"] === true) return "red";
|
|
1152
|
+
if (flags["yellowCard"] === true) return "yellow";
|
|
1153
|
+
const typed = typeof type === "string" ? keyOf(type) : isObject(type) ? keyOf(String(type["text"] ?? type["type"] ?? "")) : "";
|
|
1154
|
+
if (/^var\b/.test(typed)) return null;
|
|
1155
|
+
for (const value of [detail, type]) {
|
|
1156
|
+
const t = typeof value === "string" ? keyOf(value) : isObject(value) ? keyOf(String(value["text"] ?? value["type"] ?? "")) : "";
|
|
1157
|
+
if (!t) continue;
|
|
1158
|
+
if (/missed|saved|cancel|disallow/.test(t)) return null;
|
|
1159
|
+
if (/own goal|^og$|^own$/.test(t)) return "own-goal";
|
|
1160
|
+
if (/penalty|^pen$|^pk$/.test(t) && !/card/.test(t)) return "penalty";
|
|
1161
|
+
if (/red|second yellow|yellow red|yellowred/.test(t)) return "red";
|
|
1162
|
+
if (/yellow/.test(t)) return "yellow";
|
|
1163
|
+
if (/^sub|substitution|^subst|replacement/.test(t)) return "sub";
|
|
1164
|
+
if (/goal|^regular$|^normal$|scor/.test(t)) return "goal";
|
|
1165
|
+
}
|
|
1166
|
+
if (flags["scoringPlay"] === true) return "goal";
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
function eventSide(e, home, away) {
|
|
1170
|
+
const said = pick(e, ["side", "homeAway", "team"]);
|
|
1171
|
+
if (said === "home" || said === "away") return said;
|
|
1172
|
+
if (typeof e["isHome"] === "boolean") return e["isHome"] ? "home" : "away";
|
|
1173
|
+
const team = pick(e, ["team", "club"]);
|
|
1174
|
+
const id = isObject(team) ? str(team["id"]) : void 0;
|
|
1175
|
+
const name = textOf(team)?.toLowerCase();
|
|
1176
|
+
const matches = (t) => id !== void 0 && t.id === id || !!name && (t.name.toLowerCase() === name || t.shortName?.toLowerCase() === name);
|
|
1177
|
+
if (matches(home)) return "home";
|
|
1178
|
+
if (matches(away)) return "away";
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
function readEvent(raw, home, away, implied) {
|
|
1182
|
+
if (!isObject(raw)) return null;
|
|
1183
|
+
const e = raw;
|
|
1184
|
+
const team = eventSide(e, home, away);
|
|
1185
|
+
if (!team) return null;
|
|
1186
|
+
const kind = implied === "sub" ? "sub" : implied === "yellow" ? eventType(e["card"] ?? e["type"], void 0, e) ?? "yellow" : eventType(e["type"] ?? e["kind"] ?? e["card"], e["detail"], e) ?? (implied === "goal" ? "goal" : null);
|
|
1187
|
+
if (!kind) return null;
|
|
1188
|
+
const minute = minuteOf(pick(e, ["minute", "time", "clock", "elapsed", "min"]), e["extra"] ?? e["injuryTime"]);
|
|
1189
|
+
const athletes = e["athletesInvolved"];
|
|
1190
|
+
const player = textOf(pick(e, ["player", "scorer", "playerIn", "athlete", "playerName", "player_name"])) ?? (Array.isArray(athletes) ? textOf(athletes[0]) : void 0);
|
|
1191
|
+
const typed = typeof e["detail"] === "string" && eventType(void 0, e["detail"], {}) !== null;
|
|
1192
|
+
const detail = (typed ? void 0 : str(e["detail"])) ?? textOf(pick(e, ["assist", "playerOut", "note", "description"]));
|
|
1193
|
+
return {
|
|
1194
|
+
...minute ? { minute } : {},
|
|
1195
|
+
team,
|
|
1196
|
+
type: kind,
|
|
1197
|
+
...player ? { player } : {},
|
|
1198
|
+
...detail && detail !== player ? { detail } : {}
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function readEvents(m, home, away) {
|
|
1202
|
+
const events = [];
|
|
1203
|
+
const list = [m["events"], m["incidents"], m["timeline"], m["details"], m["keyEvents"]].find(Array.isArray);
|
|
1204
|
+
for (const e of list ?? []) events.push(readEvent(e, home, away));
|
|
1205
|
+
if (!list) {
|
|
1206
|
+
const lists = [[m["goals"], "goal"], [m["bookings"], "yellow"], [m["substitutions"], "sub"]];
|
|
1207
|
+
for (const [items, type] of lists) if (Array.isArray(items)) for (const e of items) events.push(readEvent(e, home, away, type));
|
|
1208
|
+
}
|
|
1209
|
+
const kept = events.filter((e) => e !== null);
|
|
1210
|
+
if (!list && kept.length) kept.sort((a, b) => minuteValue(a.minute) - minuteValue(b.minute));
|
|
1211
|
+
const shown = kept.slice(0, MAX_EVENTS);
|
|
1212
|
+
return shown.length ? shown : void 0;
|
|
1213
|
+
}
|
|
1214
|
+
function minuteValue(minute) {
|
|
1215
|
+
const match = /(\d+)(?:\s*\+\s*(\d+))?/.exec(minute ?? "");
|
|
1216
|
+
return match ? Number(match[1]) + Number(match[2] ?? 0) / 100 : Infinity;
|
|
1217
|
+
}
|
|
1218
|
+
function readRound(m, league) {
|
|
1219
|
+
const week = m["week"];
|
|
1220
|
+
const matchday = num(pick(m, ["matchday", "matchDay", "gameweek", "intRound"])) ?? num(isObject(week) ? week["number"] : week);
|
|
1221
|
+
const round = str(pick(m, ["round", "roundName"])) ?? str(league["round"]);
|
|
1222
|
+
const regular = round ? /^regular season\s*[-–]\s*(\d+)$/i.exec(round) : null;
|
|
1223
|
+
if (regular) return { matchday: Number(regular[1]) };
|
|
1224
|
+
if (round) return { round };
|
|
1225
|
+
if (matchday !== void 0) return { matchday };
|
|
1226
|
+
const stage = str(m["stage"]);
|
|
1227
|
+
if (stage && !/^regular[_\s]season$/i.test(stage)) {
|
|
1228
|
+
const words = stage.replace(/_/g, " ").toLowerCase();
|
|
1229
|
+
return { round: words.charAt(0).toUpperCase() + words.slice(1) };
|
|
1230
|
+
}
|
|
1231
|
+
return {};
|
|
1232
|
+
}
|
|
1233
|
+
function readBroadcast(m) {
|
|
1234
|
+
const raw = pick(m, ["broadcast", "broadcasts", "tv", "channel", "channels", "strTVStation", "geoBroadcasts"]);
|
|
1235
|
+
const names = (Array.isArray(raw) ? raw : [raw]).flatMap((b) => {
|
|
1236
|
+
if (isObject(b) && Array.isArray(b["names"])) return b["names"].map(str);
|
|
1237
|
+
if (isObject(b) && isObject(b["media"])) return [textOf(b["media"])];
|
|
1238
|
+
return [textOf(b)];
|
|
1239
|
+
}).filter((n) => !!n);
|
|
1240
|
+
const unique = [...new Set(names)].slice(0, MAX_BROADCASTS);
|
|
1241
|
+
return unique.length ? unique.join(", ") : void 0;
|
|
1242
|
+
}
|
|
1243
|
+
function readVenue(value) {
|
|
1244
|
+
if (!isObject(value)) return str(value);
|
|
1245
|
+
const name = textOf(value);
|
|
1246
|
+
const address = isObject(value["address"]) ? value["address"] : {};
|
|
1247
|
+
const city = str(value["city"] ?? address["city"]);
|
|
1248
|
+
return name && city && !name.includes(city) ? `${name}, ${city}` : name ?? city;
|
|
1249
|
+
}
|
|
1250
|
+
const utc = (value) => typeof value === "string" && /^\d{4}-\d\d-\d\dT\d\d:\d\d(:\d\d)?$/.test(value.trim()) ? `${value.trim()}Z` : value;
|
|
1251
|
+
function readMatch(raw, league0) {
|
|
1252
|
+
if (!isObject(raw)) return null;
|
|
1253
|
+
const competitions = raw["competitions"];
|
|
1254
|
+
const m = Array.isArray(competitions) && isObject(competitions[0]) ? { ...raw, ...competitions[0], status: competitions[0]["status"] ?? raw["status"] } : raw;
|
|
1255
|
+
const fixture = isObject(m["fixture"]) ? m["fixture"] : {};
|
|
1256
|
+
const league = isObject(m["league"]) ? m["league"] : {};
|
|
1257
|
+
const [rawHome, rawAway] = sidesOf(m);
|
|
1258
|
+
const home = readTeam(rawHome);
|
|
1259
|
+
const away = readTeam(rawAway);
|
|
1260
|
+
if (!home || !away) return null;
|
|
1261
|
+
const [homeScore, awayScore] = matchScores(m);
|
|
1262
|
+
if (home.score === void 0 && homeScore !== void 0) home.score = homeScore;
|
|
1263
|
+
if (away.score === void 0 && awayScore !== void 0) away.score = awayScore;
|
|
1264
|
+
const sport = sportOf(pick(m, ["sport", "strSport", "sportName", "discipline"]) ?? league["sport"]) ?? espnSport(raw["uid"] ?? m["uid"]) ?? (league0 !== void 0 ? leagueSport(league0) : void 0) ?? (m["fixture"] !== void 0 || m["goals"] !== void 0 || isObject(m["score"]) && isObject(m["score"]["fullTime"]) ? "football" : "generic");
|
|
1265
|
+
const state = readState(m, fixture);
|
|
1266
|
+
const period = state.period ?? (state.periodNumber !== void 0 ? periodName(sport, state.periodNumber) : void 0);
|
|
1267
|
+
const startTime = toDate(utc(pick(m, ["startTime", "start_time", "start", "kickoff", "kickOff", "kick_off", "utcDate", "date", "datetime", "dateTime", "startDate", "commence_time", "strTimestamp"]))) ?? toDate(fixture["date"] ?? fixture["timestamp"]);
|
|
1268
|
+
const competition = textOf(pick(m, ["competition", "tournament", "strLeague", "leagueName"]) ?? m["league"]);
|
|
1269
|
+
const venue = readVenue(pick(m, ["venue", "stadium", "strVenue", "arena"]) ?? fixture["venue"]);
|
|
1270
|
+
const periods = readPeriods(m, home, away);
|
|
1271
|
+
const events = readEvents(m, home, away);
|
|
1272
|
+
const links = m["links"];
|
|
1273
|
+
const url = webUrl(textOrUrl(pick(m, ["url", "link", "href", "matchUrl", "match_url"]))) ?? (Array.isArray(links) ? webUrl(textOrUrl(links[0])) : null);
|
|
1274
|
+
const broadcast = readBroadcast(m);
|
|
1275
|
+
for (const key of ["home", "away"]) {
|
|
1276
|
+
const team = key === "home" ? home : away;
|
|
1277
|
+
if (team.score !== void 0 || !periods || state.status === "scheduled") continue;
|
|
1278
|
+
const other = key === "home" ? "away" : "home";
|
|
1279
|
+
const own = periods.map((p) => p[key]);
|
|
1280
|
+
if (own.some((v) => v === void 0)) continue;
|
|
1281
|
+
team.score = sport === "tennis" ? periods.filter((p) => setWon(p[key] ?? 0, p[other] ?? 0)).length : own.reduce((sum, v) => sum + (v ?? 0), 0);
|
|
1282
|
+
}
|
|
1283
|
+
const winner = readWinner(m, home, away, state.status);
|
|
1284
|
+
const strip = ({ id: _id, won: _won, lines: _lines, ...team }) => team;
|
|
1285
|
+
return {
|
|
1286
|
+
home: strip(home),
|
|
1287
|
+
away: strip(away),
|
|
1288
|
+
...state.status ? { status: state.status } : {},
|
|
1289
|
+
...state.statusText ? { statusText: state.statusText } : {},
|
|
1290
|
+
...state.clock ? { clock: state.clock } : {},
|
|
1291
|
+
...period ? { period } : {},
|
|
1292
|
+
...startTime ? { startTime } : {},
|
|
1293
|
+
...competition ? { competition } : {},
|
|
1294
|
+
...readRound(m, league),
|
|
1295
|
+
...venue ? { venue } : {},
|
|
1296
|
+
sport,
|
|
1297
|
+
...periods ? { periods } : {},
|
|
1298
|
+
...events ? { events } : {},
|
|
1299
|
+
...winner ? { winner } : {},
|
|
1300
|
+
...broadcast ? { broadcast } : {},
|
|
1301
|
+
...url ? { url } : {}
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
const setWon = (own, other) => own > other && own >= 6 && (own - other >= 2 || own === 7);
|
|
1305
|
+
function readWinner(m, home, away, status) {
|
|
1306
|
+
const score = isObject(m["score"]) ? m["score"] : {};
|
|
1307
|
+
const said = str(m["winner"] ?? score["winner"])?.toLowerCase();
|
|
1308
|
+
if (said === "home" || said === "home_team") return "home";
|
|
1309
|
+
if (said === "away" || said === "away_team") return "away";
|
|
1310
|
+
if (said && said === home.name.toLowerCase()) return "home";
|
|
1311
|
+
if (said && said === away.name.toLowerCase()) return "away";
|
|
1312
|
+
if (home.won === true || away.won === false && home.won === void 0) return "home";
|
|
1313
|
+
if (away.won === true) return "away";
|
|
1314
|
+
if (said === "draw" || status !== "final" || home.score === void 0 || away.score === void 0 || home.score === away.score) return void 0;
|
|
1315
|
+
return home.score > away.score ? "home" : "away";
|
|
1316
|
+
}
|
|
1317
|
+
function readMatches(raw) {
|
|
1318
|
+
let list;
|
|
1319
|
+
let title;
|
|
1320
|
+
let league;
|
|
1321
|
+
if (Array.isArray(raw)) {
|
|
1322
|
+
list = raw;
|
|
1323
|
+
} else if (isObject(raw)) {
|
|
1324
|
+
const found = [raw["matches"], raw["fixtures"], raw["games"], raw["results"], raw["response"], raw["data"], raw["scores"], raw["events"]].find((v) => Array.isArray(v) && v.some(looksLikeMatch));
|
|
1325
|
+
if (found && !looksLikeMatch(raw)) {
|
|
1326
|
+
list = found;
|
|
1327
|
+
const leagues = raw["leagues"];
|
|
1328
|
+
league = Array.isArray(leagues) ? leagues[0] : raw["league"];
|
|
1329
|
+
title = str(raw["title"] ?? raw["heading"]) ?? textOf(raw["competition"] ?? raw["league"]) ?? (Array.isArray(leagues) ? textOf(leagues[0]) : void 0);
|
|
1330
|
+
} else {
|
|
1331
|
+
list = [raw];
|
|
1332
|
+
}
|
|
1333
|
+
} else {
|
|
1334
|
+
return null;
|
|
1335
|
+
}
|
|
1336
|
+
const matches = list.map((item) => readMatch(item, league)).filter((m) => m !== null).slice(0, MAX_MATCHES);
|
|
1337
|
+
if (!matches.length) return null;
|
|
1338
|
+
return { ...title ? { title } : {}, matches };
|
|
1339
|
+
}
|
|
1340
|
+
function phaseOf(match) {
|
|
1341
|
+
if (match.status) return match.status;
|
|
1342
|
+
if (match.statusText) return "other";
|
|
1343
|
+
if (hasScore(match)) return "none";
|
|
1344
|
+
return match.startTime ? "scheduled" : "none";
|
|
1345
|
+
}
|
|
1346
|
+
const hasScore = (match) => match.home.score !== void 0 && match.away.score !== void 0;
|
|
1347
|
+
function showsScore(match) {
|
|
1348
|
+
const phase = phaseOf(match);
|
|
1349
|
+
return hasScore(match) && phase !== "scheduled" && !((phase === "postponed" || phase === "cancelled") && match.home.score === 0 && match.away.score === 0);
|
|
1350
|
+
}
|
|
1351
|
+
function endWord(sport) {
|
|
1352
|
+
if (sport === "football" || sport === "rugby") return "cardsScoreFullTime";
|
|
1353
|
+
if (sport === "tennis" || sport === "generic") return "cardsScoreEnded";
|
|
1354
|
+
return "cardsScoreFinal";
|
|
1355
|
+
}
|
|
1356
|
+
function clockText(match) {
|
|
1357
|
+
const parts = [match.period && !match.clock?.includes(match.period) ? match.period : void 0, match.clock].filter(Boolean);
|
|
1358
|
+
return parts.length ? parts.join(" ") : void 0;
|
|
1359
|
+
}
|
|
1360
|
+
function statusText(config, match) {
|
|
1361
|
+
const phase = phaseOf(match);
|
|
1362
|
+
switch (phase) {
|
|
1363
|
+
case "live": {
|
|
1364
|
+
const clock = clockText(match);
|
|
1365
|
+
return `${word(config, "cardsScoreLive", S.cardsScoreLive)}${clock ? ` ${clock}` : ""}`;
|
|
1366
|
+
}
|
|
1367
|
+
case "halftime":
|
|
1368
|
+
return word(config, "cardsScoreHalfTime", S.cardsScoreHalfTime);
|
|
1369
|
+
case "final":
|
|
1370
|
+
return word(config, endWord(match.sport), S[endWord(match.sport)]);
|
|
1371
|
+
case "postponed":
|
|
1372
|
+
return word(config, "cardsScorePostponed", S.cardsScorePostponed);
|
|
1373
|
+
case "cancelled":
|
|
1374
|
+
return word(config, "cardsScoreCancelled", S.cardsScoreCancelled);
|
|
1375
|
+
case "other":
|
|
1376
|
+
return match.statusText;
|
|
1377
|
+
default:
|
|
1378
|
+
return void 0;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
1382
|
+
function dayText(config, date, now) {
|
|
1383
|
+
const days = Math.round((startOfDay(date) - startOfDay(now)) / 864e5);
|
|
1384
|
+
if (days === -1) {
|
|
1385
|
+
const tag = intlTag(config);
|
|
1386
|
+
const text = new Intl.RelativeTimeFormat(tag, { numeric: "auto" }).format(-1, "day");
|
|
1387
|
+
return text.charAt(0).toLocaleUpperCase(tag) + text.slice(1);
|
|
1388
|
+
}
|
|
1389
|
+
if (days >= 0 && days <= 6) return formatDay(config, date, "short", now);
|
|
1390
|
+
return new Intl.DateTimeFormat(intlTag(config), { weekday: "short", day: "numeric", month: "short" }).format(date);
|
|
1391
|
+
}
|
|
1392
|
+
const whenText = (config, date, now) => `${dayText(config, date, now)} ${formatHour(config, date)}`;
|
|
1393
|
+
const versus = (config, match) => word(config, "cardsScoreVersus", S.cardsScoreVersus, { home: match.home.name, away: match.away.name });
|
|
1394
|
+
const absoluteWhen = (config, date) => new Intl.DateTimeFormat(intlTag(config), {
|
|
1395
|
+
weekday: "short",
|
|
1396
|
+
year: "numeric",
|
|
1397
|
+
month: "short",
|
|
1398
|
+
day: "numeric",
|
|
1399
|
+
hour: "numeric",
|
|
1400
|
+
minute: "2-digit",
|
|
1401
|
+
timeZoneName: "short"
|
|
1402
|
+
}).format(date);
|
|
1403
|
+
function matchSentence(config, match, now) {
|
|
1404
|
+
const said = statusText(config, match);
|
|
1405
|
+
if (showsScore(match)) {
|
|
1406
|
+
const score = `${match.home.name} ${formatNumber(config, match.home.score)}–${formatNumber(config, match.away.score)} ${match.away.name}`;
|
|
1407
|
+
return said ? `${score} (${said})` : score;
|
|
1408
|
+
}
|
|
1409
|
+
if (said) return `${versus(config, match)} (${said})`;
|
|
1410
|
+
if (!match.startTime) return versus(config, match);
|
|
1411
|
+
return `${versus(config, match)} — ${now ? whenText(config, match.startTime, now) : absoluteWhen(config, match.startTime)}`;
|
|
1412
|
+
}
|
|
1413
|
+
const notNull = (value) => value !== null && value !== void 0 && value !== false;
|
|
1414
|
+
const dot = () => el("span", { class: "aparte-score__dot", attrs: { "aria-hidden": "true" }, text: "·" });
|
|
1415
|
+
function monogram(team) {
|
|
1416
|
+
const short = team.shortName?.replace(/[^\p{L}\p{N}]/gu, "");
|
|
1417
|
+
if (short && [...short].length <= 3) return short.toLocaleUpperCase();
|
|
1418
|
+
const name = team.name;
|
|
1419
|
+
if (/[\u3040-\u30ff\u3400-\u9fff\uac00-\ud7af]/.test(name)) return [...name.replace(/\s+/g, "")].slice(0, 2).join("");
|
|
1420
|
+
const words = name.split(/[\s\-–.'’/&]+/).map((w) => w.replace(/[^\p{L}\p{N}]/gu, "")).filter(Boolean);
|
|
1421
|
+
const meaningful = words.filter((w) => !CLUB_PARTS.has(w.toLowerCase()));
|
|
1422
|
+
const kept = meaningful.length ? meaningful : words;
|
|
1423
|
+
if (!kept.length) return "?";
|
|
1424
|
+
const letters = kept.length === 1 ? [...kept[0]].slice(0, 3).join("") : kept.slice(0, 3).map((w) => [...w][0]).join("");
|
|
1425
|
+
return letters.toLocaleUpperCase();
|
|
1426
|
+
}
|
|
1427
|
+
const CLUB_PARTS = /* @__PURE__ */ new Set(["fc", "cf", "afc", "ac", "as", "sc", "sv", "cd", "rc", "ssc", "club", "de", "del", "the", "of", "and", "vfb", "vfl", "tsg", "bk", "if", "fk", "sk"]);
|
|
1428
|
+
function inkOn(hex) {
|
|
1429
|
+
const channel = (i) => {
|
|
1430
|
+
const c = parseInt(hex.slice(1 + i * 2, 3 + i * 2), 16) / 255;
|
|
1431
|
+
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
1432
|
+
};
|
|
1433
|
+
const luminance = 0.2126 * channel(0) + 0.7152 * channel(1) + 0.0722 * channel(2);
|
|
1434
|
+
return luminance > 0.179 ? "dark" : "light";
|
|
1435
|
+
}
|
|
1436
|
+
function wear(node, property, color) {
|
|
1437
|
+
if (color) node.style.setProperty(property, color);
|
|
1438
|
+
}
|
|
1439
|
+
function crestOf(team, size) {
|
|
1440
|
+
const box = el(
|
|
1441
|
+
"span",
|
|
1442
|
+
{ class: `aparte-score__crest aparte-score__crest--${size}`, attrs: { "aria-hidden": "true", "data-ink": team.color ? inkOn(team.color) : void 0 } },
|
|
1443
|
+
el("span", { class: "aparte-score__monogram", text: monogram(team) })
|
|
1444
|
+
);
|
|
1445
|
+
wear(box, "--aparte-score-team", team.color);
|
|
1446
|
+
if (team.logo) {
|
|
1447
|
+
const img = el("img", { class: "aparte-score__logo", attrs: { src: team.logo, alt: "", loading: "lazy", decoding: "async" } });
|
|
1448
|
+
img.addEventListener("error", () => {
|
|
1449
|
+
img.remove();
|
|
1450
|
+
box.removeAttribute("data-logo");
|
|
1451
|
+
}, { once: true });
|
|
1452
|
+
box.setAttribute("data-logo", "");
|
|
1453
|
+
box.append(img);
|
|
1454
|
+
}
|
|
1455
|
+
return box;
|
|
1456
|
+
}
|
|
1457
|
+
const leadOf = (match, key) => match.winner ? match.winner === key ? "win" : "lose" : void 0;
|
|
1458
|
+
function numberOf(ctx, value, className, attrs = {}) {
|
|
1459
|
+
const node = el("span", { class: className, attrs });
|
|
1460
|
+
ctx.bind(node, () => formatNumber(ctx.config, value));
|
|
1461
|
+
return node;
|
|
1462
|
+
}
|
|
1463
|
+
function pillOf(ctx, match) {
|
|
1464
|
+
const phase = phaseOf(match);
|
|
1465
|
+
if (phase === "scheduled" || phase === "none") return null;
|
|
1466
|
+
const pill = el("span", { class: "aparte-score__pill", attrs: { "data-phase": phase } });
|
|
1467
|
+
if (phase === "live") {
|
|
1468
|
+
const said = el("span", { class: "aparte-score__live-word" });
|
|
1469
|
+
ctx.word(said, "cardsScoreLive", S.cardsScoreLive);
|
|
1470
|
+
const clock = clockText(match);
|
|
1471
|
+
pill.append(el("span", { class: "aparte-score__live-dot", attrs: { "aria-hidden": "true" } }), said);
|
|
1472
|
+
if (clock) pill.append(el("span", { class: "aparte-score__clock", text: clock }));
|
|
1473
|
+
return pill;
|
|
1474
|
+
}
|
|
1475
|
+
ctx.bind(pill, () => statusText(ctx.config, match));
|
|
1476
|
+
return pill;
|
|
1477
|
+
}
|
|
1478
|
+
function kickoffOf(ctx, date, now, className) {
|
|
1479
|
+
const node = el("time", { class: className, attrs: { datetime: date.toISOString() } });
|
|
1480
|
+
const day = el("span", { class: "aparte-score__day" });
|
|
1481
|
+
const hour = el("span", { class: "aparte-score__hour" });
|
|
1482
|
+
ctx.bind(day, () => dayText(ctx.config, date, now));
|
|
1483
|
+
ctx.bind(hour, () => formatHour(ctx.config, date));
|
|
1484
|
+
node.append(day, hour);
|
|
1485
|
+
return node;
|
|
1486
|
+
}
|
|
1487
|
+
function centreOf(ctx, match, now) {
|
|
1488
|
+
const centre = el("div", { class: "aparte-score__centre" });
|
|
1489
|
+
const phase = phaseOf(match);
|
|
1490
|
+
if (showsScore(match)) {
|
|
1491
|
+
const result = el(
|
|
1492
|
+
"div",
|
|
1493
|
+
{ class: "aparte-score__result", attrs: { "aria-hidden": "true" } },
|
|
1494
|
+
numberOf(ctx, match.home.score, "aparte-score__num", { "data-lead": leadOf(match, "home") }),
|
|
1495
|
+
el("span", { class: "aparte-score__sep", text: "–" }),
|
|
1496
|
+
numberOf(ctx, match.away.score, "aparte-score__num", { "data-lead": leadOf(match, "away") })
|
|
1497
|
+
);
|
|
1498
|
+
const said = el("span", { class: "aparte-score__sr" });
|
|
1499
|
+
ctx.bind(said, () => `${match.home.name} ${formatNumber(ctx.config, match.home.score)}, ${match.away.name} ${formatNumber(ctx.config, match.away.score)}`);
|
|
1500
|
+
centre.append(result, said);
|
|
1501
|
+
} else if (match.startTime) {
|
|
1502
|
+
centre.append(kickoffOf(ctx, match.startTime, now, "aparte-score__kickoff"));
|
|
1503
|
+
} else {
|
|
1504
|
+
centre.append(el("div", { class: "aparte-score__result", attrs: { "aria-hidden": "true" } }, el("span", { class: "aparte-score__sep", text: "–" })));
|
|
1505
|
+
}
|
|
1506
|
+
const pill = pillOf(ctx, match);
|
|
1507
|
+
if (pill) centre.append(pill);
|
|
1508
|
+
else if (phase === "scheduled" && !match.startTime) {
|
|
1509
|
+
const upcoming = el("span", { class: "aparte-score__pill", attrs: { "data-phase": "scheduled" } });
|
|
1510
|
+
ctx.word(upcoming, "cardsScoreUpcoming", S.cardsScoreUpcoming);
|
|
1511
|
+
centre.append(upcoming);
|
|
1512
|
+
}
|
|
1513
|
+
return centre;
|
|
1514
|
+
}
|
|
1515
|
+
function teamOf(match, key) {
|
|
1516
|
+
const team = match[key];
|
|
1517
|
+
return el(
|
|
1518
|
+
"div",
|
|
1519
|
+
{ class: `aparte-score__team aparte-score__team--${key}`, attrs: { "data-lead": leadOf(match, key) } },
|
|
1520
|
+
crestOf(team, "lg"),
|
|
1521
|
+
el("span", { class: "aparte-score__team-name", text: team.name }),
|
|
1522
|
+
team.record ? el("span", { class: "aparte-score__record", text: team.record }) : null
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
function headOf(ctx, match, now) {
|
|
1526
|
+
const parts = [];
|
|
1527
|
+
if (match.competition) parts.push(el("span", { class: "aparte-score__competition", text: match.competition }));
|
|
1528
|
+
if (match.round) parts.push(el("span", { class: "aparte-score__round", text: match.round }));
|
|
1529
|
+
else if (match.matchday !== void 0) {
|
|
1530
|
+
const day = match.matchday;
|
|
1531
|
+
const round = el("span", { class: "aparte-score__round" });
|
|
1532
|
+
ctx.bind(round, () => word(ctx.config, "cardsScoreMatchday", S.cardsScoreMatchday, { n: formatNumber(ctx.config, day) }));
|
|
1533
|
+
parts.push(round);
|
|
1534
|
+
}
|
|
1535
|
+
const date = match.startTime && showsScore(match) ? match.startTime : void 0;
|
|
1536
|
+
if (!parts.length && !date) return null;
|
|
1537
|
+
const line = el("div", { class: "aparte-score__meta" });
|
|
1538
|
+
parts.forEach((part, i) => line.append(...i ? [dot(), part] : [part]));
|
|
1539
|
+
let when = null;
|
|
1540
|
+
if (date) {
|
|
1541
|
+
when = el("time", { class: "aparte-score__date", attrs: { datetime: date.toISOString() } });
|
|
1542
|
+
ctx.bind(when, () => dayText(ctx.config, date, now));
|
|
1543
|
+
}
|
|
1544
|
+
return el(
|
|
1545
|
+
"div",
|
|
1546
|
+
{ class: "aparte-score__head" },
|
|
1547
|
+
glyph(SPORT_GLYPHS[match.sport], "aparte-rich-card__glyph aparte-score__sport"),
|
|
1548
|
+
line,
|
|
1549
|
+
when
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
function footOf(ctx, match) {
|
|
1553
|
+
const facts = [
|
|
1554
|
+
match.venue ? el("span", { class: "aparte-score__fact aparte-score__venue" }, glyph(PIN, "aparte-rich-card__glyph aparte-score__fact-glyph"), el("span", { text: match.venue })) : null,
|
|
1555
|
+
match.broadcast ? el("span", { class: "aparte-score__fact aparte-score__broadcast" }, glyph(TV, "aparte-rich-card__glyph aparte-score__fact-glyph"), el("span", { text: match.broadcast })) : null
|
|
1556
|
+
].filter(notNull);
|
|
1557
|
+
let link = null;
|
|
1558
|
+
if (match.url) {
|
|
1559
|
+
const text = el("span");
|
|
1560
|
+
ctx.word(text, "cardsScoreDetails", S.cardsScoreDetails);
|
|
1561
|
+
link = el(
|
|
1562
|
+
"a",
|
|
1563
|
+
{ class: "aparte-score__more", attrs: { href: match.url, target: "_blank", rel: "noopener noreferrer" } },
|
|
1564
|
+
text,
|
|
1565
|
+
glyph(CHEVRON, "aparte-rich-card__glyph aparte-score__chevron")
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
if (!facts.length && !link) return null;
|
|
1569
|
+
return el("div", { class: "aparte-score__foot" }, facts.length ? el("div", { class: "aparte-score__facts" }, ...facts) : null, link);
|
|
1570
|
+
}
|
|
1571
|
+
function boardOf(ctx, match, now) {
|
|
1572
|
+
return el(
|
|
1573
|
+
"div",
|
|
1574
|
+
{ class: "aparte-score__board", attrs: { "data-winner": match.winner } },
|
|
1575
|
+
teamOf(match, "home"),
|
|
1576
|
+
centreOf(ctx, match, now),
|
|
1577
|
+
teamOf(match, "away")
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
function matchRoot(match, className, tag = "article") {
|
|
1581
|
+
const node = el(tag, { class: className, attrs: { "data-phase": phaseOf(match), "data-sport": match.sport } });
|
|
1582
|
+
wear(node, "--aparte-score-home", match.home.color);
|
|
1583
|
+
wear(node, "--aparte-score-away", match.away.color);
|
|
1584
|
+
return node;
|
|
1585
|
+
}
|
|
1586
|
+
function cardOf(ctx, match, now) {
|
|
1587
|
+
const node = matchRoot(match, "aparte-score aparte-score--card");
|
|
1588
|
+
node.append(...[headOf(ctx, match, now), boardOf(ctx, match, now), footOf(ctx, match)].filter(notNull));
|
|
1589
|
+
return node;
|
|
1590
|
+
}
|
|
1591
|
+
function periodsOf(ctx, match) {
|
|
1592
|
+
const periods = match.periods;
|
|
1593
|
+
if (!periods) return null;
|
|
1594
|
+
const tennis = match.sport === "tennis";
|
|
1595
|
+
const caption = el("caption", { class: "aparte-score__sr" });
|
|
1596
|
+
ctx.word(caption, "cardsScorePeriods", S.cardsScorePeriods);
|
|
1597
|
+
const team = el("span", { class: "aparte-score__sr" });
|
|
1598
|
+
ctx.word(team, "cardsScoreTeam", S.cardsScoreTeam);
|
|
1599
|
+
const corner = el("th", { class: "aparte-score__corner", attrs: { scope: "col" } }, team);
|
|
1600
|
+
const total = el("th", { class: "aparte-score__total", attrs: { scope: "col" } });
|
|
1601
|
+
ctx.word(total, tennis ? "cardsScoreSets" : "cardsScoreTotal", tennis ? S.cardsScoreSets : S.cardsScoreTotal);
|
|
1602
|
+
const head = el("tr", {}, corner, ...periods.map((p) => el("th", { attrs: { scope: "col" }, text: p.label })), total);
|
|
1603
|
+
const row = (key) => {
|
|
1604
|
+
const other = key === "home" ? "away" : "home";
|
|
1605
|
+
const team2 = match[key];
|
|
1606
|
+
const cells = periods.map((p) => {
|
|
1607
|
+
const value = p[key];
|
|
1608
|
+
const took = tennis && value !== void 0 && p[other] !== void 0 && value > p[other];
|
|
1609
|
+
const cell = el("td", { attrs: { "data-lead": took ? "win" : void 0 } });
|
|
1610
|
+
if (value !== void 0) ctx.bind(cell, () => formatNumber(ctx.config, value));
|
|
1611
|
+
return cell;
|
|
1612
|
+
});
|
|
1613
|
+
const sum = el("td", { class: "aparte-score__total" });
|
|
1614
|
+
if (team2.score !== void 0) ctx.bind(sum, () => formatNumber(ctx.config, team2.score));
|
|
1615
|
+
return el(
|
|
1616
|
+
"tr",
|
|
1617
|
+
{ attrs: { "data-lead": leadOf(match, key) } },
|
|
1618
|
+
// The cell stays a cell; the crest and the name line up in a box inside it.
|
|
1619
|
+
el(
|
|
1620
|
+
"th",
|
|
1621
|
+
{ class: "aparte-score__row-team", attrs: { scope: "row" } },
|
|
1622
|
+
el("span", { class: "aparte-score__row-label" }, crestOf(team2, "sm"), el("span", { class: "aparte-score__row-name", text: team2.shortName ?? team2.name }))
|
|
1623
|
+
),
|
|
1624
|
+
...cells,
|
|
1625
|
+
sum
|
|
1626
|
+
);
|
|
1627
|
+
};
|
|
1628
|
+
const table = el("table", { class: "aparte-score__periods" }, caption, el("thead", {}, head), el("tbody", {}, row("home"), row("away")));
|
|
1629
|
+
return el("div", { class: "aparte-score__section aparte-score__table-wrap" }, table);
|
|
1630
|
+
}
|
|
1631
|
+
function eventsOf(ctx, match) {
|
|
1632
|
+
const events = match.events;
|
|
1633
|
+
if (!events) return null;
|
|
1634
|
+
const list = el("ol", { class: "aparte-score__events" });
|
|
1635
|
+
ctx.bind(list, () => word(ctx.config, "cardsScoreEvents", S.cardsScoreEvents), "aria-label");
|
|
1636
|
+
for (const event of events) {
|
|
1637
|
+
const team = match[event.team];
|
|
1638
|
+
const type = el("span", { class: "aparte-score__event-type" });
|
|
1639
|
+
ctx.word(type, EVENT_KEYS[event.type], EVENT_WORDS[event.type]);
|
|
1640
|
+
const marker = el("span", { class: "aparte-score__event-team", attrs: { "data-ink": team.color ? inkOn(team.color) : void 0 }, text: team.shortName ?? team.name });
|
|
1641
|
+
wear(marker, "--aparte-score-team", team.color);
|
|
1642
|
+
const body = el(
|
|
1643
|
+
"span",
|
|
1644
|
+
{ class: "aparte-score__event-body" },
|
|
1645
|
+
glyph(EVENT_GLYPHS[event.type], "aparte-rich-card__glyph aparte-score__event-glyph"),
|
|
1646
|
+
el(
|
|
1647
|
+
"span",
|
|
1648
|
+
{ class: "aparte-score__event-text" },
|
|
1649
|
+
event.player ? el("span", { class: "aparte-score__player", text: event.player }) : null,
|
|
1650
|
+
type,
|
|
1651
|
+
event.detail ? el("span", { class: "aparte-score__event-detail", text: event.detail }) : null
|
|
1652
|
+
),
|
|
1653
|
+
marker
|
|
1654
|
+
);
|
|
1655
|
+
list.append(el(
|
|
1656
|
+
"li",
|
|
1657
|
+
{ class: "aparte-score__event", attrs: { "data-team": event.team, "data-type": event.type } },
|
|
1658
|
+
el("span", { class: "aparte-score__minute", text: event.minute ?? "" }),
|
|
1659
|
+
body
|
|
1660
|
+
));
|
|
1661
|
+
}
|
|
1662
|
+
return el("div", { class: "aparte-score__section aparte-score__timeline" }, list);
|
|
1663
|
+
}
|
|
1664
|
+
function detailOf(ctx, match, now) {
|
|
1665
|
+
const node = matchRoot(match, "aparte-score aparte-score--detail");
|
|
1666
|
+
node.append(...[headOf(ctx, match, now), boardOf(ctx, match, now), periodsOf(ctx, match), eventsOf(ctx, match), footOf(ctx, match)].filter(notNull));
|
|
1667
|
+
return node;
|
|
1668
|
+
}
|
|
1669
|
+
function whenOf(ctx, match, now) {
|
|
1670
|
+
const box = el("div", { class: "aparte-score__when" });
|
|
1671
|
+
const phase = phaseOf(match);
|
|
1672
|
+
if (phase === "live") {
|
|
1673
|
+
const said = el("span", { class: "aparte-score__live-word" });
|
|
1674
|
+
ctx.word(said, "cardsScoreLive", S.cardsScoreLive);
|
|
1675
|
+
const clock = clockText(match);
|
|
1676
|
+
box.append(el("span", { class: "aparte-score__live-dot", attrs: { "aria-hidden": "true" } }), clock ? el("span", { class: "aparte-score__sr" }, said) : said);
|
|
1677
|
+
if (clock) box.append(el("span", { class: "aparte-score__clock", text: clock }));
|
|
1678
|
+
} else if (phase === "scheduled" || phase === "none" && !showsScore(match)) {
|
|
1679
|
+
if (match.startTime) box.append(kickoffOf(ctx, match.startTime, now, "aparte-score__kickoff aparte-score__kickoff--row"));
|
|
1680
|
+
else ctx.word(box, "cardsScoreUpcoming", S.cardsScoreUpcoming);
|
|
1681
|
+
} else {
|
|
1682
|
+
const said = statusText(ctx.config, match);
|
|
1683
|
+
if (said !== void 0) ctx.bind(box, () => statusText(ctx.config, match));
|
|
1684
|
+
else if (match.startTime) {
|
|
1685
|
+
const date = match.startTime;
|
|
1686
|
+
ctx.bind(box, () => dayText(ctx.config, date, now));
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
box.setAttribute("data-phase", phase);
|
|
1690
|
+
return box;
|
|
1691
|
+
}
|
|
1692
|
+
function lineOf(ctx, match, key, withScore) {
|
|
1693
|
+
const team = match[key];
|
|
1694
|
+
const lead = leadOf(match, key);
|
|
1695
|
+
return el(
|
|
1696
|
+
"div",
|
|
1697
|
+
{ class: "aparte-score__line", attrs: { "data-lead": lead } },
|
|
1698
|
+
crestOf(team, "sm"),
|
|
1699
|
+
el("span", { class: "aparte-score__line-name", text: team.name }),
|
|
1700
|
+
withScore && team.score !== void 0 ? numberOf(ctx, team.score, "aparte-score__line-score") : null,
|
|
1701
|
+
// The winner is not told by weight alone: a mark points at the score, as the scoreboards do.
|
|
1702
|
+
el("span", { class: "aparte-score__win-mark", attrs: { "aria-hidden": "true" }, text: lead === "win" ? "◂" : "" })
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
function rowOf(ctx, match, now, tag, withCompetition) {
|
|
1706
|
+
const node = matchRoot(match, "aparte-score__row", tag);
|
|
1707
|
+
const scored = showsScore(match);
|
|
1708
|
+
const lines = el(
|
|
1709
|
+
"div",
|
|
1710
|
+
{ class: "aparte-score__lines" },
|
|
1711
|
+
withCompetition && match.competition ? el("span", { class: "aparte-score__row-meta", text: match.competition }) : null,
|
|
1712
|
+
lineOf(ctx, match, "home", scored),
|
|
1713
|
+
lineOf(ctx, match, "away", scored)
|
|
1714
|
+
);
|
|
1715
|
+
node.append(whenOf(ctx, match, now), lines);
|
|
1716
|
+
if (match.url) {
|
|
1717
|
+
const link = el("a", { class: "aparte-score__link", attrs: { href: match.url, target: "_blank", rel: "noopener noreferrer" } });
|
|
1718
|
+
ctx.bind(link, () => matchSentence(ctx.config, match, now), "aria-label");
|
|
1719
|
+
node.setAttribute("data-linked", "");
|
|
1720
|
+
node.append(link);
|
|
1721
|
+
}
|
|
1722
|
+
return node;
|
|
1723
|
+
}
|
|
1724
|
+
function countLabel(ctx, data) {
|
|
1725
|
+
return data.title ?? commonCompetition(data.matches ?? []) ?? word(ctx.config, "cardsScoreCount", S.cardsScoreCount, { n: formatNumber(ctx.config, data.matches?.length ?? 0) });
|
|
1726
|
+
}
|
|
1727
|
+
function commonCompetition(matches) {
|
|
1728
|
+
const first = matches[0]?.competition;
|
|
1729
|
+
return first && matches.every((m) => m.competition === first) ? first : void 0;
|
|
1730
|
+
}
|
|
1731
|
+
function headingOf(ctx, data) {
|
|
1732
|
+
const text = el("span", { class: "aparte-score__heading-text" });
|
|
1733
|
+
ctx.bind(text, () => countLabel(ctx, data));
|
|
1734
|
+
const sports = new Set(data.matches.map((m) => m.sport));
|
|
1735
|
+
const sport = sports.size === 1 ? [...sports][0] : "generic";
|
|
1736
|
+
return el("div", { class: "aparte-score__heading" }, glyph(SPORT_GLYPHS[sport], "aparte-rich-card__glyph aparte-score__sport"), text);
|
|
1737
|
+
}
|
|
1738
|
+
function render(data, ctx, settings) {
|
|
1739
|
+
const now = settings.now();
|
|
1740
|
+
const [first] = data.matches;
|
|
1741
|
+
if (data.matches.length > 1) {
|
|
1742
|
+
const shared = commonCompetition(data.matches) !== void 0 || data.title !== void 0 && data.matches.every((m) => !m.competition);
|
|
1743
|
+
const list = el(
|
|
1744
|
+
"ul",
|
|
1745
|
+
{ class: "aparte-score__list", attrs: { role: "list" } },
|
|
1746
|
+
...data.matches.map((m) => rowOf(ctx, m, now, "li", !shared))
|
|
1747
|
+
);
|
|
1748
|
+
ctx.bind(list, () => countLabel(ctx, data), "aria-label");
|
|
1749
|
+
return [el("div", { class: "aparte-score__board-list" }, headingOf(ctx, data), list)];
|
|
1750
|
+
}
|
|
1751
|
+
if (ctx.variant === "compact") {
|
|
1752
|
+
const head = headOf(ctx, first, now);
|
|
1753
|
+
return [el("div", { class: "aparte-score__single" }, head, rowOf(ctx, first, now, "div", false))];
|
|
1754
|
+
}
|
|
1755
|
+
return [ctx.variant === "detail" ? detailOf(ctx, first, now) : cardOf(ctx, first, now)];
|
|
1756
|
+
}
|
|
1757
|
+
function skeleton(partial2, ctx) {
|
|
1758
|
+
const block = (cls, kind = "rect") => el("span", { class: `aparte-skeleton aparte-skeleton--${kind} ${cls}`, attrs: { "aria-hidden": "true" } });
|
|
1759
|
+
const known = partial2?.matches?.[0];
|
|
1760
|
+
const name = (key, cls) => known?.[key].name ? el("span", { class: cls, text: known[key].name }) : block(`${cls} aparte-score__sk-name`, "text");
|
|
1761
|
+
const head = partial2?.title ? el("div", { class: "aparte-score__heading" }, glyph(TROPHY, "aparte-rich-card__glyph aparte-score__sport"), el("span", { class: "aparte-score__heading-text", text: partial2.title })) : el("div", { class: "aparte-score__head" }, block("aparte-score__sk-meta", "text"));
|
|
1762
|
+
if (ctx.variant === "compact") {
|
|
1763
|
+
const line = (key) => el("div", { class: "aparte-score__line" }, block("aparte-score__crest aparte-score__crest--sm", "circle"), name(key, "aparte-score__line-name"), block("aparte-score__sk-num"));
|
|
1764
|
+
return [el(
|
|
1765
|
+
"div",
|
|
1766
|
+
{ class: "aparte-score__single" },
|
|
1767
|
+
head,
|
|
1768
|
+
el(
|
|
1769
|
+
"div",
|
|
1770
|
+
{ class: "aparte-score__row" },
|
|
1771
|
+
el("div", { class: "aparte-score__when" }, block("aparte-score__sk-when", "text")),
|
|
1772
|
+
el("div", { class: "aparte-score__lines" }, line("home"), line("away"))
|
|
1773
|
+
)
|
|
1774
|
+
)];
|
|
1775
|
+
}
|
|
1776
|
+
const team = (key) => el(
|
|
1777
|
+
"div",
|
|
1778
|
+
{ class: `aparte-score__team aparte-score__team--${key}` },
|
|
1779
|
+
block("aparte-score__crest aparte-score__crest--lg", "circle"),
|
|
1780
|
+
name(key, "aparte-score__team-name")
|
|
1781
|
+
);
|
|
1782
|
+
const parts = [head, el(
|
|
1783
|
+
"div",
|
|
1784
|
+
{ class: "aparte-score__board" },
|
|
1785
|
+
team("home"),
|
|
1786
|
+
el("div", { class: "aparte-score__centre" }, block("aparte-score__sk-score"), block("aparte-score__sk-pill")),
|
|
1787
|
+
team("away")
|
|
1788
|
+
)];
|
|
1789
|
+
if (ctx.variant === "detail") {
|
|
1790
|
+
parts.push(el("div", { class: "aparte-score__section aparte-score__sk-lines" }, ...[0, 1, 2, 3].map(() => block("aparte-score__sk-line", "text"))));
|
|
1791
|
+
}
|
|
1792
|
+
return [el("article", { class: `aparte-score aparte-score--${ctx.variant}` }, ...parts)];
|
|
1793
|
+
}
|
|
1794
|
+
function label(data, ctx) {
|
|
1795
|
+
const matches = data?.matches ?? [];
|
|
1796
|
+
if (matches.length === 1) {
|
|
1797
|
+
const [m] = matches;
|
|
1798
|
+
const names = [m.home.name, m.away.name].filter(Boolean);
|
|
1799
|
+
return names.length === 2 ? versus(ctx.config, m) : names[0] ?? word(ctx.config, "cardsScoreTitle", S.cardsScoreTitle);
|
|
1800
|
+
}
|
|
1801
|
+
if (matches.length > 1 || data?.title) return countLabel(ctx, data);
|
|
1802
|
+
return word(ctx.config, "cardsScoreTitle", S.cardsScoreTitle);
|
|
1803
|
+
}
|
|
1804
|
+
function fallback(data, ctx) {
|
|
1805
|
+
const lines = data.matches.map((m) => matchSentence(ctx.config, m));
|
|
1806
|
+
return data.title ? `${data.title}:
|
|
1807
|
+
${lines.join("\n")}` : lines.join("\n");
|
|
1808
|
+
}
|
|
1809
|
+
function partial(input) {
|
|
1810
|
+
const home = textOf(input["home"] ?? input["homeTeam"] ?? input["home_team"] ?? input["team"] ?? input["teamName"] ?? input["club"]);
|
|
1811
|
+
const away = textOf(input["away"] ?? input["awayTeam"] ?? input["away_team"] ?? input["opponent"]);
|
|
1812
|
+
if (home || away) return { matches: [{ home: { name: home ?? "" }, away: { name: away ?? "" }, sport: sportOf(input["sport"]) ?? "generic" }] };
|
|
1813
|
+
const query = str(input["query"] ?? input["q"] ?? input["search"] ?? input["competition"] ?? input["league"]);
|
|
1814
|
+
return query ? { title: query } : null;
|
|
1815
|
+
}
|
|
1816
|
+
function createScoreCard(settings) {
|
|
1817
|
+
return defineCard({
|
|
1818
|
+
name: "score",
|
|
1819
|
+
variants: ["card", "compact", "detail"],
|
|
1820
|
+
styles: scoreStyles,
|
|
1821
|
+
icon: TROPHY,
|
|
1822
|
+
normalize: readMatches,
|
|
1823
|
+
render: (data, ctx) => render(data, ctx, settings),
|
|
1824
|
+
skeleton,
|
|
1825
|
+
label,
|
|
1826
|
+
fallback,
|
|
1827
|
+
partial
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
const scoreCard = createScoreCard({ now: () => /* @__PURE__ */ new Date() });
|
|
1831
|
+
function setupScoreCard(options = {}) {
|
|
1832
|
+
const { now, ...rest } = options;
|
|
1833
|
+
return createScoreCard({ now: now ?? (() => /* @__PURE__ */ new Date()) }).setup(rest);
|
|
1834
|
+
}
|
|
1835
|
+
export {
|
|
1836
|
+
inkOn,
|
|
1837
|
+
monogram,
|
|
1838
|
+
readMatches,
|
|
1839
|
+
scoreCard,
|
|
1840
|
+
setupScoreCard,
|
|
1841
|
+
teamColor
|
|
1842
|
+
};
|
|
1843
|
+
//# sourceMappingURL=score.js.map
|