@jjlmoya/utils-sports 1.29.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -0
  3. package/src/entries.ts +4 -1
  4. package/src/tests/locale_completeness.test.ts +1 -1
  5. package/src/tests/tool_validation.test.ts +2 -2
  6. package/src/tool/baseballScoreKeeper/baseball-scorekeeper.css +419 -0
  7. package/src/tool/baseballScoreKeeper/bibliography.astro +6 -0
  8. package/src/tool/baseballScoreKeeper/bibliography.ts +10 -0
  9. package/src/tool/baseballScoreKeeper/component.astro +144 -0
  10. package/src/tool/baseballScoreKeeper/entry.ts +30 -0
  11. package/src/tool/baseballScoreKeeper/i18n/de.ts +198 -0
  12. package/src/tool/baseballScoreKeeper/i18n/en.ts +198 -0
  13. package/src/tool/baseballScoreKeeper/i18n/es.ts +198 -0
  14. package/src/tool/baseballScoreKeeper/i18n/fr.ts +198 -0
  15. package/src/tool/baseballScoreKeeper/i18n/id.ts +198 -0
  16. package/src/tool/baseballScoreKeeper/i18n/it.ts +198 -0
  17. package/src/tool/baseballScoreKeeper/i18n/ja.ts +198 -0
  18. package/src/tool/baseballScoreKeeper/i18n/ko.ts +198 -0
  19. package/src/tool/baseballScoreKeeper/i18n/nl.ts +198 -0
  20. package/src/tool/baseballScoreKeeper/i18n/pl.ts +198 -0
  21. package/src/tool/baseballScoreKeeper/i18n/pt.ts +198 -0
  22. package/src/tool/baseballScoreKeeper/i18n/ru.ts +198 -0
  23. package/src/tool/baseballScoreKeeper/i18n/sv.ts +198 -0
  24. package/src/tool/baseballScoreKeeper/i18n/tr.ts +198 -0
  25. package/src/tool/baseballScoreKeeper/i18n/zh.ts +198 -0
  26. package/src/tool/baseballScoreKeeper/index.ts +10 -0
  27. package/src/tool/baseballScoreKeeper/logic.ts +156 -0
  28. package/src/tool/baseballScoreKeeper/seo.astro +15 -0
  29. package/src/tool/baseballScoreKeeper/ui-init.ts +127 -0
  30. package/src/tool/baseballScoreKeeper/ui.ts +31 -0
  31. package/src/tool/footballScoreKeeper/i18n/de.ts +2 -2
  32. package/src/tool/footballScoreKeeper/i18n/tr.ts +2 -2
  33. package/src/tool/padelScoreKeeper/i18n/de.ts +1 -1
  34. package/src/tool/padelScoreKeeper/i18n/en.ts +1 -1
  35. package/src/tool/padelScoreKeeper/i18n/es.ts +1 -1
  36. package/src/tool/padelScoreKeeper/i18n/fr.ts +1 -1
  37. package/src/tool/padelScoreKeeper/i18n/id.ts +1 -1
  38. package/src/tool/padelScoreKeeper/i18n/it.ts +1 -1
  39. package/src/tool/padelScoreKeeper/i18n/nl.ts +1 -1
  40. package/src/tool/padelScoreKeeper/i18n/pt.ts +1 -1
  41. package/src/tool/padelScoreKeeper/i18n/sv.ts +1 -1
  42. package/src/tool/padelScoreKeeper/i18n/tr.ts +1 -1
  43. package/src/tool/rugbyScoreKeeper/i18n/de.ts +1 -1
  44. package/src/tool/rugbyScoreKeeper/i18n/en.ts +1 -1
  45. package/src/tool/rugbyScoreKeeper/i18n/es.ts +1 -1
  46. package/src/tool/rugbyScoreKeeper/i18n/fr.ts +1 -1
  47. package/src/tool/rugbyScoreKeeper/i18n/id.ts +1 -1
  48. package/src/tool/rugbyScoreKeeper/i18n/it.ts +1 -1
  49. package/src/tool/rugbyScoreKeeper/i18n/nl.ts +1 -1
  50. package/src/tool/rugbyScoreKeeper/i18n/pt.ts +1 -1
  51. package/src/tool/rugbyScoreKeeper/i18n/sv.ts +1 -1
  52. package/src/tool/rugbyScoreKeeper/i18n/tr.ts +1 -1
  53. package/src/tool/snookerScoreKeeper/i18n/de.ts +1 -1
  54. package/src/tool/snookerScoreKeeper/i18n/en.ts +1 -1
  55. package/src/tool/snookerScoreKeeper/i18n/es.ts +1 -1
  56. package/src/tool/snookerScoreKeeper/i18n/fr.ts +1 -1
  57. package/src/tool/snookerScoreKeeper/i18n/id.ts +1 -1
  58. package/src/tool/snookerScoreKeeper/i18n/it.ts +1 -1
  59. package/src/tool/snookerScoreKeeper/i18n/nl.ts +1 -1
  60. package/src/tool/snookerScoreKeeper/i18n/pt.ts +1 -1
  61. package/src/tool/snookerScoreKeeper/i18n/sv.ts +1 -1
  62. package/src/tool/snookerScoreKeeper/i18n/tr.ts +1 -1
  63. package/src/tool/streetballScoreKeeper/i18n/de.ts +1 -1
  64. package/src/tool/streetballScoreKeeper/i18n/en.ts +1 -1
  65. package/src/tool/streetballScoreKeeper/i18n/es.ts +1 -1
  66. package/src/tool/streetballScoreKeeper/i18n/fr.ts +1 -1
  67. package/src/tool/streetballScoreKeeper/i18n/id.ts +1 -1
  68. package/src/tool/streetballScoreKeeper/i18n/it.ts +1 -1
  69. package/src/tool/streetballScoreKeeper/i18n/nl.ts +1 -1
  70. package/src/tool/streetballScoreKeeper/i18n/pt.ts +1 -1
  71. package/src/tool/streetballScoreKeeper/i18n/sv.ts +1 -1
  72. package/src/tool/streetballScoreKeeper/i18n/tr.ts +1 -1
  73. package/src/tool/tournamentBracket/i18n/de.ts +1 -1
  74. package/src/tool/tournamentBracket/i18n/tr.ts +1 -1
  75. package/src/tools.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-sports",
3
- "version": "1.29.0",
3
+ "version": "1.31.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -7,6 +7,7 @@ import { gymTracker } from '../tool/gymTracker/index';
7
7
  import { reactionTester } from '../tool/reactionTester/index';
8
8
  import { pingPongScoreKeeper } from '../tool/pingPongScoreKeeper/index';
9
9
  import { rugbyScoreKeeper } from '../tool/rugbyScoreKeeper/index';
10
+ import { baseballScoreKeeper } from '../tool/baseballScoreKeeper/index';
10
11
 
11
12
  export const sportsCategory: SportsCategoryEntry = {
12
13
  icon: 'mdi:soccer',
@@ -19,6 +20,7 @@ export const sportsCategory: SportsCategoryEntry = {
19
20
  reactionTester,
20
21
  pingPongScoreKeeper,
21
22
  rugbyScoreKeeper,
23
+ baseballScoreKeeper,
22
24
  ] as unknown as SportsToolEntry<Record<string, string>>[],
23
25
  i18n: {
24
26
  es: () => import('./i18n/es').then((m) => m.content),
package/src/entries.ts CHANGED
@@ -26,6 +26,8 @@ export { snookerScoreKeeper } from './tool/snookerScoreKeeper/entry';
26
26
  export type { SnookerScoreKeeperLocaleContent } from './tool/snookerScoreKeeper/entry';
27
27
  export { rugbyScoreKeeper } from './tool/rugbyScoreKeeper/entry';
28
28
  export type { RugbyScoreKeeperLocaleContent } from './tool/rugbyScoreKeeper/entry';
29
+ export { baseballScoreKeeper } from './tool/baseballScoreKeeper/entry';
30
+ export type { BaseballScoreKeeperLocaleContent } from './tool/baseballScoreKeeper/entry';
29
31
  export { sportsCategory } from './category';
30
32
  import { basketScoreKeeper } from './tool/basketScoreKeeper/entry';
31
33
  import { footballScoreKeeper } from './tool/footballScoreKeeper/entry';
@@ -41,5 +43,6 @@ import { streetballScoreKeeper } from './tool/streetballScoreKeeper/entry';
41
43
  import { beachVolleyballScoreKeeper } from './tool/beachVolleyballScoreKeeper/entry';
42
44
  import { snookerScoreKeeper } from './tool/snookerScoreKeeper/entry';
43
45
  import { rugbyScoreKeeper } from './tool/rugbyScoreKeeper/entry';
44
- export const ALL_ENTRIES = [basketScoreKeeper, footballScoreKeeper, gymTracker, pingPongScoreKeeper, reactionTester, scoreKeeper, tournamentBracket, tennisScoreKeeper, dartsScoreKeeper, padelScoreKeeper, streetballScoreKeeper, beachVolleyballScoreKeeper, snookerScoreKeeper, rugbyScoreKeeper];
46
+ import { baseballScoreKeeper } from './tool/baseballScoreKeeper/entry';
47
+ export const ALL_ENTRIES = [basketScoreKeeper, footballScoreKeeper, gymTracker, pingPongScoreKeeper, reactionTester, scoreKeeper, tournamentBracket, tennisScoreKeeper, dartsScoreKeeper, padelScoreKeeper, streetballScoreKeeper, beachVolleyballScoreKeeper, snookerScoreKeeper, rugbyScoreKeeper, baseballScoreKeeper];
45
48
 
@@ -3,6 +3,6 @@ import { ALL_TOOLS } from '../tools';
3
3
 
4
4
  describe('Locale Completeness Validation', () => {
5
5
  it('all tools registered', () => {
6
- expect(ALL_TOOLS.length).toBe(14);
6
+ expect(ALL_TOOLS.length).toBe(15);
7
7
  });
8
8
  });
@@ -4,8 +4,8 @@ import { sportsCategory } from '../data';
4
4
 
5
5
  describe('Tool Validation Suite', () => {
6
6
  describe('Library Registration', () => {
7
- it('should have 14 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(14);
7
+ it('should have 15 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(15);
9
9
  });
10
10
 
11
11
  it('sportsCategory should be defined', () => {
@@ -0,0 +1,419 @@
1
+ .bb-app {
2
+ --bb-bg-page: var(--bg-page);
3
+ --bb-bg-surface: var(--bg-surface);
4
+ --bb-bg-muted: var(--bg-muted);
5
+ --bb-border: var(--border-base);
6
+ --bb-text: var(--text-base);
7
+ --bb-text-dim: var(--text-muted);
8
+ --bb-clay: #c49a6c;
9
+ --bb-grass: #5a8f4a;
10
+ --bb-grass-bg: rgba(90, 143, 74, 0.12);
11
+ --bb-gold: #e3b341;
12
+ --bb-danger: #da3633;
13
+ --bb-strike: #da3633;
14
+ --bb-ball: #e3b341;
15
+ --bb-out: #636363;
16
+
17
+ background: var(--bb-bg-page);
18
+ color: var(--bb-text);
19
+ max-width: 780px;
20
+ margin: 0 auto;
21
+ padding: 16px;
22
+ position: relative;
23
+ overflow: hidden;
24
+ }
25
+
26
+ .bb-main-card {
27
+ background: var(--bb-bg-surface);
28
+ border: 1px solid var(--bb-border);
29
+ border-radius: 14px;
30
+ padding: 16px;
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: 14px;
34
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
35
+ }
36
+
37
+ .bb-strip {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: space-between;
41
+ background: var(--bb-bg-muted);
42
+ border: 1px solid var(--bb-border);
43
+ border-radius: 12px;
44
+ padding: 12px 20px;
45
+ }
46
+
47
+ .bb-team {
48
+ text-align: center;
49
+ flex: 1;
50
+ }
51
+
52
+ .bb-name {
53
+ background: transparent;
54
+ border: none;
55
+ border-bottom: 2px solid var(--bb-border);
56
+ color: var(--bb-text);
57
+ font-size: 1rem;
58
+ text-align: center;
59
+ padding: 4px 8px;
60
+ outline: none;
61
+ width: 100%;
62
+ max-width: 130px;
63
+ }
64
+
65
+ .bb-name:focus {
66
+ border-color: var(--bb-gold);
67
+ }
68
+
69
+ .bb-score {
70
+ font-size: 2.8rem;
71
+ font-weight: 800;
72
+ color: var(--bb-gold);
73
+ line-height: 1;
74
+ margin-top: 4px;
75
+ }
76
+
77
+ .bb-divider {
78
+ text-align: center;
79
+ padding: 0 12px;
80
+ }
81
+
82
+ .bb-inning-badge {
83
+ font-size: 1rem;
84
+ font-weight: 700;
85
+ background: var(--bb-border);
86
+ color: var(--bb-text);
87
+ padding: 4px 14px;
88
+ border-radius: 6px;
89
+ }
90
+
91
+ .bb-diamond-wrap {
92
+ display: flex;
93
+ justify-content: center;
94
+ align-items: center;
95
+ background: var(--bb-bg-muted);
96
+ border: 1px solid var(--bb-border);
97
+ border-radius: 12px;
98
+ padding: 12px;
99
+ }
100
+
101
+ .bb-diamond-svg {
102
+ width: 100%;
103
+ max-width: 280px;
104
+ height: auto;
105
+ }
106
+
107
+ .bb-diamond-bg {
108
+ fill: var(--bb-grass);
109
+ stroke: var(--bb-clay);
110
+ stroke-width: 2;
111
+ }
112
+
113
+ .bb-base {
114
+ fill: var(--bb-clay);
115
+ stroke: var(--bb-border);
116
+ stroke-width: 2;
117
+ cursor: pointer;
118
+ transition: all 0.15s;
119
+ }
120
+
121
+ .bb-base:hover {
122
+ filter: brightness(1.15);
123
+ }
124
+
125
+ .bb-base-active {
126
+ fill: var(--bb-gold);
127
+ stroke: #d49a20;
128
+ filter: drop-shadow(0 0 10px rgba(227, 179, 65, 0.6));
129
+ }
130
+
131
+ .bb-base-label {
132
+ font-size: 11px;
133
+ font-weight: 800;
134
+ fill: var(--bb-text);
135
+ text-anchor: middle;
136
+ dominant-baseline: central;
137
+ pointer-events: none;
138
+ }
139
+
140
+ .bb-home-plate {
141
+ fill: var(--bb-clay);
142
+ stroke: var(--bb-border);
143
+ stroke-width: 2;
144
+ }
145
+
146
+ .bb-count-row {
147
+ display: flex;
148
+ justify-content: center;
149
+ gap: 32px;
150
+ background: var(--bb-bg-muted);
151
+ border: 1px solid var(--bb-border);
152
+ border-radius: 12px;
153
+ padding: 10px 16px;
154
+ }
155
+
156
+ .bb-count-item {
157
+ display: flex;
158
+ flex-direction: column;
159
+ align-items: center;
160
+ gap: 4px;
161
+ }
162
+
163
+ .bb-count-label {
164
+ font-size: 0.7rem;
165
+ font-weight: 700;
166
+ color: var(--bb-text-dim);
167
+ text-transform: uppercase;
168
+ letter-spacing: 0.05em;
169
+ }
170
+
171
+ .bb-dots {
172
+ display: flex;
173
+ gap: 6px;
174
+ }
175
+
176
+ .bb-dot {
177
+ width: 18px;
178
+ height: 18px;
179
+ border-radius: 50%;
180
+ border: 2px solid var(--bb-border);
181
+ background: transparent;
182
+ transition: all 0.2s;
183
+ }
184
+
185
+ .bb-rhe-wrap {
186
+ background: var(--bb-bg-muted);
187
+ border: 1px solid var(--bb-border);
188
+ border-radius: 12px;
189
+ padding: 10px 14px;
190
+ }
191
+
192
+ .bb-rhe-table {
193
+ width: 100%;
194
+ border-collapse: collapse;
195
+ font-size: 0.9rem;
196
+ }
197
+
198
+ .bb-rhe-table th {
199
+ text-align: center;
200
+ padding: 6px 10px;
201
+ border-bottom: 1px solid var(--bb-border);
202
+ color: var(--bb-text-dim);
203
+ font-weight: 700;
204
+ font-size: 0.75rem;
205
+ }
206
+
207
+ .bb-rhe-table td {
208
+ text-align: center;
209
+ padding: 6px 10px;
210
+ border-bottom: 1px solid var(--bb-border);
211
+ font-weight: 700;
212
+ font-size: 1.1rem;
213
+ }
214
+
215
+ .bb-rhe-team {
216
+ font-weight: 800;
217
+ text-align: left;
218
+ font-size: 0.9rem;
219
+ }
220
+
221
+ .bb-th-runs {
222
+ color: var(--bb-gold);
223
+ }
224
+
225
+ .bb-th-hits {
226
+ color: var(--bb-grass);
227
+ }
228
+
229
+ .bb-th-errors {
230
+ color: var(--bb-strike);
231
+ }
232
+
233
+ .bb-inning-scroll {
234
+ background: var(--bb-bg-muted);
235
+ border: 1px solid var(--bb-border);
236
+ border-radius: 12px;
237
+ padding: 8px 12px;
238
+ overflow-x: auto;
239
+ }
240
+
241
+ .bb-inning-header {
242
+ display: flex;
243
+ gap: 4px;
244
+ padding-bottom: 4px;
245
+ border-bottom: 1px solid var(--bb-border);
246
+ margin-bottom: 4px;
247
+ }
248
+
249
+ .bb-ih-team {
250
+ width: 44px;
251
+ flex-shrink: 0;
252
+ }
253
+
254
+ .bb-ih-cell {
255
+ width: 32px;
256
+ text-align: center;
257
+ font-size: 0.75rem;
258
+ font-weight: 700;
259
+ color: var(--bb-text-dim);
260
+ flex-shrink: 0;
261
+ }
262
+
263
+ .bb-inning-row {
264
+ display: flex;
265
+ gap: 4px;
266
+ align-items: center;
267
+ padding: 3px 0;
268
+ }
269
+
270
+ .bb-ir-team {
271
+ width: 44px;
272
+ font-size: 0.8rem;
273
+ font-weight: 700;
274
+ flex-shrink: 0;
275
+ }
276
+
277
+ .bb-inning-cell {
278
+ width: 32px;
279
+ text-align: center;
280
+ font-size: 0.85rem;
281
+ font-weight: 600;
282
+ padding: 2px 0;
283
+ flex-shrink: 0;
284
+ }
285
+
286
+ .bb-btn-row {
287
+ display: flex;
288
+ gap: 6px;
289
+ }
290
+
291
+ .bb-btn {
292
+ flex: 1;
293
+ padding: 12px 8px;
294
+ border: 1px solid var(--bb-border);
295
+ border-radius: 10px;
296
+ background: var(--bb-bg-surface);
297
+ color: var(--bb-text);
298
+ font-size: 0.85rem;
299
+ font-weight: 700;
300
+ cursor: pointer;
301
+ user-select: none;
302
+ text-align: center;
303
+ transition: transform 0.1s;
304
+ }
305
+
306
+ .bb-btn:hover {
307
+ transform: scale(1.04);
308
+ }
309
+
310
+ .bb-btn:active {
311
+ transform: scale(0.95);
312
+ }
313
+
314
+ .bb-btn-strike {
315
+ background: var(--bb-strike);
316
+ border-color: var(--bb-strike);
317
+ color: var(--text-on-accent);
318
+ }
319
+
320
+ .bb-btn-ball {
321
+ background: var(--bb-ball);
322
+ border-color: var(--bb-ball);
323
+ color: #0d1117;
324
+ }
325
+
326
+ .bb-btn-foul {
327
+ background: var(--bb-bg-surface);
328
+ border-color: var(--bb-border);
329
+ }
330
+
331
+ .bb-btn-hit {
332
+ background: var(--bb-grass);
333
+ border-color: var(--bb-grass);
334
+ color: var(--text-on-accent);
335
+ }
336
+
337
+ .bb-btn-out {
338
+ background: var(--bb-out);
339
+ border-color: var(--bb-out);
340
+ color: var(--text-on-accent);
341
+ }
342
+
343
+ .bb-btn-row-secondary {
344
+ margin-top: -8px;
345
+ }
346
+
347
+ .bb-btn-run {
348
+ background: var(--bb-gold);
349
+ border-color: var(--bb-gold);
350
+ color: #0d1117;
351
+ }
352
+
353
+ .bb-btn-error {
354
+ background: var(--bb-bg-surface);
355
+ border-color: var(--bb-strike);
356
+ color: var(--bb-strike);
357
+ }
358
+
359
+ .bb-btn-reset {
360
+ background: var(--bb-danger);
361
+ color: var(--text-on-accent);
362
+ padding: 12px 20px;
363
+ font-size: 0.9rem;
364
+ border-radius: 10px;
365
+ border: none;
366
+ cursor: pointer;
367
+ font-weight: 700;
368
+ }
369
+
370
+ .bb-reset-modal {
371
+ display: none;
372
+ position: fixed;
373
+ inset: 0;
374
+ background: rgba(0, 0, 0, 0.4);
375
+ align-items: center;
376
+ justify-content: center;
377
+ z-index: 200;
378
+ }
379
+
380
+ .bb-modal-content {
381
+ background: var(--bb-bg-surface);
382
+ border: 1px solid var(--bb-border);
383
+ border-radius: 12px;
384
+ padding: 24px;
385
+ max-width: 300px;
386
+ text-align: center;
387
+ }
388
+
389
+ .bb-modal-text {
390
+ margin-bottom: 18px;
391
+ font-size: 1rem;
392
+ line-height: 1.4;
393
+ }
394
+
395
+ .bb-modal-btns {
396
+ display: flex;
397
+ gap: 10px;
398
+ justify-content: center;
399
+ }
400
+
401
+ .bb-btn-modal-cancel {
402
+ background: var(--bb-bg-muted);
403
+ color: var(--bb-text);
404
+ border: none;
405
+ padding: 10px 20px;
406
+ border-radius: 8px;
407
+ font-weight: 600;
408
+ cursor: pointer;
409
+ }
410
+
411
+ .bb-btn-modal-confirm {
412
+ background: var(--bb-danger);
413
+ color: var(--text-on-accent);
414
+ border: none;
415
+ padding: 10px 20px;
416
+ border-radius: 8px;
417
+ font-weight: 600;
418
+ cursor: pointer;
419
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { bibliography } from './bibliography';
4
+ ---
5
+
6
+ <SharedBibliography links={bibliography} />
@@ -0,0 +1,10 @@
1
+ export const bibliography = [
2
+ {
3
+ name: 'Major League Baseball Official Rules',
4
+ url: 'https://img.mlbstatic.com/mlb-images/image/upload/mlb/atcjzj9j7wrgvsm8wnjq.pdf',
5
+ },
6
+ {
7
+ name: 'World Baseball Softball Confederation Rules',
8
+ url: 'https://www.wbsc.org/en/organisation/baseball/game-rules',
9
+ },
10
+ ];
@@ -0,0 +1,144 @@
1
+ ---
2
+ import type { KnownLocale } from '../../types';
3
+ import type { BaseballScoreKeeperUI } from './ui';
4
+
5
+ interface Props {
6
+ locale?: KnownLocale;
7
+ ui?: Record<string, unknown>;
8
+ }
9
+
10
+ const { ui } = Astro.props;
11
+ const t = (ui ?? {}) as BaseballScoreKeeperUI;
12
+ ---
13
+
14
+ <div class="bb-app" id="bb-app" data-bb-ui={JSON.stringify(t)}>
15
+
16
+ <div class="bb-main-card">
17
+
18
+ <div class="bb-strip">
19
+ <div class="bb-team">
20
+ <input type="text" class="bb-name" id="bb-name-away" value={t.away} />
21
+ <div class="bb-score" id="bb-score-away">0</div>
22
+ </div>
23
+ <div class="bb-divider">
24
+ <span class="bb-inning-badge" id="bb-inning-label">Top 1</span>
25
+ </div>
26
+ <div class="bb-team">
27
+ <input type="text" class="bb-name" id="bb-name-home" value={t.home} />
28
+ <div class="bb-score" id="bb-score-home">0</div>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="bb-diamond-wrap">
33
+ <svg class="bb-diamond-svg" viewBox="0 0 240 240">
34
+ <polygon class="bb-diamond-bg" points="120,12 228,120 120,228 12,120" />
35
+ <circle class="bb-base" id="bb-base-first" cx="190" cy="155" r="24" />
36
+ <circle class="bb-base" id="bb-base-second" cx="120" cy="50" r="24" />
37
+ <circle class="bb-base" id="bb-base-third" cx="50" cy="155" r="24" />
38
+ <text class="bb-base-label" x="190" y="161">1B</text>
39
+ <text class="bb-base-label" x="120" y="56">2B</text>
40
+ <text class="bb-base-label" x="50" y="161">3B</text>
41
+ <path class="bb-home-plate" d="M 112 212 L 128 212 L 128 224 L 120 230 L 112 224 Z" />
42
+ </svg>
43
+ </div>
44
+
45
+ <div class="bb-count-row">
46
+ <div class="bb-count-item">
47
+ <span class="bb-count-label">{t.balls}</span>
48
+ <div class="bb-dots" id="bb-dots-balls">
49
+ <span class="bb-dot"></span><span class="bb-dot"></span><span class="bb-dot"></span><span class="bb-dot"></span>
50
+ </div>
51
+ </div>
52
+ <div class="bb-count-item">
53
+ <span class="bb-count-label">{t.strikes}</span>
54
+ <div class="bb-dots" id="bb-dots-strikes">
55
+ <span class="bb-dot"></span><span class="bb-dot"></span><span class="bb-dot"></span>
56
+ </div>
57
+ </div>
58
+ <div class="bb-count-item">
59
+ <span class="bb-count-label">{t.outs}</span>
60
+ <div class="bb-dots" id="bb-dots-outs">
61
+ <span class="bb-dot bb-dot-out"></span><span class="bb-dot bb-dot-out"></span><span class="bb-dot bb-dot-out"></span>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="bb-rhe-wrap">
67
+ <table class="bb-rhe-table">
68
+ <thead>
69
+ <tr>
70
+ <th></th>
71
+ <th class="bb-th-runs">{t.runs}</th>
72
+ <th class="bb-th-hits">{t.hits}</th>
73
+ <th class="bb-th-errors">{t.errors}</th>
74
+ </tr>
75
+ </thead>
76
+ <tbody>
77
+ <tr>
78
+ <td class="bb-rhe-team" id="bb-rhe-away-label">{t.away}</td>
79
+ <td class="bb-rhe-val" id="bb-rhe-away-r">0</td>
80
+ <td class="bb-rhe-val" id="bb-rhe-away-h">0</td>
81
+ <td class="bb-rhe-val" id="bb-rhe-away-e">0</td>
82
+ </tr>
83
+ <tr>
84
+ <td class="bb-rhe-team" id="bb-rhe-home-label">{t.home}</td>
85
+ <td class="bb-rhe-val" id="bb-rhe-home-r">0</td>
86
+ <td class="bb-rhe-val" id="bb-rhe-home-h">0</td>
87
+ <td class="bb-rhe-val" id="bb-rhe-home-e">0</td>
88
+ </tr>
89
+ </tbody>
90
+ </table>
91
+ </div>
92
+
93
+ <div class="bb-inning-scroll" id="bb-inning-scroll">
94
+ <div class="bb-inning-header">
95
+ <span class="bb-ih-team"></span>
96
+ <span class="bb-ih-cell">1</span>
97
+ <span class="bb-ih-cell">2</span>
98
+ <span class="bb-ih-cell">3</span>
99
+ <span class="bb-ih-cell">4</span>
100
+ <span class="bb-ih-cell">5</span>
101
+ <span class="bb-ih-cell">6</span>
102
+ <span class="bb-ih-cell">7</span>
103
+ <span class="bb-ih-cell">8</span>
104
+ <span class="bb-ih-cell">9</span>
105
+ </div>
106
+ <div class="bb-inning-row" id="bb-row-away">
107
+ <span class="bb-ir-team" id="bb-ir-away-label">{t.away}</span>
108
+ </div>
109
+ <div class="bb-inning-row" id="bb-row-home">
110
+ <span class="bb-ir-team" id="bb-ir-home-label">{t.home}</span>
111
+ </div>
112
+ </div>
113
+
114
+ <div class="bb-btn-row">
115
+ <button class="bb-btn bb-btn-strike" id="bb-btn-strike">{t.strikeBtn}</button>
116
+ <button class="bb-btn bb-btn-ball" id="bb-btn-ball">{t.ballBtn}</button>
117
+ <button class="bb-btn bb-btn-foul" id="bb-btn-foul">{t.foulBtn}</button>
118
+ <button class="bb-btn bb-btn-hit" id="bb-btn-hit">{t.hitBtn}</button>
119
+ <button class="bb-btn bb-btn-out" id="bb-btn-out">{t.outBtn}</button>
120
+ </div>
121
+ <div class="bb-btn-row bb-btn-row-secondary">
122
+ <button class="bb-btn bb-btn-run" id="bb-btn-run">{t.runBtn}</button>
123
+ <button class="bb-btn bb-btn-error" id="bb-btn-error">{t.errorBtn}</button>
124
+ </div>
125
+
126
+ <button class="bb-btn bb-btn-reset" id="bb-btn-reset">{t.resetMatch}</button>
127
+
128
+ </div>
129
+
130
+ <div class="bb-reset-modal" id="bb-modal">
131
+ <div class="bb-modal-content">
132
+ <div class="bb-modal-text">{t.resetConfirm}</div>
133
+ <div class="bb-modal-btns">
134
+ <button class="bb-btn bb-btn-modal-cancel" id="bb-modal-cancel">{t.cancel}</button>
135
+ <button class="bb-btn bb-btn-modal-confirm" id="bb-modal-confirm">{t.confirm}</button>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <script>
142
+ import { initBaseballScorekeeper } from './ui-init';
143
+ initBaseballScorekeeper();
144
+ </script>
@@ -0,0 +1,30 @@
1
+ import type { SportsToolEntry, ToolLocaleContent } from '../../types';
2
+ import type { BaseballScoreKeeperUI } from './ui';
3
+
4
+ export type { BaseballScoreKeeperUI };
5
+ export type BaseballScoreKeeperLocaleContent = ToolLocaleContent<BaseballScoreKeeperUI>;
6
+
7
+ export const baseballScoreKeeper: SportsToolEntry<BaseballScoreKeeperUI> = {
8
+ id: 'baseball-scorekeeper',
9
+ icons: {
10
+ bg: 'mdi:baseball',
11
+ fg: 'mdi:scoreboard-outline',
12
+ },
13
+ i18n: {
14
+ en: () => import('./i18n/en').then((m) => m.content),
15
+ es: () => import('./i18n/es').then((m) => m.content),
16
+ fr: () => import('./i18n/fr').then((m) => m.content),
17
+ de: () => import('./i18n/de').then((m) => m.content),
18
+ it: () => import('./i18n/it').then((m) => m.content),
19
+ nl: () => import('./i18n/nl').then((m) => m.content),
20
+ pt: () => import('./i18n/pt').then((m) => m.content),
21
+ id: () => import('./i18n/id').then((m) => m.content),
22
+ pl: () => import('./i18n/pl').then((m) => m.content),
23
+ sv: () => import('./i18n/sv').then((m) => m.content),
24
+ tr: () => import('./i18n/tr').then((m) => m.content),
25
+ ja: () => import('./i18n/ja').then((m) => m.content),
26
+ ko: () => import('./i18n/ko').then((m) => m.content),
27
+ ru: () => import('./i18n/ru').then((m) => m.content),
28
+ zh: () => import('./i18n/zh').then((m) => m.content),
29
+ },
30
+ };