@jjlmoya/utils-motor 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +4 -1
  4. package/src/index.ts +5 -0
  5. package/src/tests/locale_completeness.test.ts +1 -1
  6. package/src/tests/tool_validation.test.ts +1 -1
  7. package/src/tool/motorcycleSkidMarkSpeedEstimator/bibliography.astro +6 -0
  8. package/src/tool/motorcycleSkidMarkSpeedEstimator/bibliography.ts +12 -0
  9. package/src/tool/motorcycleSkidMarkSpeedEstimator/component.astro +166 -0
  10. package/src/tool/motorcycleSkidMarkSpeedEstimator/controller.ts +207 -0
  11. package/src/tool/motorcycleSkidMarkSpeedEstimator/dom-views.ts +101 -0
  12. package/src/tool/motorcycleSkidMarkSpeedEstimator/entry.ts +30 -0
  13. package/src/tool/motorcycleSkidMarkSpeedEstimator/evaluator.ts +7 -0
  14. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/de.ts +185 -0
  15. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/en.ts +185 -0
  16. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/es.ts +185 -0
  17. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/fr.ts +185 -0
  18. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/id.ts +185 -0
  19. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/it.ts +185 -0
  20. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/ja.ts +201 -0
  21. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/ko.ts +201 -0
  22. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/nl.ts +185 -0
  23. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/pl.ts +185 -0
  24. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/pt.ts +185 -0
  25. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/ru.ts +185 -0
  26. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/sv.ts +185 -0
  27. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/tr.ts +185 -0
  28. package/src/tool/motorcycleSkidMarkSpeedEstimator/i18n/zh.ts +201 -0
  29. package/src/tool/motorcycleSkidMarkSpeedEstimator/index.ts +10 -0
  30. package/src/tool/motorcycleSkidMarkSpeedEstimator/logic.test.ts +229 -0
  31. package/src/tool/motorcycleSkidMarkSpeedEstimator/logic.ts +179 -0
  32. package/src/tool/motorcycleSkidMarkSpeedEstimator/motorcycle-skid-mark-speed-estimator.css +523 -0
  33. package/src/tool/motorcycleSkidMarkSpeedEstimator/seo.astro +15 -0
  34. package/src/tool/motorcycleSkidMarkSpeedEstimator/storage.ts +49 -0
  35. package/src/tool/motorcycleSkidMarkSpeedEstimator/ui.ts +46 -0
  36. package/src/tools.ts +2 -1
@@ -0,0 +1,523 @@
1
+ .trace {
2
+ --trace-bg-primary: #f8fafc;
3
+ --trace-bg-secondary: #fff;
4
+ --trace-bg-card: rgba(255, 255, 255, 0.95);
5
+ --trace-border: #e2e8f0;
6
+ --trace-border-active: #0284c7;
7
+ --trace-text-primary: #0f172a;
8
+ --trace-text-muted: #64748b;
9
+ --trace-accent-cyan: #0284c7;
10
+ --trace-accent-amber: #d97706;
11
+ --trace-accent-red: #dc2626;
12
+ --trace-road-asphalt: #334155;
13
+ --trace-grit-color: #475569;
14
+ --trace-rubber-mark: #0f172a;
15
+ --trace-metal-silver: #475569;
16
+ --trace-hud-bg: rgba(255, 255, 255, 0.92);
17
+ --trace-hud-shadow: rgba(0, 0, 0, 0.12);
18
+ --trace-input-bg: #f1f5f9;
19
+ --trace-segmented-bg: #f1f5f9;
20
+ --trace-span: 0.55;
21
+ --trace-tilt: 0deg;
22
+
23
+ color: var(--trace-text-primary);
24
+ width: 100%;
25
+ box-sizing: border-box;
26
+ }
27
+
28
+ .theme-dark .trace {
29
+ --trace-bg-primary: #0f172a;
30
+ --trace-bg-secondary: #1e293b;
31
+ --trace-bg-card: rgba(30, 41, 59, 0.85);
32
+ --trace-border: rgba(255, 255, 255, 0.1);
33
+ --trace-border-active: #38bdf8;
34
+ --trace-text-primary: #f8fafc;
35
+ --trace-text-muted: #94a3b8;
36
+ --trace-accent-cyan: #38bdf8;
37
+ --trace-accent-amber: #f59e0b;
38
+ --trace-accent-red: #ef4444;
39
+ --trace-road-asphalt: #334155;
40
+ --trace-grit-color: #475569;
41
+ --trace-rubber-mark: #0f172a;
42
+ --trace-metal-silver: #cbd5e1;
43
+ --trace-hud-bg: rgba(15, 23, 42, 0.88);
44
+ --trace-hud-shadow: rgba(0, 0, 0, 0.6);
45
+ --trace-input-bg: rgba(15, 23, 42, 0.8);
46
+ --trace-segmented-bg: rgba(15, 23, 42, 0.6);
47
+ }
48
+
49
+ .trace * {
50
+ box-sizing: border-box;
51
+ }
52
+
53
+ .trace-card {
54
+ background: var(--trace-bg-primary);
55
+ border: 1px solid var(--trace-border);
56
+ border-radius: 1rem;
57
+ overflow: hidden;
58
+ box-shadow: 0 20px 25px -5px var(--trace-hud-shadow), 0 8px 10px -6px var(--trace-hud-shadow);
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: 0;
62
+ transition: background-color 0.3s ease, border-color 0.3s ease;
63
+ }
64
+
65
+ .trace-header {
66
+ background: var(--trace-bg-secondary);
67
+ padding: 1.25rem 1.5rem;
68
+ display: grid;
69
+ grid-template-columns: auto 1fr auto;
70
+ gap: 1.5rem;
71
+ align-items: center;
72
+ border-bottom: 1px solid var(--trace-border);
73
+ transition: background-color 0.3s ease, border-color 0.3s ease;
74
+ }
75
+
76
+ .trace-control-group {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 0.4rem;
80
+ }
81
+
82
+ .trace-label-sm {
83
+ font-size: 0.75rem;
84
+ font-weight: 600;
85
+ text-transform: uppercase;
86
+ letter-spacing: 0.05em;
87
+ color: var(--trace-text-muted);
88
+ }
89
+
90
+ .trace-segmented {
91
+ display: inline-flex;
92
+ background: var(--trace-segmented-bg);
93
+ padding: 0.25rem;
94
+ border-radius: 0.6rem;
95
+ border: 1px solid var(--trace-border);
96
+ gap: 0.25rem;
97
+ }
98
+
99
+ .trace-pill {
100
+ border: none;
101
+ background: transparent;
102
+ color: var(--trace-text-muted);
103
+ padding: 0.45rem 0.85rem;
104
+ font-size: 0.85rem;
105
+ font-weight: 500;
106
+ border-radius: 0.45rem;
107
+ cursor: pointer;
108
+ transition: all 0.2s ease;
109
+ display: flex;
110
+ align-items: center;
111
+ gap: 0.35rem;
112
+ }
113
+
114
+ .trace-pill:hover {
115
+ color: var(--trace-text-primary);
116
+ background: rgba(0, 0, 0, 0.05);
117
+ }
118
+
119
+ .theme-dark .trace-pill:hover {
120
+ background: rgba(255, 255, 255, 0.05);
121
+ }
122
+
123
+ .trace-pill.is-stencil,
124
+ .trace-pill.is-lock {
125
+ background: var(--trace-accent-cyan);
126
+ color: #fff;
127
+ font-weight: 600;
128
+ box-shadow: 0 0 12px rgba(2, 132, 199, 0.3);
129
+ }
130
+
131
+ .theme-dark .trace-pill.is-stencil,
132
+ .theme-dark .trace-pill.is-lock {
133
+ color: #0f172a;
134
+ box-shadow: 0 0 12px rgba(56, 189, 248, 0.4);
135
+ }
136
+
137
+ .trace-pill-unit {
138
+ font-size: 0.7rem;
139
+ opacity: 0.85;
140
+ font-weight: 400;
141
+ }
142
+
143
+ .trace-length-group {
144
+ max-width: 220px;
145
+ justify-self: center;
146
+ width: 100%;
147
+ }
148
+
149
+ .trace-length-input-box {
150
+ display: flex;
151
+ flex-direction: column;
152
+ gap: 0.4rem;
153
+ width: 100%;
154
+ }
155
+
156
+ .trace-input-label {
157
+ font-size: 0.75rem;
158
+ font-weight: 600;
159
+ text-transform: uppercase;
160
+ letter-spacing: 0.05em;
161
+ color: var(--trace-text-muted);
162
+ }
163
+
164
+ .trace-input-wrapper {
165
+ display: flex;
166
+ align-items: center;
167
+ background: var(--trace-input-bg);
168
+ border: 1px solid var(--trace-border);
169
+ border-radius: 0.6rem;
170
+ overflow: hidden;
171
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
172
+ }
173
+
174
+ .trace-input-wrapper:focus-within {
175
+ border-color: var(--trace-accent-cyan);
176
+ box-shadow: 0 0 0 3px rgba(2, 132, 199, 0.2);
177
+ }
178
+
179
+ .trace-numeric-input {
180
+ background: transparent;
181
+ border: none;
182
+ color: var(--trace-text-primary);
183
+ padding: 0.5rem 0.75rem;
184
+ font-size: 1.1rem;
185
+ font-weight: 700;
186
+ width: 100%;
187
+ outline: none;
188
+ }
189
+
190
+ .trace-unit-badge {
191
+ background: rgba(0, 0, 0, 0.05);
192
+ color: var(--trace-accent-cyan);
193
+ padding: 0.5rem 0.75rem;
194
+ font-size: 0.85rem;
195
+ font-weight: 600;
196
+ }
197
+
198
+ .theme-dark .trace-unit-badge {
199
+ background: rgba(255, 255, 255, 0.08);
200
+ }
201
+
202
+ .trace-canvas-container {
203
+ position: relative;
204
+ background: #1e293b;
205
+ cursor: ew-resize;
206
+ overflow: hidden;
207
+ user-select: none;
208
+ touch-action: none;
209
+ }
210
+
211
+ .trace-hud-overlay {
212
+ position: absolute;
213
+ top: 1.25rem;
214
+ left: 1.25rem;
215
+ z-index: 10;
216
+ pointer-events: none;
217
+ }
218
+
219
+ .trace-hud-badge {
220
+ background: var(--trace-hud-bg);
221
+ backdrop-filter: blur(12px);
222
+ border: 1px solid var(--trace-border);
223
+ border-radius: 0.75rem;
224
+ padding: 0.85rem 1.25rem;
225
+ box-shadow: 0 10px 25px -5px var(--trace-hud-shadow);
226
+ }
227
+
228
+ .trace-hud-caption {
229
+ font-size: 0.7rem;
230
+ font-weight: 700;
231
+ text-transform: uppercase;
232
+ letter-spacing: 0.08em;
233
+ color: var(--trace-text-muted);
234
+ display: block;
235
+ margin-bottom: 0.2rem;
236
+ }
237
+
238
+ .trace-hud-speed {
239
+ font-size: 2.2rem;
240
+ font-weight: 800;
241
+ color: var(--trace-accent-cyan);
242
+ line-height: 1.1;
243
+ letter-spacing: -0.02em;
244
+ }
245
+
246
+ .trace-hud-range {
247
+ font-size: 0.85rem;
248
+ font-weight: 500;
249
+ color: var(--trace-text-muted);
250
+ margin-top: 0.25rem;
251
+ }
252
+
253
+ .trace[data-eval='invalid'] .trace-hud-speed {
254
+ font-size: 1.25rem;
255
+ color: var(--trace-accent-red);
256
+ text-shadow: none;
257
+ }
258
+
259
+ .trace-svg {
260
+ display: block;
261
+ width: 100%;
262
+ height: auto;
263
+ min-height: 260px;
264
+ transform: rotate(var(--trace-tilt));
265
+ transform-origin: center center;
266
+ transition: transform 0.3s ease;
267
+ }
268
+
269
+ .trace-fill-road {
270
+ fill: var(--trace-road-asphalt);
271
+ transition: fill 0.4s ease;
272
+ }
273
+
274
+ .trace-fill-grit {
275
+ fill: var(--trace-grit-color);
276
+ }
277
+
278
+ .trace-lane {
279
+ fill: none;
280
+ stroke: rgba(255, 255, 255, 0.4);
281
+ stroke-width: 5;
282
+ stroke-dasharray: 28 20;
283
+ }
284
+
285
+ .trace-scar-line {
286
+ fill: none;
287
+ stroke: var(--trace-rubber-mark);
288
+ stroke-linecap: round;
289
+ stroke-dasharray: 1;
290
+ stroke-dashoffset: calc(1 - var(--trace-span));
291
+ transition: stroke-dashoffset 0.1s linear, opacity 0.3s ease;
292
+ }
293
+
294
+ .trace-scar-rear {
295
+ stroke-width: 20;
296
+ }
297
+
298
+ .trace-scar-front {
299
+ stroke-width: 12;
300
+ }
301
+
302
+ .trace-stria {
303
+ fill: none;
304
+ stroke: rgba(255, 255, 255, 0.25);
305
+ stroke-width: 2;
306
+ stroke-dasharray: 1;
307
+ stroke-dashoffset: calc(1 - var(--trace-span));
308
+ transition: stroke-dashoffset 0.1s linear;
309
+ }
310
+
311
+ .trace[data-brake='rear'] .trace-scar-front,
312
+ .trace[data-brake='front'] .trace-scar-rear {
313
+ opacity: 0.15;
314
+ }
315
+
316
+ .trace[data-brake='unknown'] .trace-scar-line {
317
+ opacity: 0.45;
318
+ }
319
+
320
+ .trace-tyre {
321
+ fill: #090d16;
322
+ }
323
+
324
+ .trace-hub {
325
+ fill: var(--trace-metal-silver);
326
+ }
327
+
328
+ .trace-rotor {
329
+ fill: none;
330
+ stroke: var(--trace-metal-silver);
331
+ stroke-width: 4;
332
+ transition: all 0.3s ease;
333
+ }
334
+
335
+ .trace[data-brake='rear'] .trace-rotor-rear,
336
+ .trace[data-brake='both'] .trace-rotor-rear,
337
+ .trace[data-brake='front'] .trace-rotor-front,
338
+ .trace[data-brake='both'] .trace-rotor-front {
339
+ fill: var(--trace-accent-amber);
340
+ stroke: var(--trace-accent-amber);
341
+ }
342
+
343
+ .trace-swing,
344
+ .trace-bars,
345
+ .trace-pipe,
346
+ .trace-rider {
347
+ fill: none;
348
+ stroke: var(--trace-accent-cyan);
349
+ stroke-width: 4.5;
350
+ stroke-linecap: round;
351
+ stroke-linejoin: round;
352
+ }
353
+
354
+ .trace-body,
355
+ .trace-saddle {
356
+ fill: #1e293b;
357
+ stroke: var(--trace-accent-cyan);
358
+ stroke-width: 2;
359
+ }
360
+
361
+ .trace-head {
362
+ fill: var(--trace-accent-cyan);
363
+ }
364
+
365
+ .trace-controls-bottom {
366
+ background: var(--trace-bg-secondary);
367
+ padding: 1.25rem 1.5rem;
368
+ display: grid;
369
+ grid-template-columns: 1fr 340px;
370
+ gap: 1.5rem;
371
+ border-top: 1px solid var(--trace-border);
372
+ transition: background-color 0.3s ease, border-color 0.3s ease;
373
+ }
374
+
375
+ .trace-section-title {
376
+ font-size: 0.75rem;
377
+ font-weight: 700;
378
+ text-transform: uppercase;
379
+ letter-spacing: 0.06em;
380
+ color: var(--trace-text-muted);
381
+ margin: 0 0 0.75rem;
382
+ }
383
+
384
+ .trace-surface-grid {
385
+ display: grid;
386
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
387
+ gap: 0.5rem;
388
+ }
389
+
390
+ .trace-surface-chip {
391
+ background: var(--trace-segmented-bg);
392
+ border: 1px solid var(--trace-border);
393
+ border-radius: 0.6rem;
394
+ color: var(--trace-text-primary);
395
+ padding: 0.6rem 0.75rem;
396
+ font-size: 0.8rem;
397
+ font-weight: 500;
398
+ cursor: pointer;
399
+ display: flex;
400
+ align-items: center;
401
+ gap: 0.5rem;
402
+ transition: all 0.2s ease;
403
+ text-align: left;
404
+ }
405
+
406
+ .trace-surface-chip:hover {
407
+ background: rgba(0, 0, 0, 0.04);
408
+ border-color: var(--trace-text-muted);
409
+ }
410
+
411
+ .theme-dark .trace-surface-chip:hover {
412
+ background: rgba(255, 255, 255, 0.08);
413
+ }
414
+
415
+ .trace-surface-dot {
416
+ width: 0.6rem;
417
+ height: 0.6rem;
418
+ border-radius: 50%;
419
+ background: var(--trace-text-muted);
420
+ flex-shrink: 0;
421
+ }
422
+
423
+ .trace-surface-chip[data-tone='dry'] .trace-surface-dot { background: #64748b; }
424
+ .trace-surface-chip[data-tone='wet'] .trace-surface-dot { background: #0284c7; }
425
+ .trace-surface-chip[data-tone='concrete'] .trace-surface-dot { background: #94a3b8; }
426
+ .trace-surface-chip[data-tone='gravel'] .trace-surface-dot { background: #d97706; }
427
+ .trace-surface-chip[data-tone='earth'] .trace-surface-dot { background: #16a34a; }
428
+ .trace-surface-chip[data-tone='ice'] .trace-surface-dot { background: #0284c7; }
429
+ .trace-surface-chip[data-tone='steel'] .trace-surface-dot { background: #dc2626; }
430
+
431
+ .trace-surface-chip.is-core {
432
+ border-color: var(--trace-accent-cyan);
433
+ background: rgba(2, 132, 199, 0.1);
434
+ color: var(--trace-accent-cyan);
435
+ font-weight: 600;
436
+ box-shadow: 0 0 10px rgba(2, 132, 199, 0.15);
437
+ }
438
+
439
+ .theme-dark .trace-surface-chip.is-core {
440
+ background: rgba(56, 189, 248, 0.12);
441
+ box-shadow: 0 0 12px rgba(56, 189, 248, 0.2);
442
+ }
443
+
444
+ .trace-sliders-section {
445
+ display: flex;
446
+ flex-direction: column;
447
+ gap: 1rem;
448
+ }
449
+
450
+ .trace-slider-card {
451
+ background: var(--trace-segmented-bg);
452
+ border: 1px solid var(--trace-border);
453
+ border-radius: 0.6rem;
454
+ padding: 0.75rem 1rem;
455
+ }
456
+
457
+ .trace-slider-header {
458
+ display: flex;
459
+ justify-content: space-between;
460
+ align-items: center;
461
+ margin-bottom: 0.5rem;
462
+ }
463
+
464
+ .trace-slider-title {
465
+ font-size: 0.8rem;
466
+ font-weight: 600;
467
+ color: var(--trace-text-muted);
468
+ }
469
+
470
+ .trace-small-input {
471
+ background: var(--trace-input-bg);
472
+ border: 1px solid var(--trace-border);
473
+ border-radius: 0.4rem;
474
+ color: var(--trace-accent-cyan);
475
+ font-size: 0.85rem;
476
+ font-weight: 700;
477
+ width: 4rem;
478
+ padding: 0.2rem 0.4rem;
479
+ text-align: right;
480
+ outline: none;
481
+ }
482
+
483
+ .trace-small-input:focus {
484
+ border-color: var(--trace-accent-cyan);
485
+ }
486
+
487
+ .trace-slider-val-badge {
488
+ font-size: 0.85rem;
489
+ font-weight: 700;
490
+ color: var(--trace-accent-cyan);
491
+ }
492
+
493
+ .trace-range-slider {
494
+ width: 100%;
495
+ height: 6px;
496
+ border-radius: 3px;
497
+ background: var(--trace-border);
498
+ outline: none;
499
+ accent-color: var(--trace-accent-cyan);
500
+ cursor: pointer;
501
+ }
502
+
503
+ /* Dynamic surface environment colors */
504
+ .trace[data-surface='wet-asphalt'] .trace-fill-road { fill: #1e293b; }
505
+ .trace[data-surface='dry-concrete'] .trace-fill-road { fill: #475569; }
506
+ .trace[data-surface='gravel'] .trace-fill-road { fill: #451a03; }
507
+ .trace[data-surface='grass'] .trace-fill-road { fill: #064e3b; }
508
+ .trace[data-surface='ice'] .trace-fill-road { fill: #1e3a8a; }
509
+
510
+ @media (max-width: 900px) {
511
+ .trace-header {
512
+ grid-template-columns: 1fr;
513
+ gap: 1rem;
514
+ }
515
+
516
+ .trace-length-group {
517
+ max-width: 100%;
518
+ }
519
+
520
+ .trace-controls-bottom {
521
+ grid-template-columns: 1fr;
522
+ }
523
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { motorcycleSkidMarkSpeedEstimator } from './entry';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const loader = motorcycleSkidMarkSpeedEstimator.i18n[locale] ?? motorcycleSkidMarkSpeedEstimator.i18n.en;
12
+ const content = await loader?.();
13
+ ---
14
+
15
+ {content && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,49 @@
1
+ import {
2
+ isBrakeUse,
3
+ isSurfaceId,
4
+ isUnitSystem,
5
+ type BrakeUse,
6
+ type SurfaceId,
7
+ type UnitSystem,
8
+ } from './logic';
9
+
10
+ export interface SavedSkidState {
11
+ lengthMeters: number;
12
+ unit: UnitSystem;
13
+ surface: SurfaceId;
14
+ friction: number;
15
+ gradePercent: number;
16
+ brakeUse: BrakeUse;
17
+ }
18
+
19
+ const STORAGE_KEY = 'jjlmoya:motorcycle-skid-mark-speed-estimator';
20
+
21
+ function isSavedSkidState(value: unknown): value is SavedSkidState {
22
+ if (!value || typeof value !== 'object') return false;
23
+ const state = value as SavedSkidState;
24
+ return (
25
+ typeof state.lengthMeters === 'number' &&
26
+ isUnitSystem(state.unit) &&
27
+ isSurfaceId(state.surface) &&
28
+ typeof state.friction === 'number' &&
29
+ typeof state.gradePercent === 'number' &&
30
+ isBrakeUse(state.brakeUse)
31
+ );
32
+ }
33
+
34
+ export function loadSkidState(): SavedSkidState | null {
35
+ try {
36
+ const raw = localStorage.getItem(STORAGE_KEY);
37
+ if (!raw) return null;
38
+ const parsed: unknown = JSON.parse(raw);
39
+ return isSavedSkidState(parsed) ? parsed : null;
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ export function saveSkidState(state: SavedSkidState): void {
46
+ try {
47
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
48
+ } catch {}
49
+ }
@@ -0,0 +1,46 @@
1
+ export interface MotorcycleSkidMarkSpeedEstimatorUI extends Record<string, string> {
2
+ unitMetric: string;
3
+ unitImperial: string;
4
+ disclaimer: string;
5
+ lengthLabel: string;
6
+ lengthHint: string;
7
+ gradeLabel: string;
8
+ gradeHint: string;
9
+ surfaceLabel: string;
10
+ frictionLabel: string;
11
+ frictionHint: string;
12
+ brakeLabel: string;
13
+ brakeBoth: string;
14
+ brakeFront: string;
15
+ brakeRear: string;
16
+ brakeUnknown: string;
17
+ speedLabel: string;
18
+ rangeLabel: string;
19
+ dragHint: string;
20
+ emptyMessage: string;
21
+ invalidMessage: string;
22
+ readyMessage: string;
23
+ educationalBadge: string;
24
+ surfaceDryAsphalt: string;
25
+ surfaceWetAsphalt: string;
26
+ surfaceDryConcrete: string;
27
+ surfaceGravel: string;
28
+ surfaceGrass: string;
29
+ surfaceIce: string;
30
+ surfaceCustom: string;
31
+ sensitivityLabel: string;
32
+ lowAssumption: string;
33
+ highAssumption: string;
34
+ gradeUphill: string;
35
+ gradeDownhill: string;
36
+ gradeLevel: string;
37
+ measureHint: string;
38
+ stencilUnitKmh: string;
39
+ stencilUnitMph: string;
40
+ lengthUnitM: string;
41
+ lengthUnitFt: string;
42
+ percentSuffix: string;
43
+ dragLowLabel: string;
44
+ dragMidLabel: string;
45
+ dragHighLabel: string;
46
+ }
package/src/tools.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export { ALL_ENTRIES } from './entries';
2
2
  import { BRAKING_DISTANCE_CALCULATOR_TOOL } from './tool/brakingDistanceCalculator';
3
3
  import { CAR_MOTORCYCLE_GEAR_RATIO_CALCULATOR_TOOL } from './tool/carMotorcycleGearRatioCalculator';
4
+ import { MOTORCYCLE_SKID_MARK_SPEED_ESTIMATOR_TOOL } from './tool/motorcycleSkidMarkSpeedEstimator';
4
5
  import { REAL_FUEL_CONSUMPTION_CALCULATOR_TOOL } from './tool/realFuelConsumptionCalculator';
5
6
  import { TIRE_PRESSURE_CONVERTER_TOOL } from './tool/tirePressureConverter';
6
7
 
7
- export const ALL_TOOLS = [BRAKING_DISTANCE_CALCULATOR_TOOL, REAL_FUEL_CONSUMPTION_CALCULATOR_TOOL, CAR_MOTORCYCLE_GEAR_RATIO_CALCULATOR_TOOL, TIRE_PRESSURE_CONVERTER_TOOL];
8
+ export const ALL_TOOLS = [BRAKING_DISTANCE_CALCULATOR_TOOL, REAL_FUEL_CONSUMPTION_CALCULATOR_TOOL, CAR_MOTORCYCLE_GEAR_RATIO_CALCULATOR_TOOL, TIRE_PRESSURE_CONVERTER_TOOL, MOTORCYCLE_SKID_MARK_SPEED_ESTIMATOR_TOOL];