@jjlmoya/utils-sports 1.1.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 (79) hide show
  1. package/package.json +62 -0
  2. package/src/category/i18n/en.ts +108 -0
  3. package/src/category/i18n/es.ts +108 -0
  4. package/src/category/i18n/fr.ts +95 -0
  5. package/src/category/index.ts +21 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +55 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/gymTracker/bibliography.astro +15 -0
  25. package/src/tool/gymTracker/component.astro +835 -0
  26. package/src/tool/gymTracker/exercises.ts +28 -0
  27. package/src/tool/gymTracker/i18n/en.ts +225 -0
  28. package/src/tool/gymTracker/i18n/es.ts +225 -0
  29. package/src/tool/gymTracker/i18n/fr.ts +225 -0
  30. package/src/tool/gymTracker/index.ts +34 -0
  31. package/src/tool/gymTracker/logic.ts +169 -0
  32. package/src/tool/gymTracker/seo.astro +15 -0
  33. package/src/tool/gymTracker/storage.ts +43 -0
  34. package/src/tool/gymTracker/timer.ts +126 -0
  35. package/src/tool/gymTracker/types.ts +11 -0
  36. package/src/tool/gymTracker/ui-utils.ts +59 -0
  37. package/src/tool/gymTracker/ui.ts +27 -0
  38. package/src/tool/reactionTester/bibliography.astro +2 -0
  39. package/src/tool/reactionTester/component.astro +1074 -0
  40. package/src/tool/reactionTester/i18n/en.ts +144 -0
  41. package/src/tool/reactionTester/i18n/es.ts +144 -0
  42. package/src/tool/reactionTester/i18n/fr.ts +144 -0
  43. package/src/tool/reactionTester/index.ts +34 -0
  44. package/src/tool/reactionTester/seo.astro +12 -0
  45. package/src/tool/reactionTester/ui.ts +43 -0
  46. package/src/tool/scoreKeeper/bibliography.astro +14 -0
  47. package/src/tool/scoreKeeper/component.astro +858 -0
  48. package/src/tool/scoreKeeper/i18n/en.ts +207 -0
  49. package/src/tool/scoreKeeper/i18n/es.ts +207 -0
  50. package/src/tool/scoreKeeper/i18n/fr.ts +207 -0
  51. package/src/tool/scoreKeeper/index.ts +35 -0
  52. package/src/tool/scoreKeeper/logic.ts +275 -0
  53. package/src/tool/scoreKeeper/seo.astro +15 -0
  54. package/src/tool/scoreKeeper/sports.ts +70 -0
  55. package/src/tool/scoreKeeper/ui.ts +19 -0
  56. package/src/tool/tournamentBracket/bibliography.astro +10 -0
  57. package/src/tool/tournamentBracket/component.astro +1092 -0
  58. package/src/tool/tournamentBracket/i18n/en.ts +160 -0
  59. package/src/tool/tournamentBracket/i18n/es.ts +178 -0
  60. package/src/tool/tournamentBracket/i18n/fr.ts +160 -0
  61. package/src/tool/tournamentBracket/index.ts +34 -0
  62. package/src/tool/tournamentBracket/logic/active.controller.ts +106 -0
  63. package/src/tool/tournamentBracket/logic/generator.ts +71 -0
  64. package/src/tool/tournamentBracket/logic/manager.ts +165 -0
  65. package/src/tool/tournamentBracket/logic/setup.controller.ts +84 -0
  66. package/src/tool/tournamentBracket/logic/sharing.ts +81 -0
  67. package/src/tool/tournamentBracket/logic/storage.ts +56 -0
  68. package/src/tool/tournamentBracket/models.ts +34 -0
  69. package/src/tool/tournamentBracket/seo.astro +12 -0
  70. package/src/tool/tournamentBracket/tournament.controller.ts +65 -0
  71. package/src/tool/tournamentBracket/tournament.renderer.ts +45 -0
  72. package/src/tool/tournamentBracket/ui/bracket-desktop.ts +143 -0
  73. package/src/tool/tournamentBracket/ui/bracket-mobile.ts +82 -0
  74. package/src/tool/tournamentBracket/ui/mediator.ts +96 -0
  75. package/src/tool/tournamentBracket/ui/navigator.ts +84 -0
  76. package/src/tool/tournamentBracket/ui/setup.ts +120 -0
  77. package/src/tool/tournamentBracket/ui.ts +42 -0
  78. package/src/tools.ts +13 -0
  79. package/src/types.ts +72 -0
@@ -0,0 +1,835 @@
1
+ ---
2
+ import type { KnownLocale } from '../../types';
3
+ import type { GymTrackerUI } from './ui';
4
+ import { defaultExercises } from './exercises';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ ui?: Record<string, unknown>;
9
+ }
10
+
11
+ const { ui } = Astro.props;
12
+ const t = (ui ?? {}) as GymTrackerUI & Record<string, string>;
13
+ ---
14
+
15
+ <div class="gt-root" id="gym-tracker-app" data-gt-ui={JSON.stringify(t)}>
16
+ <div class="gt-card gt-animate-in">
17
+ <div class="gt-header">
18
+ <div class="gt-header-row">
19
+ <div class="gt-field">
20
+ <label for="exerciseSelect">
21
+ <svg viewBox="0 0 24 24" class="gt-icon-label"><path fill="currentColor" d="M21 12c.56 0 1.08.15 1.53.42c.3-.44.47-.96.47-1.53c0-1.63-1.33-2.95-2.95-2.95c-.64 0-1.24.21-1.7.55c-.31-.56-.91-.94-1.6-.94c-.58 0-1.1.27-1.44.7c-.36-.43-.9-.7-1.51-.7a2.38 2.38 0 0 0-2.38 2.38c0 .28.05.54.14.79c-.4.29-.66.77-.66 1.3c0 .18.03.36.09.53c-.32.41-.5.93-.5 1.5c0 1.34.89 2.47 2.11 2.83c.33 1.14 1.38 1.97 2.62 1.97a2.73 2.73 0 0 0 2.72-2.37c.45.24.96.37 1.5.37c1.38 0 2.54-.92 2.89-2.18c.2-.07.4-.16.58-.28c.11.45.28.87.52 1.25V12z"/></svg>
22
+ {t.exerciseLabel}
23
+ </label>
24
+ <div class="gt-select-box">
25
+ <select id="exerciseSelect" class="gt-select">
26
+ <optgroup label={t.pushCategory}>
27
+ {defaultExercises.filter(ex => ex.categoryKey === 'push').map(ex => (
28
+ <option value={ex.id}>{t[ex.nameKey]}</option>
29
+ ))}
30
+ </optgroup>
31
+ <optgroup label={t.pullCategory}>
32
+ {defaultExercises.filter(ex => ex.categoryKey === 'pull').map(ex => (
33
+ <option value={ex.id}>{t[ex.nameKey]}</option>
34
+ ))}
35
+ </optgroup>
36
+ <optgroup label={t.gluteCategory}>
37
+ {defaultExercises.filter(ex => ex.categoryKey === 'glute').map(ex => (
38
+ <option value={ex.id}>{t[ex.nameKey]}</option>
39
+ ))}
40
+ </optgroup>
41
+ </select>
42
+ </div>
43
+ </div>
44
+ <button id="toggleCustomExerciseBtn" class="gt-btn-toggle" title={t.addCustomExerciseTitle}>
45
+ <svg viewBox="0 0 24 24" class="gt-icon-md"><path fill="currentColor" d="M17 13h-4v4h-2v-4H7v-2h4V7h2v4h4m2-7H5c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"/></svg>
46
+ </button>
47
+ </div>
48
+
49
+ <div id="customExerciseForm" class="gt-custom-form gt-hidden">
50
+ <label for="customExerciseInput" class="gt-label-small">
51
+ {t.newExerciseLabel}
52
+ </label>
53
+ <div class="gt-custom-row">
54
+ <input type="text" id="customExerciseInput" placeholder={t.exercisePlaceholder} maxlength="40" class="gt-input-text" />
55
+ <button id="addCustomExerciseBtn" class="gt-btn-secondary">{t.addBtn}</button>
56
+ <button id="closeCustomExerciseBtn" class="gt-btn-icon">x</button>
57
+ </div>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="gt-log-section">
62
+ <label for="weightInput" class="gt-label-main">
63
+ <svg viewBox="0 0 24 24" class="gt-icon-sm"><path fill="currentColor" d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
64
+ {t.registerWeightLabel}
65
+ </label>
66
+ <div class="gt-log-row">
67
+ <input type="number" id="weightInput" placeholder={t.weightPlaceholder} step="0.5" min="0" inputmode="decimal" class="gt-input-number" />
68
+ <button id="addLogBtn" class="gt-btn-primary">{t.addBtn}</button>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="gt-timer-section">
73
+ <div class="gt-timer-container">
74
+ <div class="gt-timer-main">
75
+ <span id="timerDisplay" class="gt-timer-text">00:00</span>
76
+ <div class="gt-timer-actions">
77
+ <button id="startTimerBtn" class="gt-btn-round" title={t.startBtn}>
78
+ <svg viewBox="0 0 24 24" class="gt-icon-sm"><path fill="currentColor" d="M8 5.14v14l11-7L8 5.14z"/></svg>
79
+ </button>
80
+ <button id="resetTimerBtn" class="gt-btn-round" title={t.resetBtn}>
81
+ <svg viewBox="0 0 24 24" class="gt-icon-sm"><path fill="currentColor" d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
82
+ </button>
83
+ </div>
84
+ </div>
85
+ <div class="gt-timer-presets">
86
+ <div class="gt-presets-grid">
87
+ <button class="gt-preset-btn preset-btn" data-seconds="60">60s</button>
88
+ <button class="gt-preset-btn preset-btn" data-seconds="90">90s</button>
89
+ <button class="gt-preset-btn preset-btn" data-seconds="120">120s</button>
90
+ </div>
91
+ <div class="gt-custom-timer">
92
+ <input type="number" id="customTimerInput" placeholder="s" min="1" max="999" class="gt-input-timer" />
93
+ <button id="setCustomTimerBtn" class="gt-btn-ok">{t.okBtn}</button>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ <div class="gt-progress-bg">
98
+ <div id="timerProgress" class="gt-progress-bar"></div>
99
+ </div>
100
+ </div>
101
+
102
+ <div class="gt-dashboard">
103
+ <div class="gt-chart-wrapper">
104
+ <div class="gt-chart-box">
105
+ <svg id="progressChart" viewBox="0 0 400 200" preserveAspectRatio="none" class="gt-svg-chart">
106
+ <path id="chartPath" d="" fill="none" stroke="currentColor" stroke-width="4" class="gt-path"></path>
107
+ <g id="chartPoints"></g>
108
+ </svg>
109
+ </div>
110
+ <div id="emptyState" class="gt-empty-state">
111
+ {t.noData}
112
+ </div>
113
+ </div>
114
+ <div class="gt-stats">
115
+ <div class="gt-stat-item">
116
+ <span class="gt-stat-label">{t.recordLabel}</span>
117
+ <span id="maxWeight" class="gt-stat-val">0 {t.units}</span>
118
+ </div>
119
+ <div class="gt-stat-item">
120
+ <span class="gt-stat-label">{t.lastLabel}</span>
121
+ <span id="lastWeight" class="gt-stat-val">0 {t.units}</span>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="gt-history">
127
+ <div class="gt-history-header">
128
+ <h3 class="gt-history-title">
129
+ <svg viewBox="0 0 24 24" class="gt-icon-xs"><path fill="currentColor" d="M13.5 8H12v5l4.28 2.54l.72-1.21l-3.5-2.08V8M13 3a9 9 0 0 0-9 9H1l3.96 4.07l.04.03L9 12H6a7 7 0 0 1 7-7a7 7 0 0 1 7 7a7 7 0 0 1-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 9-9a9 9 0 0 0-9-9z"/></svg>
130
+ {t.historyTitle}
131
+ </h3>
132
+ <div class="gt-history-actions">
133
+ <button id="exportDataBtn" class="gt-btn-text">
134
+ <svg viewBox="0 0 24 24" class="gt-icon-xs"><path fill="currentColor" d="M5 20h14v-2H5v2m0-10h4v6h6v-6h4l-7-7l-7 7z"/></svg>
135
+ {t.exportBtn}
136
+ </button>
137
+ <button id="clearHistoryBtn" class="gt-btn-text">Reset</button>
138
+ </div>
139
+ </div>
140
+
141
+ <div id="exportMenu" class="gt-export-menu gt-hidden">
142
+ <button id="exportJsonBtn" class="gt-export-item">JSON</button>
143
+ <button id="exportCsvBtn" class="gt-export-item">CSV</button>
144
+ </div>
145
+
146
+ <div id="historyList" class="gt-history-list"></div>
147
+ </div>
148
+ </div>
149
+
150
+ <div id="confirmModal" class="gt-modal gt-hidden">
151
+ <div class="gt-modal-box">
152
+ <h4>{t.confirmDeleteTitle}</h4>
153
+ <p>{t.confirmDeleteText}</p>
154
+ <div class="gt-modal-btns">
155
+ <button id="confirmDeleteBtn" class="gt-btn-danger">{t.deleteBtn}</button>
156
+ <button id="cancelDeleteBtn" class="gt-btn-cancel">{t.cancelBtn}</button>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+
162
+ <script>
163
+ import { initGymTracker } from './logic';
164
+ initGymTracker();
165
+ </script>
166
+
167
+ <style>
168
+ :global(.gt-root) {
169
+ width: 100%;
170
+ max-width: 520px;
171
+ margin: 0 auto;
172
+ padding: 0.5rem;
173
+ box-sizing: border-box;
174
+ }
175
+
176
+ :global(.gt-card) {
177
+ background: var(--bg-surface);
178
+ border: 1px solid var(--border-base);
179
+ border-radius: 20px;
180
+ padding: 1.25rem;
181
+ display: flex;
182
+ flex-direction: column;
183
+ gap: 1.25rem;
184
+ box-shadow: 0 4px 6px -1px var(--shadow-base);
185
+ width: 100%;
186
+ box-sizing: border-box;
187
+ }
188
+
189
+ :global(.gt-header-row) {
190
+ display: flex;
191
+ gap: 0.75rem;
192
+ align-items: flex-end;
193
+ }
194
+
195
+ :global(.gt-field) {
196
+ flex: 1;
197
+ display: flex;
198
+ flex-direction: column;
199
+ gap: 0.5rem;
200
+ min-width: 0;
201
+ }
202
+
203
+ :global(.gt-field label) {
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 0.5rem;
207
+ font-size: 0.75rem;
208
+ font-weight: 800;
209
+ color: var(--text-muted);
210
+ text-transform: uppercase;
211
+ letter-spacing: 0.05em;
212
+ }
213
+
214
+ :global(.gt-icon-label) {
215
+ width: 16px;
216
+ height: 16px;
217
+ color: var(--primary);
218
+ }
219
+
220
+ :global(.gt-select) {
221
+ width: 100%;
222
+ padding: 0.6rem 2rem 0.6rem 0.75rem;
223
+ background: var(--bg-page);
224
+ border: 1px solid var(--border-base);
225
+ border-radius: 10px;
226
+ color: var(--text-base);
227
+ font-size: 0.95rem;
228
+ font-weight: 600;
229
+ cursor: pointer;
230
+ appearance: none;
231
+ outline: none;
232
+ text-overflow: ellipsis;
233
+ }
234
+
235
+ :global(.gt-select-box) {
236
+ position: relative;
237
+ width: 100%;
238
+ }
239
+
240
+ :global(.gt-select-box::after) {
241
+ content: "\25BC";
242
+ position: absolute;
243
+ right: 0.75rem;
244
+ top: 50%;
245
+ transform: translateY(-50%);
246
+ font-size: 0.6rem;
247
+ color: var(--text-muted);
248
+ pointer-events: none;
249
+ }
250
+
251
+ :global(.gt-btn-toggle) {
252
+ background: var(--bg-page);
253
+ border: 1px solid var(--border-base);
254
+ border-radius: 10px;
255
+ width: 2.75rem;
256
+ height: 2.75rem;
257
+ display: flex;
258
+ align-items: center;
259
+ justify-content: center;
260
+ color: var(--primary);
261
+ cursor: pointer;
262
+ transition: all 0.2s ease;
263
+ flex-shrink: 0;
264
+ }
265
+
266
+ :global(.gt-btn-toggle:hover) {
267
+ background: var(--primary-bg);
268
+ transform: scale(1.05);
269
+ }
270
+
271
+ :global(.gt-custom-form) {
272
+ margin-top: 1rem;
273
+ padding: 1rem;
274
+ background: var(--bg-page);
275
+ border-radius: 12px;
276
+ border: 1px dashed var(--border-base);
277
+ }
278
+
279
+ :global(.gt-label-small) {
280
+ display: block;
281
+ font-size: 0.65rem;
282
+ font-weight: 700;
283
+ color: var(--text-muted);
284
+ margin-bottom: 0.5rem;
285
+ text-transform: uppercase;
286
+ }
287
+
288
+ :global(.gt-custom-row) {
289
+ display: flex;
290
+ gap: 0.5rem;
291
+ }
292
+
293
+ :global(.gt-input-text) {
294
+ flex: 1;
295
+ min-width: 0;
296
+ padding: 0.5rem;
297
+ background: var(--bg-surface);
298
+ border: 1px solid var(--border-base);
299
+ border-radius: 8px;
300
+ color: var(--text-base);
301
+ font-size: 0.9rem;
302
+ }
303
+
304
+ :global(.gt-btn-secondary) {
305
+ background: var(--bg-surface);
306
+ border: 1px solid var(--border-base);
307
+ color: var(--text-base);
308
+ padding: 0 0.75rem;
309
+ border-radius: 8px;
310
+ font-weight: 700;
311
+ font-size: 0.75rem;
312
+ cursor: pointer;
313
+ }
314
+
315
+ :global(.gt-btn-icon) {
316
+ background: none;
317
+ border: none;
318
+ color: var(--text-muted);
319
+ font-size: 1rem;
320
+ cursor: pointer;
321
+ padding: 0 0.5rem;
322
+ }
323
+
324
+ :global(.gt-log-section) {
325
+ background: var(--primary-bg);
326
+ padding: 1rem;
327
+ border-radius: 14px;
328
+ border: 1px solid var(--primary-soft);
329
+ }
330
+
331
+ :global(.gt-label-main) {
332
+ display: flex;
333
+ align-items: center;
334
+ gap: 0.5rem;
335
+ font-weight: 800;
336
+ font-size: 0.8rem;
337
+ color: var(--primary);
338
+ margin-bottom: 0.75rem;
339
+ text-transform: uppercase;
340
+ }
341
+
342
+ :global(.gt-log-row) {
343
+ display: flex;
344
+ gap: 0.75rem;
345
+ }
346
+
347
+ :global(.gt-input-number) {
348
+ flex: 1;
349
+ min-width: 0;
350
+ padding: 0.75rem;
351
+ background: var(--bg-surface);
352
+ border: 1px solid var(--border-base);
353
+ border-radius: 10px;
354
+ color: var(--primary);
355
+ font-size: 1.25rem;
356
+ font-weight: 900;
357
+ text-align: center;
358
+ outline: none;
359
+ }
360
+
361
+ :global(.gt-btn-primary) {
362
+ background: var(--primary);
363
+ color: white;
364
+ border: none;
365
+ border-radius: 10px;
366
+ padding: 0 1.5rem;
367
+ font-weight: 800;
368
+ font-size: 0.85rem;
369
+ text-transform: uppercase;
370
+ cursor: pointer;
371
+ box-shadow: 0 4px 12px var(--primary-soft);
372
+ }
373
+
374
+ :global(.gt-timer-section) {
375
+ background: var(--bg-page);
376
+ border-radius: 16px;
377
+ overflow: hidden;
378
+ position: relative;
379
+ border: 1px solid var(--border-base);
380
+ }
381
+
382
+ :global(.gt-timer-container) {
383
+ padding: 1rem;
384
+ display: flex;
385
+ justify-content: space-between;
386
+ align-items: center;
387
+ gap: 1.5rem;
388
+ }
389
+
390
+ :global(.gt-timer-main) {
391
+ display: flex;
392
+ flex-direction: column;
393
+ align-items: center;
394
+ min-width: 100px;
395
+ }
396
+
397
+ :global(.gt-timer-text) {
398
+ font-size: 2rem;
399
+ font-weight: 900;
400
+ color: var(--text-muted);
401
+ font-variant-numeric: tabular-nums;
402
+ }
403
+
404
+ :global(.gt-timer-text.gt-timer-active) {
405
+ color: var(--primary);
406
+ text-shadow: 0 0 15px var(--primary-soft);
407
+ }
408
+
409
+ :global(.gt-timer-actions) {
410
+ display: flex;
411
+ gap: 0.75rem;
412
+ margin-top: 0.5rem;
413
+ }
414
+
415
+ :global(.gt-btn-round) {
416
+ width: 32px;
417
+ height: 32px;
418
+ border-radius: 50%;
419
+ background: var(--bg-surface);
420
+ border: 1px solid var(--border-base);
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: center;
424
+ color: var(--text-base);
425
+ cursor: pointer;
426
+ transition: all 0.2s ease;
427
+ }
428
+
429
+ :global(.gt-btn-round:hover) {
430
+ background: var(--bg-page);
431
+ transform: scale(1.1);
432
+ }
433
+
434
+ :global(.gt-timer-presets) {
435
+ flex: 1;
436
+ display: flex;
437
+ flex-direction: column;
438
+ gap: 0.5rem;
439
+ }
440
+
441
+ :global(.gt-presets-grid) {
442
+ display: grid;
443
+ grid-template-columns: repeat(3, 1fr);
444
+ gap: 0.4rem;
445
+ }
446
+
447
+ :global(.gt-preset-btn) {
448
+ background: var(--bg-surface);
449
+ border: 1px solid var(--border-base);
450
+ color: var(--text-base);
451
+ border-radius: 6px;
452
+ padding: 0.4rem;
453
+ font-size: 0.75rem;
454
+ font-weight: 700;
455
+ cursor: pointer;
456
+ }
457
+
458
+ :global(.gt-custom-timer) {
459
+ display: flex;
460
+ gap: 0.4rem;
461
+ }
462
+
463
+ :global(.gt-input-timer) {
464
+ flex: 1;
465
+ padding: 0.3rem;
466
+ border-radius: 6px;
467
+ border: 1px solid var(--border-base);
468
+ background: var(--bg-surface);
469
+ color: var(--text-base);
470
+ font-size: 0.8rem;
471
+ text-align: center;
472
+ min-width: 0;
473
+ }
474
+
475
+ :global(.gt-btn-ok) {
476
+ background: var(--primary);
477
+ color: white;
478
+ border: none;
479
+ border-radius: 6px;
480
+ padding: 0 0.75rem;
481
+ font-size: 0.7rem;
482
+ font-weight: 800;
483
+ cursor: pointer;
484
+ }
485
+
486
+ :global(.gt-progress-bg) {
487
+ height: 4px;
488
+ background: var(--border-base);
489
+ width: 100%;
490
+ }
491
+
492
+ :global(.gt-progress-bar) {
493
+ height: 100%;
494
+ background: var(--primary);
495
+ width: 0%;
496
+ transition: width 1s linear;
497
+ }
498
+
499
+ :global(.gt-dashboard) {
500
+ display: flex;
501
+ flex-direction: column;
502
+ gap: 1rem;
503
+ width: 100%;
504
+ }
505
+
506
+ :global(.gt-chart-wrapper) {
507
+ background: var(--bg-page);
508
+ border-radius: 12px;
509
+ padding: 0.75rem;
510
+ height: 120px;
511
+ position: relative;
512
+ border: 1px solid var(--border-base);
513
+ min-width: 0;
514
+ }
515
+
516
+ :global(.gt-chart-box) {
517
+ width: 100%;
518
+ height: 100%;
519
+ }
520
+
521
+ :global(.gt-svg-chart) {
522
+ width: 100%;
523
+ height: 100%;
524
+ color: var(--primary);
525
+ overflow: visible;
526
+ }
527
+
528
+ :global(.gt-path) {
529
+ filter: drop-shadow(0 0 4px var(--primary-soft));
530
+ }
531
+
532
+ :global(.gt-chart-dot) {
533
+ fill: var(--primary);
534
+ stroke: var(--bg-page);
535
+ stroke-width: 2;
536
+ }
537
+
538
+ :global(.gt-empty-state) {
539
+ position: absolute;
540
+ inset: 0;
541
+ display: flex;
542
+ align-items: center;
543
+ justify-content: center;
544
+ font-size: 0.75rem;
545
+ font-weight: 600;
546
+ color: var(--text-muted);
547
+ text-transform: uppercase;
548
+ letter-spacing: 0.1em;
549
+ }
550
+
551
+ :global(.gt-stats) {
552
+ display: grid;
553
+ grid-template-columns: 1fr 1fr;
554
+ gap: 0.75rem;
555
+ width: 100%;
556
+ }
557
+
558
+ :global(.gt-stat-item) {
559
+ background: var(--bg-page);
560
+ border: 1px solid var(--border-base);
561
+ padding: 0.75rem;
562
+ border-radius: 12px;
563
+ text-align: center;
564
+ min-width: 0;
565
+ }
566
+
567
+ :global(.gt-stat-label) {
568
+ display: block;
569
+ font-size: 0.6rem;
570
+ font-weight: 800;
571
+ color: var(--text-muted);
572
+ text-transform: uppercase;
573
+ margin-bottom: 0.25rem;
574
+ }
575
+
576
+ :global(.gt-stat-val) {
577
+ font-size: 1.1rem;
578
+ font-weight: 900;
579
+ color: var(--text-base);
580
+ }
581
+
582
+ :global(.gt-history) {
583
+ border-top: 1px solid var(--border-base);
584
+ padding-top: 1rem;
585
+ min-width: 0;
586
+ }
587
+
588
+ :global(.gt-history-header) {
589
+ display: flex;
590
+ justify-content: space-between;
591
+ align-items: center;
592
+ margin-bottom: 0.75rem;
593
+ }
594
+
595
+ :global(.gt-history-title) {
596
+ display: flex;
597
+ align-items: center;
598
+ gap: 0.5rem;
599
+ margin: 0;
600
+ font-size: 0.8rem;
601
+ font-weight: 800;
602
+ color: var(--text-base);
603
+ text-transform: uppercase;
604
+ white-space: nowrap;
605
+ }
606
+
607
+ :global(.gt-history-actions) {
608
+ display: flex;
609
+ gap: 0.75rem;
610
+ }
611
+
612
+ :global(.gt-btn-text) {
613
+ background: none;
614
+ border: none;
615
+ color: var(--text-muted);
616
+ font-size: 0.7rem;
617
+ font-weight: 700;
618
+ cursor: pointer;
619
+ display: flex;
620
+ align-items: center;
621
+ gap: 0.25rem;
622
+ }
623
+
624
+ :global(.gt-btn-text:hover) {
625
+ color: var(--primary);
626
+ }
627
+
628
+ :global(.gt-export-menu) {
629
+ display: flex;
630
+ gap: 0.5rem;
631
+ margin-bottom: 0.75rem;
632
+ }
633
+
634
+ :global(.gt-export-item) {
635
+ background: var(--bg-page);
636
+ border: 1px solid var(--border-base);
637
+ color: var(--text-base);
638
+ border-radius: 6px;
639
+ padding: 0.4rem 0.75rem;
640
+ font-size: 0.65rem;
641
+ font-weight: 800;
642
+ cursor: pointer;
643
+ }
644
+
645
+ :global(.gt-history-list) {
646
+ display: flex;
647
+ flex-direction: column;
648
+ gap: 0.5rem;
649
+ }
650
+
651
+ :global(.gt-history-item) {
652
+ display: flex;
653
+ justify-content: space-between;
654
+ align-items: center;
655
+ padding: 0.6rem 0.75rem;
656
+ background: var(--bg-page);
657
+ border-radius: 8px;
658
+ font-size: 0.8rem;
659
+ font-weight: 600;
660
+ animation: gt-slide-in 0.3s ease-out;
661
+ }
662
+
663
+ @keyframes gt-slide-in {
664
+ from {
665
+ opacity: 0;
666
+ transform: translateY(4px);
667
+ }
668
+ to {
669
+ opacity: 1;
670
+ transform: translateY(0);
671
+ }
672
+ }
673
+
674
+ :global(.gt-history-row) {
675
+ display: flex;
676
+ align-items: center;
677
+ gap: 1rem;
678
+ }
679
+
680
+ :global(.gt-history-weight) {
681
+ color: var(--primary);
682
+ font-weight: 800;
683
+ }
684
+
685
+ :global(.gt-btn-delete-log) {
686
+ background: none;
687
+ border: none;
688
+ color: var(--text-muted);
689
+ cursor: pointer;
690
+ font-size: 0.8rem;
691
+ padding: 4px;
692
+ display: flex;
693
+ align-items: center;
694
+ justify-content: center;
695
+ }
696
+
697
+ :global(.gt-btn-delete-log:hover) {
698
+ color: #ef4444;
699
+ }
700
+
701
+ :global(.gt-modal) {
702
+ position: fixed;
703
+ inset: 0;
704
+ background: rgba(0, 0, 0, 0.6);
705
+ backdrop-filter: blur(4px);
706
+ z-index: 100;
707
+ display: flex;
708
+ align-items: center;
709
+ justify-content: center;
710
+ padding: 1.5rem;
711
+ }
712
+
713
+ :global(.gt-modal-box) {
714
+ background: var(--bg-surface);
715
+ border: 1px solid var(--border-base);
716
+ border-radius: 20px;
717
+ padding: 1.5rem;
718
+ max-width: 320px;
719
+ width: 100%;
720
+ text-align: center;
721
+ }
722
+
723
+ :global(.gt-modal-box h4) {
724
+ margin: 0 0 0.75rem;
725
+ font-size: 1.1rem;
726
+ font-weight: 900;
727
+ color: var(--text-base);
728
+ }
729
+
730
+ :global(.gt-modal-box p) {
731
+ font-size: 0.85rem;
732
+ color: var(--text-muted);
733
+ margin: 0 0 1.5rem;
734
+ line-height: 1.5;
735
+ }
736
+
737
+ :global(.gt-modal-btns) {
738
+ display: flex;
739
+ gap: 0.75rem;
740
+ }
741
+
742
+ :global(.gt-btn-danger) {
743
+ flex: 1;
744
+ background: #ef4444;
745
+ color: white;
746
+ border: none;
747
+ border-radius: 10px;
748
+ padding: 0.75rem;
749
+ font-weight: 800;
750
+ font-size: 0.8rem;
751
+ cursor: pointer;
752
+ }
753
+
754
+ :global(.gt-btn-cancel) {
755
+ flex: 1;
756
+ background: var(--bg-page);
757
+ border: 1px solid var(--border-base);
758
+ color: var(--text-base);
759
+ border-radius: 10px;
760
+ font-weight: 800;
761
+ font-size: 0.8rem;
762
+ cursor: pointer;
763
+ }
764
+
765
+ :global(.gt-icon-xs) {
766
+ width: 14px;
767
+ height: 14px;
768
+ }
769
+
770
+ :global(.gt-icon-sm) {
771
+ width: 18px;
772
+ height: 18px;
773
+ }
774
+
775
+ :global(.gt-icon-md) {
776
+ width: 22px;
777
+ height: 22px;
778
+ }
779
+
780
+ :global(.gt-hidden) {
781
+ display: none;
782
+ }
783
+ :global(.gt-option-highlight) {
784
+ color: var(--primary);
785
+ font-weight: 800;
786
+ }
787
+
788
+ @media (min-width: 400px) {
789
+ :global(.gt-dashboard) {
790
+ flex-direction: column;
791
+ }
792
+ :global(.gt-chart-wrapper) {
793
+ height: 160px;
794
+ }
795
+ :global(.gt-stats) {
796
+ display: grid;
797
+ grid-template-columns: 1fr 1fr;
798
+ width: 100%;
799
+ gap: 0.75rem;
800
+ }
801
+ }
802
+
803
+ :global(.gt-animate-in) {
804
+ animation: gt-fade-up 0.5s ease-out;
805
+ }
806
+
807
+ @keyframes gt-fade-up {
808
+ from {
809
+ opacity: 0;
810
+ transform: translateY(10px);
811
+ }
812
+ to {
813
+ opacity: 1;
814
+ transform: translateY(0);
815
+ }
816
+ }
817
+
818
+ :global(.theme-dark .gt-card) {
819
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
820
+ }
821
+
822
+ :global(.theme-dark .gt-select),
823
+ :global(.theme-dark .gt-input-text),
824
+ :global(.theme-dark .gt-input-number),
825
+ :global(.theme-dark .gt-input-timer),
826
+ :global(.theme-dark .gt-btn-toggle),
827
+ :global(.theme-dark .gt-btn-round),
828
+ :global(.theme-dark .gt-preset-btn),
829
+ :global(.theme-dark .gt-export-item),
830
+ :global(.theme-dark .gt-stat-item),
831
+ :global(.theme-dark .gt-history-item) {
832
+ background-color: var(--bg-page);
833
+ border-color: rgba(255, 255, 255, 0.1);
834
+ }
835
+ </style>