@jjlmoya/utils-health 1.10.0 → 1.11.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 (34) hide show
  1. package/package.json +5 -3
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/tool/binauralTuner/binaural-wave-tuner-lucid-dreams.css +430 -0
  4. package/src/tool/binauralTuner/component.astro +0 -433
  5. package/src/tool/bloodUnitConverter/blood-test-unit-converter.css +475 -0
  6. package/src/tool/bloodUnitConverter/component.astro +0 -477
  7. package/src/tool/bmiCalculator/bmi-calculator.css +252 -0
  8. package/src/tool/bmiCalculator/component.astro +0 -254
  9. package/src/tool/breathingVisualizer/breathing-visualizer.css +309 -0
  10. package/src/tool/breathingVisualizer/component.astro +0 -311
  11. package/src/tool/caffeineTracker/caffeine-tracker.css +767 -0
  12. package/src/tool/caffeineTracker/component.astro +0 -769
  13. package/src/tool/daltonismSimulator/color-blindness-simulator.css +167 -0
  14. package/src/tool/daltonismSimulator/component.astro +0 -169
  15. package/src/tool/digestionStopwatch/component.astro +0 -423
  16. package/src/tool/digestionStopwatch/digestion-stopwatch.css +421 -0
  17. package/src/tool/epworthSleepinessScale/component.astro +0 -337
  18. package/src/tool/epworthSleepinessScale/epworth-sleepiness-scale-test.css +335 -0
  19. package/src/tool/hydrationCalculator/component.astro +0 -427
  20. package/src/tool/hydrationCalculator/hydration-calculator-climate.css +425 -0
  21. package/src/tool/pelliRobsonTest/component.astro +0 -428
  22. package/src/tool/pelliRobsonTest/pelli-robson-contrast-sensitivity-test.css +426 -0
  23. package/src/tool/peripheralVisionTrainer/component.astro +0 -400
  24. package/src/tool/peripheralVisionTrainer/peripheral-vision-trainer.css +399 -0
  25. package/src/tool/readingDistanceCalculator/component.astro +0 -397
  26. package/src/tool/readingDistanceCalculator/reading-distance-calculator.css +395 -0
  27. package/src/tool/screenDecompressionTime/component.astro +0 -390
  28. package/src/tool/screenDecompressionTime/ocular-decompression-rest-calculator.css +388 -0
  29. package/src/tool/tinnitusReliever/component.astro +0 -266
  30. package/src/tool/tinnitusReliever/tinnitus-relief.css +264 -0
  31. package/src/tool/ubeCalculator/component.astro +0 -423
  32. package/src/tool/ubeCalculator/standard-drink-unit-calculator.css +421 -0
  33. package/src/tool/waterPurifier/component.astro +0 -451
  34. package/src/tool/waterPurifier/water-purifier.css +449 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-health",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -10,7 +10,8 @@
10
10
  "./entries": "./src/entries.ts"
11
11
  },
12
12
  "files": [
13
- "src"
13
+ "src",
14
+ "scripts"
14
15
  ],
15
16
  "publishConfig": {
16
17
  "access": "public"
@@ -29,7 +30,8 @@
29
30
  "postversion": "git push && git push --tags",
30
31
  "patch": "npm version patch",
31
32
  "minor": "npm version minor",
32
- "major": "npm version major"
33
+ "major": "npm version major",
34
+ "postinstall": "node scripts/postinstall.mjs"
33
35
  },
34
36
  "lint-staged": {
35
37
  "*.{ts,tsx,astro}": [
@@ -0,0 +1,27 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const libDir = dirname(fileURLToPath(import.meta.url));
6
+ const toolsDir = join(libDir, '../src/tool');
7
+
8
+ const inNodeModules = libDir.includes('node_modules');
9
+ if (!inNodeModules) process.exit(0);
10
+
11
+ const projectRoot = join(libDir, '../../../..');
12
+ const categoryKey = JSON.parse(readFileSync(join(libDir, '../package.json'), 'utf8')).name.replace('@jjlmoya/utils-', '');
13
+ const destDir = join(projectRoot, `public/styles/lib/${categoryKey}`);
14
+
15
+ mkdirSync(destDir, { recursive: true });
16
+
17
+ const tools = readdirSync(toolsDir, { withFileTypes: true }).filter(d => d.isDirectory());
18
+ for (const tool of tools) {
19
+ const toolDir = join(toolsDir, tool.name);
20
+ let files;
21
+ try { files = readdirSync(toolDir).filter(f => f.endsWith('.css')); }
22
+ catch { continue; }
23
+ for (const file of files) {
24
+ writeFileSync(join(destDir, file), readFileSync(join(toolDir, file)));
25
+ console.log(`[@jjlmoya/utils-${categoryKey}] copied ${file}`);
26
+ }
27
+ }
@@ -0,0 +1,430 @@
1
+ .bt {
2
+ --bt-bg: #f5f0ff;
3
+ --bt-primary: #7000ff;
4
+ --bt-secondary: #0ad;
5
+ --bt-accent: #c0c;
6
+ --bt-text: #1a003d;
7
+ --bt-glass: rgba(112, 0, 255, 0.04);
8
+ --bt-glass-border: rgba(112, 0, 255, 0.18);
9
+ --bt-muted: rgba(26, 0, 61, 0.5);
10
+ --bt-range-track: rgba(112, 0, 255, 0.08);
11
+ --bt-range-track-border: rgba(112, 0, 255, 0.18);
12
+ --bt-preset-color: rgba(26, 0, 61, 0.7);
13
+ --bt-warning-bg: rgba(220, 38, 38, 0.05);
14
+ --bt-warning-border: rgba(220, 38, 38, 0.18);
15
+ --bt-warning-text: rgba(26, 0, 61, 0.6);
16
+ --bt-warning-strong: #dc2626;
17
+ --bt-strobe-border: rgba(112, 0, 255, 0.2);
18
+ --bt-strobe-color: #1a003d;
19
+ --bt-visualizer-bg: rgba(3, 4, 22, 0.88);
20
+ --bt-shadow: 0 8px 32px rgba(112, 0, 255, 0.15);
21
+
22
+ max-width: 56rem;
23
+ margin: 0 auto;
24
+ padding: 0 1rem;
25
+ }
26
+
27
+
28
+ :global(.theme-dark) .bt {
29
+ --bt-bg: #030416;
30
+ --bt-secondary: #00f2ff;
31
+ --bt-accent: #f0f;
32
+ --bt-text: #fff;
33
+ --bt-glass: rgba(255, 255, 255, 0.03);
34
+ --bt-glass-border: rgba(255, 255, 255, 0.1);
35
+ --bt-muted: rgba(255, 255, 255, 0.5);
36
+ --bt-range-track: rgba(255, 255, 255, 0.05);
37
+ --bt-range-track-border: rgba(255, 255, 255, 0.1);
38
+ --bt-preset-color: rgba(255, 255, 255, 0.7);
39
+ --bt-warning-bg: rgba(255, 0, 0, 0.05);
40
+ --bt-warning-border: rgba(255, 0, 0, 0.1);
41
+ --bt-warning-text: rgba(255, 255, 255, 0.5);
42
+ --bt-warning-strong: rgba(255, 100, 100, 1);
43
+ --bt-strobe-border: rgba(255, 255, 255, 0.1);
44
+ --bt-strobe-color: #fff;
45
+ --bt-visualizer-bg: rgba(0, 0, 0, 0.3);
46
+ --bt-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
47
+ }
48
+
49
+
50
+ .bt__card {
51
+ background: var(--bt-bg);
52
+ border: 1px solid var(--bt-glass-border);
53
+ border-radius: 2rem;
54
+ padding: 2rem 1.5rem;
55
+ box-shadow: var(--bt-shadow);
56
+ display: flex;
57
+ flex-direction: column;
58
+ gap: 2.5rem;
59
+ position: relative;
60
+ overflow: hidden;
61
+ backdrop-filter: blur(20px);
62
+ }
63
+
64
+ @media (min-width: 768px) {
65
+ .bt__card {
66
+ padding: 3rem;
67
+ border-radius: 2.5rem;
68
+ gap: 3rem;
69
+ }
70
+ }
71
+
72
+ .bt__card::before {
73
+ content: '';
74
+ position: absolute;
75
+ top: -10%;
76
+ right: -10%;
77
+ width: 40%;
78
+ height: 40%;
79
+ background: radial-gradient(circle, rgba(112, 0, 255, 0.12) 0%, transparent 70%);
80
+ pointer-events: none;
81
+ }
82
+
83
+ :global(.theme-dark) .bt__card::before {
84
+ background: radial-gradient(circle, rgba(112, 0, 255, 0.15) 0%, transparent 70%);
85
+ }
86
+
87
+ .bt__card::after {
88
+ content: '';
89
+ position: absolute;
90
+ bottom: -10%;
91
+ left: -10%;
92
+ width: 40%;
93
+ height: 40%;
94
+ background: radial-gradient(circle, rgba(0, 170, 221, 0.1) 0%, transparent 70%);
95
+ }
96
+
97
+ :global(.theme-dark) .bt__card::after {
98
+ background: radial-gradient(circle, rgba(0, 242, 255, 0.1) 0%, transparent 70%);
99
+ pointer-events: none;
100
+ }
101
+
102
+
103
+ .bt__controls-grid {
104
+ display: grid;
105
+ gap: 2rem;
106
+ position: relative;
107
+ z-index: 1;
108
+ }
109
+
110
+ @media (min-width: 640px) {
111
+ .bt__controls-grid {
112
+ grid-template-columns: 1fr 1fr;
113
+ gap: 3rem;
114
+ }
115
+ }
116
+
117
+ .bt__control-group {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 1.5rem;
121
+ }
122
+
123
+ .bt__control-header {
124
+ display: flex;
125
+ justify-content: space-between;
126
+ align-items: flex-end;
127
+ }
128
+
129
+ .bt__control-label {
130
+ font-weight: 700;
131
+ font-size: 0.75rem;
132
+ text-transform: uppercase;
133
+ letter-spacing: 0.15em;
134
+ color: var(--bt-muted);
135
+ }
136
+
137
+ .bt__value-display {
138
+ font-size: 2.25rem;
139
+ font-weight: 900;
140
+ color: var(--bt-text);
141
+ line-height: 1;
142
+ text-shadow: 0 0 15px rgba(255, 255, 255, 0.2);
143
+ }
144
+
145
+ @media (min-width: 768px) {
146
+ .bt__value-display {
147
+ font-size: 2.5rem;
148
+ }
149
+ }
150
+
151
+ .bt__value-unit {
152
+ font-size: 1rem;
153
+ font-weight: 400;
154
+ margin-left: 0.25rem;
155
+ opacity: 0.6;
156
+ }
157
+
158
+
159
+ .bt__range {
160
+ -webkit-appearance: none;
161
+ appearance: none;
162
+ width: 100%;
163
+ background: transparent;
164
+ cursor: pointer;
165
+ }
166
+
167
+ .bt__range::-webkit-slider-runnable-track {
168
+ height: 8px;
169
+ background: var(--bt-range-track);
170
+ border-radius: 4px;
171
+ border: 1px solid var(--bt-range-track-border);
172
+ }
173
+
174
+ .bt__range::-webkit-slider-thumb {
175
+ -webkit-appearance: none;
176
+ appearance: none;
177
+ height: 24px;
178
+ width: 24px;
179
+ background: var(--bt-text);
180
+ border-radius: 50%;
181
+ margin-top: -9px;
182
+ box-shadow: 0 0 15px rgba(255, 255, 255, 0.4);
183
+ transition: transform 0.2s, box-shadow 0.2s;
184
+ }
185
+
186
+ .bt__range::-webkit-slider-thumb:hover {
187
+ transform: scale(1.1);
188
+ box-shadow: 0 0 20px var(--bt-secondary);
189
+ }
190
+
191
+ .bt__range::-moz-range-track {
192
+ height: 8px;
193
+ background: var(--bt-range-track);
194
+ border-radius: 4px;
195
+ border: 1px solid var(--bt-range-track-border);
196
+ }
197
+
198
+ .bt__range::-moz-range-thumb {
199
+ height: 24px;
200
+ width: 24px;
201
+ background: var(--bt-text);
202
+ border-radius: 50%;
203
+ border: none;
204
+ box-shadow: 0 0 15px rgba(255, 255, 255, 0.4);
205
+ }
206
+
207
+
208
+ .bt__presets-wrap {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 1rem;
212
+ align-items: center;
213
+ position: relative;
214
+ z-index: 1;
215
+ }
216
+
217
+ .bt__beat-desc {
218
+ background: linear-gradient(90deg, var(--bt-primary), var(--bt-secondary));
219
+ -webkit-background-clip: text;
220
+ background-clip: text;
221
+ -webkit-text-fill-color: transparent;
222
+ font-weight: 600;
223
+ font-size: 1rem;
224
+ text-align: center;
225
+ }
226
+
227
+ .bt__presets {
228
+ display: flex;
229
+ flex-wrap: wrap;
230
+ gap: 0.75rem;
231
+ justify-content: center;
232
+ }
233
+
234
+ .bt__preset-btn {
235
+ background: var(--bt-glass);
236
+ border: 1px solid var(--bt-glass-border);
237
+ color: var(--bt-preset-color);
238
+ padding: 0.625rem 1.25rem;
239
+ border-radius: 100px;
240
+ font-size: 0.85rem;
241
+ font-weight: 600;
242
+ cursor: pointer;
243
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
244
+ }
245
+
246
+ @media (max-width: 640px) {
247
+ .bt__preset-btn {
248
+ padding: 0.5rem 0.75rem;
249
+ font-size: 0.75rem;
250
+ flex: 1 1 auto;
251
+ text-align: center;
252
+ }
253
+ }
254
+
255
+ .bt__preset-btn:hover {
256
+ border-color: var(--bt-secondary);
257
+ color: var(--bt-secondary);
258
+ background: rgba(0, 242, 255, 0.05);
259
+ }
260
+
261
+ .bt__preset-btn--active {
262
+ background: var(--bt-text);
263
+ color: var(--bt-bg);
264
+ border-color: var(--bt-text);
265
+ transform: scale(1.05);
266
+ box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
267
+ }
268
+
269
+
270
+ .bt__actions {
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: center;
274
+ gap: 2.5rem;
275
+ margin: 0.5rem 0;
276
+ position: relative;
277
+ z-index: 1;
278
+ }
279
+
280
+ @media (max-width: 640px) {
281
+ .bt__actions {
282
+ flex-direction: column;
283
+ gap: 1rem;
284
+ }
285
+ }
286
+
287
+ .bt__play-btn {
288
+ width: 6rem;
289
+ height: 6rem;
290
+ border-radius: 50%;
291
+ background: var(--bt-text);
292
+ border: none;
293
+ display: flex;
294
+ align-items: center;
295
+ justify-content: center;
296
+ cursor: pointer;
297
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
298
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
299
+ flex-shrink: 0;
300
+ }
301
+
302
+ @media (max-width: 640px) {
303
+ .bt__play-btn {
304
+ width: 5rem;
305
+ height: 5rem;
306
+ }
307
+ }
308
+
309
+ .bt__play-btn:hover {
310
+ transform: scale(1.1);
311
+ box-shadow: 0 0 40px rgba(255, 255, 255, 0.4);
312
+ }
313
+
314
+ .bt__play-btn--playing {
315
+ background: var(--bt-accent);
316
+ }
317
+
318
+ .bt__play-svg {
319
+ width: 2.5rem;
320
+ height: 2.5rem;
321
+ fill: var(--bt-bg);
322
+ }
323
+
324
+ .bt__play-btn--playing .bt__play-svg {
325
+ fill: white;
326
+ }
327
+
328
+ .bt__play-svg--hidden {
329
+ display: none;
330
+ }
331
+
332
+ .bt__strobe-btn {
333
+ background: transparent;
334
+ border: 2px solid var(--bt-strobe-border);
335
+ color: var(--bt-strobe-color);
336
+ padding: 1rem 2rem;
337
+ border-radius: 100px;
338
+ font-weight: 700;
339
+ text-transform: uppercase;
340
+ letter-spacing: 0.05em;
341
+ cursor: pointer;
342
+ transition: all 0.3s ease;
343
+ }
344
+
345
+ @media (max-width: 640px) {
346
+ .bt__strobe-btn {
347
+ padding: 0.75rem 1rem;
348
+ font-size: 0.85rem;
349
+ width: 100%;
350
+ box-sizing: border-box;
351
+ text-align: center;
352
+ }
353
+ }
354
+
355
+ .bt__strobe-btn:hover {
356
+ border-color: var(--bt-secondary);
357
+ background: rgba(0, 242, 255, 0.05);
358
+ }
359
+
360
+ .bt__strobe-btn--active {
361
+ background: var(--bt-secondary);
362
+ border-color: var(--bt-secondary);
363
+ color: var(--bt-bg);
364
+ box-shadow: 0 0 25px rgba(0, 242, 255, 0.4);
365
+ }
366
+
367
+
368
+ .bt__visualizer {
369
+ width: 100%;
370
+ height: 12rem;
371
+ background: var(--bt-visualizer-bg);
372
+ border-radius: 1.5rem;
373
+ position: relative;
374
+ overflow: hidden;
375
+ border: 1px solid rgba(255, 255, 255, 0.05);
376
+ }
377
+
378
+ @media (max-width: 640px) {
379
+ .bt__visualizer {
380
+ height: 7.5rem;
381
+ border-radius: 1rem;
382
+ }
383
+ }
384
+
385
+ .bt__strobe {
386
+ position: absolute;
387
+ inset: 0;
388
+ background: white;
389
+ opacity: 0;
390
+ pointer-events: none;
391
+ z-index: 2;
392
+ }
393
+
394
+ .bt__strobe--active {
395
+ animation: bt-strobe var(--bt-strobe-duration, 0.25s) infinite;
396
+ }
397
+
398
+ @keyframes bt-strobe {
399
+ 0% { opacity: 0.9; }
400
+ 2% { opacity: 0; }
401
+ 100% { opacity: 0; }
402
+ }
403
+
404
+ .bt__canvas {
405
+ width: 100%;
406
+ height: 100%;
407
+ filter: blur(2px);
408
+ }
409
+
410
+
411
+ .bt__warning {
412
+ background: var(--bt-warning-bg);
413
+ border: 1px solid var(--bt-warning-border);
414
+ padding: 1.25rem;
415
+ border-radius: 1rem;
416
+ font-size: 0.8rem;
417
+ color: var(--bt-warning-text);
418
+ line-height: 1.6;
419
+ position: relative;
420
+ z-index: 1;
421
+ }
422
+
423
+ .bt__warning-title {
424
+ color: var(--bt-warning-strong);
425
+ text-transform: uppercase;
426
+ letter-spacing: 0.05em;
427
+ display: block;
428
+ margin-bottom: 0.5rem;
429
+ font-size: 0.75rem;
430
+ }