@jjlmoya/utils-home 1.26.0 → 1.27.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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +4 -1
  3. package/src/tests/locale_completeness.test.ts +2 -2
  4. package/src/tests/tool_validation.test.ts +2 -2
  5. package/src/tool/vampireDrawSimulator/bibliography.astro +14 -0
  6. package/src/tool/vampireDrawSimulator/bibliography.ts +14 -0
  7. package/src/tool/vampireDrawSimulator/component.astro +320 -0
  8. package/src/tool/vampireDrawSimulator/entry.ts +29 -0
  9. package/src/tool/vampireDrawSimulator/i18n/de.ts +211 -0
  10. package/src/tool/vampireDrawSimulator/i18n/en.ts +211 -0
  11. package/src/tool/vampireDrawSimulator/i18n/es.ts +211 -0
  12. package/src/tool/vampireDrawSimulator/i18n/fr.ts +211 -0
  13. package/src/tool/vampireDrawSimulator/i18n/id.ts +211 -0
  14. package/src/tool/vampireDrawSimulator/i18n/it.ts +211 -0
  15. package/src/tool/vampireDrawSimulator/i18n/ja.ts +211 -0
  16. package/src/tool/vampireDrawSimulator/i18n/ko.ts +211 -0
  17. package/src/tool/vampireDrawSimulator/i18n/nl.ts +211 -0
  18. package/src/tool/vampireDrawSimulator/i18n/pl.ts +211 -0
  19. package/src/tool/vampireDrawSimulator/i18n/pt.ts +211 -0
  20. package/src/tool/vampireDrawSimulator/i18n/ru.ts +211 -0
  21. package/src/tool/vampireDrawSimulator/i18n/sv.ts +211 -0
  22. package/src/tool/vampireDrawSimulator/i18n/tr.ts +211 -0
  23. package/src/tool/vampireDrawSimulator/i18n/zh.ts +211 -0
  24. package/src/tool/vampireDrawSimulator/index.ts +9 -0
  25. package/src/tool/vampireDrawSimulator/logic.ts +31 -0
  26. package/src/tool/vampireDrawSimulator/seo.astro +15 -0
  27. package/src/tool/vampireDrawSimulator/ui.ts +32 -0
  28. package/src/tool/vampireDrawSimulator/vampire-draw-simulator.css +542 -0
  29. package/src/tool/wallPaintingCalculator/bibliography.ts +4 -4
  30. package/src/tools.ts +2 -0
@@ -0,0 +1,542 @@
1
+ .vamp-wrapper {
2
+ --vamp-p: #8b5cf6;
3
+ --vamp-success: #22c55e;
4
+ --vamp-warn: #f59e0b;
5
+ --vamp-danger: #ef4444;
6
+ --vamp-extreme: #b91c1c;
7
+ --vamp-surface: var(--bg-surface);
8
+ --vamp-border: var(--border-color);
9
+ --vamp-text: var(--text-main);
10
+ --vamp-muted: var(--text-muted);
11
+ --vamp-page: var(--bg-page);
12
+ --vamp-base: var(--text-base);
13
+
14
+ width: 100%;
15
+ padding: 1rem 0;
16
+ }
17
+
18
+ /* ---- SINGLE CARD ---- */
19
+ .vamp-card {
20
+ width: 100%;
21
+ max-width: 640px;
22
+ margin: 0 auto;
23
+ background: var(--vamp-surface);
24
+ border: 1px solid var(--vamp-border);
25
+ border-radius: 24px;
26
+ overflow: hidden;
27
+ display: flex;
28
+ flex-direction: column;
29
+ }
30
+
31
+ /* ---- HERO ---- */
32
+ .vamp-hero {
33
+ text-align: center;
34
+ padding: 1.75rem 1.25rem 1.25rem;
35
+ border-bottom: 1px solid var(--vamp-border);
36
+ }
37
+
38
+ .vamp-result-badge {
39
+ display: inline-block;
40
+ font-size: 0.6rem;
41
+ font-weight: 900;
42
+ text-transform: uppercase;
43
+ letter-spacing: 0.22em;
44
+ color: var(--vamp-p);
45
+ margin-bottom: 0.625rem;
46
+ padding: 0.3rem 0.75rem;
47
+ border-radius: 999px;
48
+ border: 1px solid rgba(139, 92, 246, 0.22);
49
+ background: rgba(139, 92, 246, 0.05);
50
+ }
51
+
52
+ .vamp-annual-label {
53
+ font-size: 0.625rem;
54
+ font-weight: 800;
55
+ text-transform: uppercase;
56
+ letter-spacing: 0.2em;
57
+ color: var(--vamp-muted);
58
+ margin: 0 0 0.5rem;
59
+ }
60
+
61
+ .vamp-annual-value {
62
+ font-size: clamp(2.8rem, 8vw, 4.5rem);
63
+ font-weight: 900;
64
+ line-height: 1;
65
+ margin: 0;
66
+ color: var(--vamp-base);
67
+ }
68
+
69
+ .vamp-annual-unit {
70
+ font-size: clamp(1.2rem, 3vw, 1.8rem);
71
+ font-weight: 300;
72
+ color: var(--vamp-muted);
73
+ }
74
+
75
+ .vamp-category-badge {
76
+ display: inline-block;
77
+ margin-top: 0.75rem;
78
+ font-size: 0.7rem;
79
+ font-weight: 800;
80
+ text-transform: uppercase;
81
+ letter-spacing: 0.14em;
82
+ padding: 0.4rem 1rem;
83
+ border-radius: 999px;
84
+ border: 1px solid;
85
+ }
86
+
87
+ .vamp-cat-low {
88
+ color: var(--vamp-success);
89
+ border-color: rgba(34, 197, 94, 0.35);
90
+ background: rgba(34, 197, 94, 0.07);
91
+ }
92
+
93
+ .vamp-cat-moderate {
94
+ color: #b45309;
95
+ border-color: rgba(245, 158, 11, 0.35);
96
+ background: rgba(245, 158, 11, 0.07);
97
+ }
98
+
99
+ .vamp-cat-high {
100
+ color: var(--vamp-danger);
101
+ border-color: rgba(239, 68, 68, 0.35);
102
+ background: rgba(239, 68, 68, 0.07);
103
+ }
104
+
105
+ .vamp-cat-extreme {
106
+ color: var(--vamp-extreme);
107
+ border-color: rgba(185, 28, 28, 0.4);
108
+ background: rgba(185, 28, 28, 0.08);
109
+ }
110
+
111
+ /* ---- STATS ---- */
112
+ .vamp-stats {
113
+ display: grid;
114
+ grid-template-columns: repeat(3, 1fr);
115
+ gap: 0.5rem;
116
+ margin-top: 1rem;
117
+ }
118
+
119
+ .vamp-stat {
120
+ text-align: center;
121
+ padding: 0.625rem 0.375rem;
122
+ border-radius: 14px;
123
+ background: var(--vamp-page);
124
+ border: 1px solid var(--vamp-border);
125
+ transition: transform 0.2s, border-color 0.2s;
126
+ }
127
+
128
+ .vamp-stat:hover {
129
+ transform: translateY(-2px);
130
+ border-color: rgba(139, 92, 246, 0.25);
131
+ }
132
+
133
+ .vamp-stat-label {
134
+ font-size: 0.55rem;
135
+ font-weight: 800;
136
+ text-transform: uppercase;
137
+ letter-spacing: 0.13em;
138
+ color: var(--vamp-muted);
139
+ margin: 0 0 0.25rem;
140
+ }
141
+
142
+ .vamp-stat-value {
143
+ font-size: 0.95rem;
144
+ font-weight: 800;
145
+ color: var(--vamp-text);
146
+ margin: 0;
147
+ }
148
+
149
+ /* ---- BODY (Devices) ---- */
150
+ .vamp-body {
151
+ padding: 1.25rem;
152
+ border-bottom: 1px solid var(--vamp-border);
153
+ }
154
+
155
+ .vamp-section-title {
156
+ font-size: 0.65rem;
157
+ font-weight: 900;
158
+ text-transform: uppercase;
159
+ letter-spacing: 0.18em;
160
+ color: var(--vamp-p);
161
+ margin: 0 0 0.875rem;
162
+ }
163
+
164
+ .vamp-device-list {
165
+ display: flex;
166
+ flex-direction: column;
167
+ gap: 0.4rem;
168
+ }
169
+
170
+ .vamp-device-row {
171
+ display: grid;
172
+ grid-template-columns: 1fr auto 60px auto auto;
173
+ align-items: center;
174
+ gap: 0.4rem;
175
+ padding: 0.55rem 0.75rem;
176
+ border-radius: 12px;
177
+ border: 1px solid var(--vamp-border);
178
+ background: var(--vamp-page);
179
+ transition: all 0.2s ease;
180
+ }
181
+
182
+ .vamp-device-row:hover {
183
+ border-color: rgba(139, 92, 246, 0.3);
184
+ transform: translateX(3px);
185
+ }
186
+
187
+ .vamp-device-name {
188
+ font-size: 0.8rem;
189
+ font-weight: 700;
190
+ color: var(--vamp-text);
191
+ white-space: nowrap;
192
+ overflow: hidden;
193
+ text-overflow: ellipsis;
194
+ }
195
+
196
+ .vamp-device-watts {
197
+ font-size: 0.7rem;
198
+ font-weight: 600;
199
+ color: var(--vamp-muted);
200
+ white-space: nowrap;
201
+ }
202
+
203
+ .vamp-device-hours {
204
+ width: 100%;
205
+ font-size: 0.85rem;
206
+ font-weight: 800;
207
+ color: var(--vamp-text);
208
+ background: transparent;
209
+ border: none;
210
+ border-bottom: 1px solid var(--vamp-border);
211
+ text-align: center;
212
+ outline: none;
213
+ padding: 0.15rem 0;
214
+ transition: border-color 0.2s;
215
+ }
216
+
217
+ .vamp-device-hours:focus {
218
+ border-color: var(--vamp-p);
219
+ }
220
+
221
+ .vamp-remove-btn {
222
+ padding: 0.25rem 0.5rem;
223
+ border-radius: 8px;
224
+ border: none;
225
+ background: rgba(239, 68, 68, 0.06);
226
+ color: var(--vamp-danger);
227
+ font-size: 0.65rem;
228
+ font-weight: 700;
229
+ cursor: pointer;
230
+ transition: all 0.2s;
231
+ white-space: nowrap;
232
+ }
233
+
234
+ .vamp-remove-btn:hover {
235
+ background: rgba(239, 68, 68, 0.14);
236
+ }
237
+
238
+ .vamp-add-btn {
239
+ width: 100%;
240
+ margin-top: 0.625rem;
241
+ padding: 0.625rem;
242
+ border-radius: 12px;
243
+ border: 1px dashed rgba(139, 92, 246, 0.28);
244
+ background: rgba(139, 92, 246, 0.03);
245
+ color: var(--vamp-p);
246
+ font-size: 0.75rem;
247
+ font-weight: 700;
248
+ cursor: pointer;
249
+ transition: all 0.2s;
250
+ display: flex;
251
+ align-items: center;
252
+ justify-content: center;
253
+ gap: 0.375rem;
254
+ }
255
+
256
+ .vamp-add-btn:hover {
257
+ background: rgba(139, 92, 246, 0.08);
258
+ border-style: solid;
259
+ }
260
+
261
+ /* ---- FOOTER (Price + Currency) ---- */
262
+ .vamp-footer {
263
+ display: grid;
264
+ grid-template-columns: 1fr 1fr;
265
+ gap: 0;
266
+ padding: 1rem 1.25rem;
267
+ }
268
+
269
+ .vamp-field {
270
+ display: flex;
271
+ flex-direction: column;
272
+ gap: 0.4rem;
273
+ padding-right: 1rem;
274
+ border-right: 1px solid var(--vamp-border);
275
+ }
276
+
277
+ .vamp-field:last-child {
278
+ border-right: none;
279
+ padding-right: 0;
280
+ padding-left: 1rem;
281
+ }
282
+
283
+ .vamp-label {
284
+ font-size: 0.6rem;
285
+ font-weight: 900;
286
+ text-transform: uppercase;
287
+ letter-spacing: 0.16em;
288
+ color: var(--vamp-muted);
289
+ }
290
+
291
+ .vamp-price-row {
292
+ display: flex;
293
+ align-items: baseline;
294
+ gap: 0.4rem;
295
+ }
296
+
297
+ .vamp-price-input {
298
+ width: 100%;
299
+ font-size: 1.375rem;
300
+ font-weight: 900;
301
+ color: var(--vamp-text);
302
+ background: transparent;
303
+ border: none;
304
+ border-bottom: 2px solid var(--vamp-border);
305
+ padding: 0.15rem 0;
306
+ outline: none;
307
+ transition: border-color 0.2s;
308
+ }
309
+
310
+ .vamp-price-input:focus {
311
+ border-color: var(--vamp-p);
312
+ }
313
+
314
+ .vamp-price-unit {
315
+ font-size: 0.8rem;
316
+ font-weight: 600;
317
+ color: var(--vamp-muted);
318
+ white-space: nowrap;
319
+ }
320
+
321
+ .vamp-currency-toggle {
322
+ gap: 0.4rem;
323
+ }
324
+
325
+ .vamp-currency-label {
326
+ font-size: 0.6rem;
327
+ font-weight: 900;
328
+ text-transform: uppercase;
329
+ letter-spacing: 0.16em;
330
+ color: var(--vamp-muted);
331
+ }
332
+
333
+ .vamp-currency-btns {
334
+ display: flex;
335
+ gap: 0.3rem;
336
+ }
337
+
338
+ .vamp-currency-btn {
339
+ flex: 1;
340
+ padding: 0.4rem 0.2rem;
341
+ border-radius: 8px;
342
+ border: 1px solid var(--vamp-border);
343
+ background: var(--vamp-page);
344
+ color: var(--vamp-muted);
345
+ font-size: 0.8rem;
346
+ font-weight: 700;
347
+ cursor: pointer;
348
+ transition: all 0.2s;
349
+ }
350
+
351
+ .vamp-currency-btn:hover {
352
+ border-color: var(--vamp-p);
353
+ color: var(--vamp-text);
354
+ }
355
+
356
+ .vamp-currency-active {
357
+ background: var(--vamp-p);
358
+ border-color: var(--vamp-p);
359
+ color: #fff;
360
+ }
361
+
362
+ /* ---- MODAL ---- */
363
+ .vamp-modal {
364
+ position: fixed;
365
+ inset: 0;
366
+ z-index: 1000;
367
+ display: flex;
368
+ align-items: center;
369
+ justify-content: center;
370
+ padding: 1rem;
371
+ }
372
+
373
+ .vamp-modal-backdrop {
374
+ position: absolute;
375
+ inset: 0;
376
+ background: rgba(0, 0, 0, 0.45);
377
+ backdrop-filter: blur(4px);
378
+ }
379
+
380
+ .vamp-modal-card {
381
+ position: relative;
382
+ width: 100%;
383
+ max-width: 380px;
384
+ background: var(--vamp-surface);
385
+ border: 1px solid var(--vamp-border);
386
+ border-radius: 24px;
387
+ padding: 1.5rem;
388
+ box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.45);
389
+ animation: vamp-modal-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);
390
+ }
391
+
392
+ @keyframes vamp-modal-in {
393
+ from {
394
+ opacity: 0;
395
+ transform: translateY(16px) scale(0.97);
396
+ }
397
+ to {
398
+ opacity: 1;
399
+ transform: translateY(0) scale(1);
400
+ }
401
+ }
402
+
403
+ .vamp-modal-title {
404
+ font-size: 1rem;
405
+ font-weight: 800;
406
+ color: var(--vamp-text);
407
+ margin: 0 0 1rem;
408
+ text-align: center;
409
+ }
410
+
411
+ .vamp-modal-body {
412
+ display: flex;
413
+ flex-direction: column;
414
+ gap: 0.875rem;
415
+ margin-bottom: 1.25rem;
416
+ }
417
+
418
+ .vamp-modal-field {
419
+ display: flex;
420
+ flex-direction: column;
421
+ gap: 0.3rem;
422
+ }
423
+
424
+ .vamp-modal-label {
425
+ font-size: 0.6rem;
426
+ font-weight: 800;
427
+ text-transform: uppercase;
428
+ letter-spacing: 0.13em;
429
+ color: var(--vamp-muted);
430
+ }
431
+
432
+ .vamp-modal-input {
433
+ width: 100%;
434
+ font-size: 0.95rem;
435
+ font-weight: 700;
436
+ color: var(--vamp-text);
437
+ background: var(--vamp-page);
438
+ border: 1px solid var(--vamp-border);
439
+ border-radius: 12px;
440
+ padding: 0.55rem 0.75rem;
441
+ outline: none;
442
+ transition: border-color 0.2s, box-shadow 0.2s;
443
+ }
444
+
445
+ .vamp-modal-input:focus {
446
+ border-color: var(--vamp-p);
447
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.12);
448
+ }
449
+
450
+ .vamp-modal-actions {
451
+ display: flex;
452
+ gap: 0.625rem;
453
+ }
454
+
455
+ .vamp-modal-btn {
456
+ flex: 1;
457
+ padding: 0.65rem;
458
+ border-radius: 12px;
459
+ font-size: 0.8rem;
460
+ font-weight: 800;
461
+ cursor: pointer;
462
+ transition: all 0.2s;
463
+ border: 1px solid transparent;
464
+ }
465
+
466
+ .vamp-modal-btn-primary {
467
+ background: var(--vamp-p);
468
+ color: #fff;
469
+ border-color: var(--vamp-p);
470
+ }
471
+
472
+ .vamp-modal-btn-primary:hover {
473
+ filter: brightness(1.08);
474
+ transform: translateY(-1px);
475
+ }
476
+
477
+ .vamp-modal-btn-secondary {
478
+ background: var(--vamp-page);
479
+ color: var(--vamp-muted);
480
+ border-color: var(--vamp-border);
481
+ }
482
+
483
+ .vamp-modal-btn-secondary:hover {
484
+ color: var(--vamp-text);
485
+ border-color: var(--vamp-p);
486
+ }
487
+
488
+ /* ---- RESPONSIVE ---- */
489
+ @media (max-width: 520px) {
490
+ .vamp-wrapper {
491
+ padding: 0.75rem 0;
492
+ }
493
+
494
+ .vamp-card {
495
+ border-radius: 20px;
496
+ }
497
+
498
+ .vamp-hero {
499
+ padding: 1.5rem 1rem 1rem;
500
+ }
501
+
502
+ .vamp-stats {
503
+ grid-template-columns: 1fr;
504
+ gap: 0.4rem;
505
+ }
506
+
507
+ .vamp-body {
508
+ padding: 1rem;
509
+ }
510
+
511
+ .vamp-footer {
512
+ grid-template-columns: 1fr;
513
+ padding: 1rem;
514
+ gap: 1rem;
515
+ }
516
+
517
+ .vamp-field {
518
+ border-right: none;
519
+ border-bottom: 1px solid var(--vamp-border);
520
+ padding-right: 0;
521
+ padding-bottom: 1rem;
522
+ }
523
+
524
+ .vamp-field:last-child {
525
+ border-bottom: none;
526
+ padding-left: 0;
527
+ padding-bottom: 0;
528
+ }
529
+
530
+ .vamp-device-row {
531
+ grid-template-columns: 1fr auto;
532
+ row-gap: 0.35rem;
533
+ }
534
+
535
+ .vamp-device-row .vamp-device-name {
536
+ grid-column: 1 / -1;
537
+ }
538
+
539
+ .vamp-device-hours {
540
+ width: 56px;
541
+ }
542
+ }
@@ -1,14 +1,14 @@
1
1
  export const bibliography = [
2
2
  {
3
- name: 'Paint Coverage and Application Guide: Sherwin-Williams',
4
- url: 'https://www.sherwin-williams.com/homeowners/how-to/paint-coverage-and-application',
3
+ name: 'Paint Coverage and Application Guide',
4
+ url: 'https://www.sherwin-williams.com/home-builders/color/color-education/sw-article-pro-hueandhide',
5
5
  },
6
6
  {
7
7
  name: 'How Much Paint Do I Need: Benjamin Moore',
8
- url: 'https://www.benjaminmoore.com/en-us/how-to/how-much-paint-do-i-need',
8
+ url: 'https://www.benjaminmoore.com/en-us/paint-calculator',
9
9
  },
10
10
  {
11
11
  name: 'Paint Calculator and Coverage Estimator: Dulux',
12
- url: 'https://www.dulux.co.uk/en/diy/paint-calculator',
12
+ url: 'https://www.dulux.co.uk/en/paint-calculator',
13
13
  },
14
14
  ];
package/src/tools.ts CHANGED
@@ -10,6 +10,7 @@ import { HEATING_COMPARATOR_TOOL } from './tool/heatingComparator/index';
10
10
  import { WIFI_RANGE_SIMULATOR_TOOL } from './tool/wifiRangeSimulator/index';
11
11
  import { AC_TONNAGE_CALCULATOR_TOOL } from './tool/acTonnageCalculator/index';
12
12
  import { WALL_PAINTING_CALCULATOR_TOOL } from './tool/wallPaintingCalculator/index';
13
+ import { VAMPIRE_DRAW_SIMULATOR_TOOL } from './tool/vampireDrawSimulator/index';
13
14
 
14
15
  export const ALL_TOOLS: ToolDefinition[] = [
15
16
  QR_GENERATOR_TOOL,
@@ -22,5 +23,6 @@ export const ALL_TOOLS: ToolDefinition[] = [
22
23
  WIFI_RANGE_SIMULATOR_TOOL,
23
24
  AC_TONNAGE_CALCULATOR_TOOL,
24
25
  WALL_PAINTING_CALCULATOR_TOOL,
26
+ VAMPIRE_DRAW_SIMULATOR_TOOL,
25
27
  ];
26
28