@jjlmoya/utils-hardware 1.27.0 → 1.29.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 (55) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +7 -1
  4. package/src/index.ts +2 -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/mobileSensorTest/bibliography.astro +14 -0
  8. package/src/tool/mobileSensorTest/bibliography.ts +24 -0
  9. package/src/tool/mobileSensorTest/component.astro +241 -0
  10. package/src/tool/mobileSensorTest/entry.ts +29 -0
  11. package/src/tool/mobileSensorTest/i18n/de.ts +186 -0
  12. package/src/tool/mobileSensorTest/i18n/en.ts +186 -0
  13. package/src/tool/mobileSensorTest/i18n/es.ts +186 -0
  14. package/src/tool/mobileSensorTest/i18n/fr.ts +186 -0
  15. package/src/tool/mobileSensorTest/i18n/id.ts +186 -0
  16. package/src/tool/mobileSensorTest/i18n/it.ts +186 -0
  17. package/src/tool/mobileSensorTest/i18n/ja.ts +186 -0
  18. package/src/tool/mobileSensorTest/i18n/ko.ts +186 -0
  19. package/src/tool/mobileSensorTest/i18n/nl.ts +186 -0
  20. package/src/tool/mobileSensorTest/i18n/pl.ts +186 -0
  21. package/src/tool/mobileSensorTest/i18n/pt.ts +186 -0
  22. package/src/tool/mobileSensorTest/i18n/ru.ts +186 -0
  23. package/src/tool/mobileSensorTest/i18n/sv.ts +186 -0
  24. package/src/tool/mobileSensorTest/i18n/tr.ts +186 -0
  25. package/src/tool/mobileSensorTest/i18n/zh.ts +186 -0
  26. package/src/tool/mobileSensorTest/index.ts +11 -0
  27. package/src/tool/mobileSensorTest/logic.ts +39 -0
  28. package/src/tool/mobileSensorTest/mobile-sensor-test.css +460 -0
  29. package/src/tool/mobileSensorTest/seo.astro +15 -0
  30. package/src/tool/mobileSensorTest/ui.ts +31 -0
  31. package/src/tool/subwooferCrossoverTest/bibliography.astro +14 -0
  32. package/src/tool/subwooferCrossoverTest/bibliography.ts +16 -0
  33. package/src/tool/subwooferCrossoverTest/component.astro +253 -0
  34. package/src/tool/subwooferCrossoverTest/entry.ts +29 -0
  35. package/src/tool/subwooferCrossoverTest/i18n/de.ts +188 -0
  36. package/src/tool/subwooferCrossoverTest/i18n/en.ts +188 -0
  37. package/src/tool/subwooferCrossoverTest/i18n/es.ts +188 -0
  38. package/src/tool/subwooferCrossoverTest/i18n/fr.ts +188 -0
  39. package/src/tool/subwooferCrossoverTest/i18n/id.ts +188 -0
  40. package/src/tool/subwooferCrossoverTest/i18n/it.ts +188 -0
  41. package/src/tool/subwooferCrossoverTest/i18n/ja.ts +188 -0
  42. package/src/tool/subwooferCrossoverTest/i18n/ko.ts +188 -0
  43. package/src/tool/subwooferCrossoverTest/i18n/nl.ts +188 -0
  44. package/src/tool/subwooferCrossoverTest/i18n/pl.ts +188 -0
  45. package/src/tool/subwooferCrossoverTest/i18n/pt.ts +188 -0
  46. package/src/tool/subwooferCrossoverTest/i18n/ru.ts +188 -0
  47. package/src/tool/subwooferCrossoverTest/i18n/sv.ts +188 -0
  48. package/src/tool/subwooferCrossoverTest/i18n/tr.ts +188 -0
  49. package/src/tool/subwooferCrossoverTest/i18n/zh.ts +188 -0
  50. package/src/tool/subwooferCrossoverTest/index.ts +11 -0
  51. package/src/tool/subwooferCrossoverTest/logic.ts +30 -0
  52. package/src/tool/subwooferCrossoverTest/seo.astro +15 -0
  53. package/src/tool/subwooferCrossoverTest/subwoofer-crossover-test.css +282 -0
  54. package/src/tool/subwooferCrossoverTest/ui.ts +20 -0
  55. package/src/tools.ts +3 -1
@@ -0,0 +1,460 @@
1
+ .mst-shell {
2
+ --mst-paper: #f6f3ed;
3
+ --mst-ink: #111;
4
+ --mst-muted: #77736c;
5
+ --mst-line: #d8d2c7;
6
+ --mst-panel: #fffaf1;
7
+ --mst-accent: #e84f3d;
8
+ --mst-accent-soft: #f2d8d2;
9
+
10
+ background: var(--mst-paper);
11
+ border: 1px solid var(--mst-line);
12
+ border-radius: 8px;
13
+ color: var(--mst-ink);
14
+ display: grid;
15
+ gap: 0;
16
+ overflow: hidden;
17
+ width: 100%;
18
+ }
19
+
20
+ .theme-dark .mst-shell {
21
+ --mst-paper: #10100f;
22
+ --mst-ink: #f4efe7;
23
+ --mst-muted: #a09a91;
24
+ --mst-line: #34312d;
25
+ --mst-panel: #171614;
26
+ --mst-accent: #ff6b55;
27
+ --mst-accent-soft: #35201d;
28
+
29
+ background: var(--mst-paper);
30
+ }
31
+
32
+ .mst-stage,
33
+ .mst-panel {
34
+ background: var(--mst-panel);
35
+ border: 0;
36
+ border-radius: 0;
37
+ position: relative;
38
+ }
39
+
40
+ .mst-stage {
41
+ align-content: center;
42
+ border-bottom: 1px solid var(--mst-line);
43
+ display: grid;
44
+ min-height: 30rem;
45
+ overflow: hidden;
46
+ padding: clamp(1rem, 4vw, 2rem);
47
+ place-items: center;
48
+ }
49
+
50
+ .mst-stage::before,
51
+ .mst-stage::after {
52
+ content: '';
53
+ pointer-events: none;
54
+ position: absolute;
55
+ }
56
+
57
+ .mst-stage::before {
58
+ border: 1px solid var(--mst-line);
59
+ border-radius: 50%;
60
+ height: min(68vw, 28rem);
61
+ left: 50%;
62
+ top: 50%;
63
+ transform: translate(-50%, -50%);
64
+ width: min(68vw, 28rem);
65
+ }
66
+
67
+ .mst-stage::after {
68
+ border-bottom: 1px solid var(--mst-line);
69
+ border-top: 1px solid var(--mst-line);
70
+ height: min(32vw, 13rem);
71
+ left: 10%;
72
+ right: 10%;
73
+ top: 50%;
74
+ transform: translateY(-50%) rotate(-18deg);
75
+ }
76
+
77
+ .mst-privacy {
78
+ align-items: center;
79
+ background: var(--mst-paper);
80
+ border: 1px solid var(--mst-line);
81
+ border-radius: 999px;
82
+ display: inline-flex;
83
+ gap: 0.48rem;
84
+ left: clamp(1rem, 4vw, 2rem);
85
+ padding: 0.42rem 0.68rem;
86
+ position: absolute;
87
+ top: clamp(1rem, 4vw, 2rem);
88
+ z-index: 3;
89
+ }
90
+
91
+ .mst-privacy::before {
92
+ background: var(--mst-accent);
93
+ border-radius: 50%;
94
+ content: '';
95
+ height: 0.48rem;
96
+ width: 0.48rem;
97
+ }
98
+
99
+ .mst-privacy span {
100
+ display: none;
101
+ }
102
+
103
+ .mst-privacy strong,
104
+ .mst-panel-top span,
105
+ .mst-axis-grid span,
106
+ .mst-bars span,
107
+ .mst-readout span,
108
+ .mst-rotation-grid span,
109
+ .mst-status,
110
+ .mst-start small {
111
+ color: var(--mst-muted);
112
+ font-size: 0.68rem;
113
+ font-weight: 800;
114
+ letter-spacing: 0;
115
+ text-transform: uppercase;
116
+ }
117
+
118
+ .mst-start {
119
+ background: var(--mst-ink);
120
+ border: 1px solid var(--mst-ink);
121
+ border-radius: 50%;
122
+ color: var(--mst-paper);
123
+ cursor: pointer;
124
+ align-content: center;
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: 0.72rem;
128
+ height: clamp(11.5rem, 38vw, 17rem);
129
+ justify-content: center;
130
+ padding: clamp(1.15rem, 4vw, 1.65rem);
131
+ position: relative;
132
+ transition: transform 180ms ease, background 180ms ease, color 180ms ease;
133
+ width: clamp(11.5rem, 38vw, 17rem);
134
+ z-index: 2;
135
+ }
136
+
137
+ .mst-start::before {
138
+ border: 1px solid var(--mst-ink);
139
+ border-radius: 50%;
140
+ content: '';
141
+ inset: -1.25rem;
142
+ position: absolute;
143
+ }
144
+
145
+ .mst-start::after {
146
+ background: var(--mst-accent);
147
+ border-radius: 50%;
148
+ content: '';
149
+ height: 0.72rem;
150
+ left: 50%;
151
+ position: absolute;
152
+ top: -0.36rem;
153
+ transform: translateX(-50%);
154
+ width: 0.72rem;
155
+ }
156
+
157
+ .mst-start span {
158
+ display: block;
159
+ font-size: clamp(1.7rem, 4.2vw, 2.18rem);
160
+ font-weight: 920;
161
+ line-height: 0.94;
162
+ margin: 0 auto;
163
+ max-width: 100%;
164
+ overflow-wrap: normal;
165
+ text-align: center;
166
+ text-wrap: balance;
167
+ width: 100%;
168
+ }
169
+
170
+ .mst-start small {
171
+ color: var(--mst-paper);
172
+ font-size: 0.72rem;
173
+ font-weight: 850;
174
+ line-height: 1.15;
175
+ margin: 0 auto;
176
+ max-width: 7.5rem;
177
+ opacity: 0.78;
178
+ text-align: center;
179
+ text-transform: none;
180
+ }
181
+
182
+ .mst-start:hover {
183
+ background: var(--mst-accent);
184
+ border-color: var(--mst-accent);
185
+ color: #fff;
186
+ transform: scale(1.025);
187
+ }
188
+
189
+ .mst-start:hover small {
190
+ color: #fff;
191
+ opacity: 0.86;
192
+ }
193
+
194
+ .mst-start:disabled {
195
+ background: var(--mst-panel);
196
+ color: var(--mst-muted);
197
+ cursor: default;
198
+ }
199
+
200
+ .mst-start:disabled small {
201
+ color: var(--mst-muted);
202
+ opacity: 1;
203
+ }
204
+
205
+ .mst-shell[data-state='active'] .mst-start span,
206
+ .mst-shell[data-state='active'] .mst-start small {
207
+ opacity: 0;
208
+ }
209
+
210
+ .mst-shell[data-state='active'] .mst-start {
211
+ background: var(--mst-panel);
212
+ border-color: var(--mst-line);
213
+ }
214
+
215
+ .mst-shell[data-state='active'] .mst-start::after {
216
+ background: var(--mst-accent);
217
+ }
218
+
219
+ .mst-status {
220
+ background: var(--mst-paper);
221
+ border: 1px solid var(--mst-line);
222
+ border-radius: 999px;
223
+ bottom: clamp(1rem, 4vw, 2rem);
224
+ left: 50%;
225
+ min-width: 12rem;
226
+ padding: 0.55rem 0.8rem;
227
+ position: absolute;
228
+ text-align: center;
229
+ transform: translateX(-50%);
230
+ z-index: 3;
231
+ }
232
+
233
+ .mst-shell[data-state='active'] .mst-status {
234
+ color: var(--mst-accent);
235
+ }
236
+
237
+ .mst-shell[data-state='denied'] .mst-status,
238
+ .mst-shell[data-state='unsupported'] .mst-status {
239
+ color: var(--mst-accent);
240
+ }
241
+
242
+ .mst-orbit {
243
+ display: none;
244
+ }
245
+
246
+ .mst-panels {
247
+ display: grid;
248
+ gap: 0;
249
+ }
250
+
251
+ .mst-panel {
252
+ border-bottom: 1px solid var(--mst-line);
253
+ display: grid;
254
+ gap: 0.85rem;
255
+ padding: clamp(1rem, 3vw, 1.35rem);
256
+ }
257
+
258
+ .mst-panel:last-child {
259
+ border-bottom: 0;
260
+ }
261
+
262
+ .mst-panel-top {
263
+ align-items: center;
264
+ display: flex;
265
+ gap: 0.75rem;
266
+ justify-content: space-between;
267
+ }
268
+
269
+ .mst-panel-top strong {
270
+ color: var(--mst-accent);
271
+ font-size: 0.85rem;
272
+ font-weight: 850;
273
+ }
274
+
275
+ .mst-bubble-card {
276
+ min-height: 18rem;
277
+ }
278
+
279
+ .mst-bubble {
280
+ aspect-ratio: 1;
281
+ background:
282
+ linear-gradient(90deg, transparent 49.7%, var(--mst-line) 49.7% 50.3%, transparent 50.3%),
283
+ linear-gradient(transparent 49.7%, var(--mst-line) 49.7% 50.3%, transparent 50.3%);
284
+ border: 1px solid var(--mst-line);
285
+ border-radius: 50%;
286
+ margin: 0 auto;
287
+ max-width: 13.5rem;
288
+ position: relative;
289
+ width: 100%;
290
+ }
291
+
292
+ .mst-bubble::before,
293
+ .mst-bubble::after,
294
+ .mst-bubble i,
295
+ .mst-bubble b {
296
+ border: 1px solid var(--mst-line);
297
+ border-radius: 50%;
298
+ content: '';
299
+ inset: 16%;
300
+ position: absolute;
301
+ }
302
+
303
+ .mst-bubble::after {
304
+ inset: 32%;
305
+ }
306
+
307
+ .mst-bubble i {
308
+ inset: 48%;
309
+ }
310
+
311
+ .mst-bubble b {
312
+ display: none;
313
+ }
314
+
315
+ .mst-bubble span {
316
+ background: var(--mst-accent);
317
+ border: 0.38rem solid var(--mst-accent-soft);
318
+ border-radius: 50%;
319
+ height: 2.35rem;
320
+ left: 50%;
321
+ position: absolute;
322
+ top: 50%;
323
+ transform: translate(-50%, -50%);
324
+ transition: transform 80ms linear;
325
+ width: 2.35rem;
326
+ z-index: 2;
327
+ }
328
+
329
+ .mst-readout {
330
+ align-items: end;
331
+ display: flex;
332
+ justify-content: space-between;
333
+ }
334
+
335
+ .mst-readout strong {
336
+ font-size: clamp(2rem, 7vw, 3.15rem);
337
+ font-weight: 900;
338
+ line-height: 0.88;
339
+ }
340
+
341
+ .mst-axis-grid,
342
+ .mst-rotation-grid {
343
+ display: grid;
344
+ gap: 0;
345
+ grid-template-columns: repeat(3, minmax(0, 1fr));
346
+ }
347
+
348
+ .mst-axis-grid div,
349
+ .mst-rotation-grid div {
350
+ border-right: 1px solid var(--mst-line);
351
+ display: grid;
352
+ gap: 0.3rem;
353
+ min-width: 0;
354
+ padding: 0.15rem 0.8rem 0.15rem 0;
355
+ }
356
+
357
+ .mst-axis-grid div + div,
358
+ .mst-rotation-grid div + div {
359
+ padding-left: 0.8rem;
360
+ }
361
+
362
+ .mst-axis-grid div:last-child,
363
+ .mst-rotation-grid div:last-child {
364
+ border-right: 0;
365
+ }
366
+
367
+ .mst-axis-grid strong {
368
+ font-size: clamp(1.3rem, 5vw, 2.1rem);
369
+ font-weight: 900;
370
+ line-height: 0.95;
371
+ }
372
+
373
+ .mst-bars {
374
+ display: grid;
375
+ gap: 0.7rem;
376
+ }
377
+
378
+ .mst-bars label {
379
+ align-items: center;
380
+ display: grid;
381
+ gap: 0.55rem;
382
+ grid-template-columns: 1.4rem minmax(0, 1fr) 3rem;
383
+ }
384
+
385
+ .mst-bars i {
386
+ background: var(--mst-line);
387
+ border-radius: 999px;
388
+ height: 0.55rem;
389
+ overflow: hidden;
390
+ }
391
+
392
+ .mst-bars b {
393
+ background: var(--mst-accent);
394
+ border-radius: inherit;
395
+ display: block;
396
+ height: 100%;
397
+ transform-origin: left center;
398
+ transition: width 90ms linear, transform 90ms linear;
399
+ width: 2%;
400
+ }
401
+
402
+ .mst-bars strong,
403
+ .mst-rotation-grid strong {
404
+ font-size: 1rem;
405
+ font-weight: 850;
406
+ text-align: right;
407
+ }
408
+
409
+ @media (min-width: 820px) {
410
+ .mst-shell {
411
+ grid-template-columns: minmax(0, 1.05fr) minmax(23rem, 0.95fr);
412
+ }
413
+
414
+ .mst-stage {
415
+ border-bottom: 0;
416
+ border-right: 1px solid var(--mst-line);
417
+ min-height: 36rem;
418
+ }
419
+
420
+ .mst-panels {
421
+ align-content: stretch;
422
+ }
423
+
424
+ .mst-bubble-card {
425
+ min-height: 20rem;
426
+ }
427
+ }
428
+
429
+ @media (max-width: 520px) {
430
+ .mst-stage {
431
+ min-height: 28rem;
432
+ }
433
+
434
+ .mst-axis-grid,
435
+ .mst-rotation-grid {
436
+ grid-template-columns: 1fr;
437
+ }
438
+
439
+ .mst-axis-grid div,
440
+ .mst-rotation-grid div,
441
+ .mst-axis-grid div + div,
442
+ .mst-rotation-grid div + div {
443
+ border-bottom: 1px solid var(--mst-line);
444
+ border-right: 0;
445
+ padding: 0.65rem 0;
446
+ }
447
+
448
+ .mst-axis-grid div:last-child,
449
+ .mst-rotation-grid div:last-child {
450
+ border-bottom: 0;
451
+ }
452
+ }
453
+
454
+ @media (prefers-reduced-motion: reduce) {
455
+ .mst-start,
456
+ .mst-bars b,
457
+ .mst-bubble span {
458
+ transition: none;
459
+ }
460
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { mobileSensorTest } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await mobileSensorTest.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,31 @@
1
+ export interface MobileSensorTestUI extends Record<string, string> {
2
+ startButton: string;
3
+ permissionHint: string;
4
+ privacyBadge: string;
5
+ privacyCopy: string;
6
+ orientationPanel: string;
7
+ motionPanel: string;
8
+ bubblePanel: string;
9
+ statusReady: string;
10
+ statusWaiting: string;
11
+ statusDenied: string;
12
+ statusUnsupported: string;
13
+ statusActive: string;
14
+ steadyLabel: string;
15
+ movingLabel: string;
16
+ shakingLabel: string;
17
+ alphaLabel: string;
18
+ betaLabel: string;
19
+ gammaLabel: string;
20
+ accelXLabel: string;
21
+ accelYLabel: string;
22
+ accelZLabel: string;
23
+ rotationAlphaLabel: string;
24
+ rotationBetaLabel: string;
25
+ rotationGammaLabel: string;
26
+ levelOffsetLabel: string;
27
+ motionMagnitudeLabel: string;
28
+ cubeLabel: string;
29
+ bubbleLabel: string;
30
+ calibrationLabel: string;
31
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import type { KnownLocale } from '../../types';
4
+ import { subwooferCrossoverTest } from './index';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await subwooferCrossoverTest.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && content.bibliography.length > 0 && <SharedBibliography links={content.bibliography} />}
@@ -0,0 +1,16 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'Dolby - Speaker setup guides for home theater',
6
+ url: 'https://www.dolby.com/about/support/guide/speaker-setup-guides/',
7
+ },
8
+ {
9
+ name: 'THX - Speaker and subwoofer placement',
10
+ url: 'https://www.thx.com/questions/where-should-i-position-my-speakers-and-subwoofer/',
11
+ },
12
+ {
13
+ name: 'SVS - Subwoofer room placement and tuning',
14
+ url: 'https://www.svsound.com/blogs/subwoofer-setup-and-tuning',
15
+ },
16
+ ];