@jjlmoya/utils-home 1.14.0 → 1.16.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 (32) hide show
  1. package/package.json +7 -4
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/entries.ts +23 -0
  4. package/src/tool/dewPointCalculator/component.astro +0 -232
  5. package/src/tool/dewPointCalculator/dew-point-calculator.css +230 -0
  6. package/src/tool/dewPointCalculator/entry.ts +32 -0
  7. package/src/tool/dewPointCalculator/index.ts +2 -34
  8. package/src/tool/heatingComparator/component.astro +0 -269
  9. package/src/tool/heatingComparator/entry.ts +30 -0
  10. package/src/tool/heatingComparator/heating-consumption-comparator.css +267 -0
  11. package/src/tool/heatingComparator/index.ts +2 -32
  12. package/src/tool/ledSavingCalculator/component.astro +0 -305
  13. package/src/tool/ledSavingCalculator/entry.ts +31 -0
  14. package/src/tool/ledSavingCalculator/index.ts +2 -33
  15. package/src/tool/ledSavingCalculator/led-saving-calculator.css +303 -0
  16. package/src/tool/projectorCalculator/component.astro +0 -359
  17. package/src/tool/projectorCalculator/entry.ts +31 -0
  18. package/src/tool/projectorCalculator/index.ts +2 -33
  19. package/src/tool/projectorCalculator/projector-throw-calculator.css +357 -0
  20. package/src/tool/qrGenerator/component.astro +0 -266
  21. package/src/tool/qrGenerator/entry.ts +30 -0
  22. package/src/tool/qrGenerator/index.ts +2 -32
  23. package/src/tool/qrGenerator/qr-generator.css +264 -0
  24. package/src/tool/solarCalculator/component.astro +0 -298
  25. package/src/tool/solarCalculator/entry.ts +30 -0
  26. package/src/tool/solarCalculator/index.ts +2 -32
  27. package/src/tool/solarCalculator/solar-panel-calculator.css +296 -0
  28. package/src/tool/tariffComparator/component.astro +0 -337
  29. package/src/tool/tariffComparator/electricity-tariff-comparator.css +335 -0
  30. package/src/tool/tariffComparator/entry.ts +31 -0
  31. package/src/tool/tariffComparator/index.ts +2 -33
  32. package/src/tools.ts +1 -1
@@ -0,0 +1,357 @@
1
+ .proj-wrapper {
2
+ --proj-p: #06b6d4;
3
+
4
+ width: 100%;
5
+ padding: 1rem 0;
6
+ }
7
+
8
+ .proj-card {
9
+ background: var(--bg-surface);
10
+ width: calc(100% - 24px);
11
+ max-width: 960px;
12
+ margin: 0 auto;
13
+ border-radius: 24px;
14
+ overflow: hidden;
15
+ display: flex;
16
+ flex-direction: column;
17
+ border: 1px solid var(--border-color);
18
+ color: var(--text-main);
19
+ }
20
+
21
+ @media (min-width: 768px) {
22
+ .proj-card {
23
+ flex-direction: row;
24
+ min-height: 580px;
25
+ }
26
+ }
27
+
28
+ .proj-left {
29
+ flex: 0 0 auto;
30
+ width: 100%;
31
+ padding: 32px;
32
+ border-bottom: 1px solid var(--border-color);
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 24px;
36
+ }
37
+
38
+ @media (min-width: 768px) {
39
+ .proj-left {
40
+ width: 360px;
41
+ border-bottom: none;
42
+ border-right: 1px solid var(--border-color);
43
+ }
44
+ }
45
+
46
+ .proj-right {
47
+ flex: 1;
48
+ background: #020617;
49
+ position: relative;
50
+ overflow: hidden;
51
+ display: flex;
52
+ flex-direction: column;
53
+ min-height: 380px;
54
+ }
55
+
56
+ .proj-viz-dots {
57
+ position: absolute;
58
+ inset: 0;
59
+ opacity: 0.15;
60
+ pointer-events: none;
61
+ background-image: radial-gradient(#334155 1px, transparent 1px);
62
+ background-size: 30px 30px;
63
+ }
64
+
65
+ .proj-sim-badge {
66
+ position: relative;
67
+ z-index: 1;
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 6px;
71
+ padding: 16px 20px 0;
72
+ font-size: 0.6rem;
73
+ font-weight: 900;
74
+ text-transform: uppercase;
75
+ letter-spacing: 0.18em;
76
+ color: #94a3b8;
77
+ }
78
+
79
+ .proj-sim-dot {
80
+ width: 7px;
81
+ height: 7px;
82
+ border-radius: 50%;
83
+ background: var(--proj-p);
84
+ animation: proj-pulse 2s infinite;
85
+ }
86
+
87
+ @keyframes proj-pulse {
88
+ 0%, 100% { opacity: 1; }
89
+ 50% { opacity: 0.3; }
90
+ }
91
+
92
+ .proj-lens-pulse {
93
+ animation: proj-pulse 2s infinite;
94
+ }
95
+
96
+ .proj-svg {
97
+ flex: 1;
98
+ width: 100%;
99
+ position: relative;
100
+ z-index: 1;
101
+ }
102
+
103
+ .proj-header {
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: 4px;
107
+ }
108
+
109
+ .proj-title {
110
+ font-size: 1.25rem;
111
+ font-weight: 900;
112
+ color: var(--text-main);
113
+ margin: 0;
114
+ }
115
+
116
+ .proj-subtitle {
117
+ font-size: 0.8125rem;
118
+ color: var(--text-muted);
119
+ margin: 0;
120
+ }
121
+
122
+ .proj-field {
123
+ display: flex;
124
+ flex-direction: column;
125
+ gap: 10px;
126
+ }
127
+
128
+ .proj-field-header {
129
+ display: flex;
130
+ justify-content: space-between;
131
+ align-items: center;
132
+ }
133
+
134
+ .proj-label {
135
+ font-size: 0.6875rem;
136
+ font-weight: 700;
137
+ text-transform: uppercase;
138
+ letter-spacing: 0.1em;
139
+ color: var(--proj-p);
140
+ }
141
+
142
+ .proj-unit {
143
+ font-size: 0.75rem;
144
+ color: var(--text-muted);
145
+ }
146
+
147
+ .proj-slider {
148
+ width: 100%;
149
+ height: 6px;
150
+ accent-color: var(--proj-p);
151
+ cursor: pointer;
152
+ border-radius: 9999px;
153
+ }
154
+
155
+ .proj-number-row {
156
+ position: relative;
157
+ display: flex;
158
+ align-items: center;
159
+ }
160
+
161
+ .proj-number-input {
162
+ width: 100%;
163
+ font-size: 3rem;
164
+ font-weight: 900;
165
+ color: var(--text-main);
166
+ background: transparent;
167
+ border: none;
168
+ border-bottom: 2px solid var(--border-color);
169
+ padding: 4px 2rem 4px 0;
170
+ outline: none;
171
+ transition: border-color 0.2s;
172
+ }
173
+
174
+ .proj-number-input:focus {
175
+ border-color: var(--proj-p);
176
+ }
177
+
178
+ .proj-number-unit {
179
+ position: absolute;
180
+ right: 4px;
181
+ bottom: 8px;
182
+ font-size: 1.5rem;
183
+ color: var(--text-muted);
184
+ font-weight: 300;
185
+ }
186
+
187
+ .proj-ratio-grid {
188
+ display: grid;
189
+ grid-template-columns: repeat(3, 1fr);
190
+ gap: 8px;
191
+ }
192
+
193
+ .proj-ratio-btn {
194
+ display: flex;
195
+ flex-direction: column;
196
+ align-items: center;
197
+ gap: 4px;
198
+ padding: 10px 8px;
199
+ border-radius: 12px;
200
+ border: 1px solid var(--border-color);
201
+ background: var(--bg-surface);
202
+ color: var(--text-muted);
203
+ font-size: 0.8125rem;
204
+ font-weight: 700;
205
+ cursor: pointer;
206
+ transition: all 0.2s;
207
+ }
208
+
209
+ .proj-ratio-btn:hover {
210
+ border-color: var(--proj-p);
211
+ color: var(--text-main);
212
+ }
213
+
214
+ .proj-ratio-active {
215
+ background: var(--proj-p);
216
+ color: #fff;
217
+ border-color: var(--proj-p);
218
+ box-shadow: 0 4px 14px rgba(6, 182, 212, 0.35);
219
+ }
220
+
221
+ .proj-ratio-icon {
222
+ display: block;
223
+ border: 2px solid currentcolor;
224
+ border-radius: 2px;
225
+ opacity: 0.6;
226
+ }
227
+
228
+ .proj-ratio-active .proj-ratio-icon {
229
+ opacity: 1;
230
+ border-color: #fff;
231
+ }
232
+
233
+ .ratio-169 {
234
+ width: 28px;
235
+ height: 16px;
236
+ }
237
+
238
+ .ratio-219 {
239
+ width: 36px;
240
+ height: 14px;
241
+ }
242
+
243
+ .ratio-43 {
244
+ width: 20px;
245
+ height: 16px;
246
+ }
247
+
248
+ .proj-ratio-sub {
249
+ font-size: 0.625rem;
250
+ font-weight: 500;
251
+ opacity: 0.75;
252
+ }
253
+
254
+ .proj-hint-wrap {
255
+ position: relative;
256
+ }
257
+
258
+ .proj-hint-icon {
259
+ width: 16px;
260
+ height: 16px;
261
+ color: var(--text-muted);
262
+ cursor: help;
263
+ }
264
+
265
+ .proj-hint-tooltip {
266
+ position: absolute;
267
+ bottom: calc(100% + 6px);
268
+ right: 0;
269
+ width: 220px;
270
+ background: #1e293b;
271
+ color: #e2e8f0;
272
+ font-size: 0.75rem;
273
+ font-weight: 400;
274
+ padding: 10px 12px;
275
+ border-radius: 10px;
276
+ box-shadow: 0 8px 24px rgba(0,0,0,0.3);
277
+ opacity: 0;
278
+ pointer-events: none;
279
+ transition: opacity 0.15s;
280
+ z-index: 10;
281
+ line-height: 1.5;
282
+ }
283
+
284
+ .proj-hint-wrap:hover .proj-hint-tooltip {
285
+ opacity: 1;
286
+ }
287
+
288
+ .proj-throw-row {
289
+ position: relative;
290
+ display: flex;
291
+ align-items: center;
292
+ }
293
+
294
+ .proj-throw-input {
295
+ width: 100%;
296
+ font-size: 2.5rem;
297
+ font-weight: 900;
298
+ color: var(--text-main);
299
+ background: transparent;
300
+ border: none;
301
+ border-bottom: 2px solid var(--border-color);
302
+ padding: 4px 3rem 4px 0;
303
+ outline: none;
304
+ transition: border-color 0.2s;
305
+ }
306
+
307
+ .proj-throw-input:focus {
308
+ border-color: var(--proj-p);
309
+ }
310
+
311
+ .proj-throw-unit {
312
+ position: absolute;
313
+ right: 4px;
314
+ bottom: 10px;
315
+ font-size: 1.25rem;
316
+ color: var(--text-muted);
317
+ }
318
+
319
+ .proj-results {
320
+ background: rgba(6, 182, 212, 0.06);
321
+ border: 1px solid rgba(6, 182, 212, 0.15);
322
+ border-radius: 16px;
323
+ padding: 18px;
324
+ }
325
+
326
+ .proj-results-grid {
327
+ display: grid;
328
+ grid-template-columns: 1fr 1fr;
329
+ gap: 12px;
330
+ margin-bottom: 14px;
331
+ padding-bottom: 14px;
332
+ border-bottom: 1px solid rgba(6, 182, 212, 0.15);
333
+ }
334
+
335
+ .proj-res-label {
336
+ font-size: 0.625rem;
337
+ font-weight: 900;
338
+ text-transform: uppercase;
339
+ letter-spacing: 0.12em;
340
+ color: var(--proj-p);
341
+ margin: 0 0 4px;
342
+ }
343
+
344
+ .proj-res-val {
345
+ font-size: 1.125rem;
346
+ font-weight: 700;
347
+ color: var(--text-main);
348
+ margin: 0;
349
+ }
350
+
351
+ .proj-distance-val {
352
+ font-size: 2.5rem;
353
+ font-weight: 900;
354
+ color: var(--text-main);
355
+ margin: 0;
356
+ line-height: 1;
357
+ }
@@ -231,269 +231,3 @@ const qrUI = ui as QRGeneratorUI;
231
231
  init();
232
232
  </script>
233
233
 
234
- <style>
235
- .qr-wrapper {
236
- --qr-p: #3b82f6;
237
-
238
- width: 100%;
239
- padding: 1rem 0;
240
- }
241
-
242
- .qr-card {
243
- background: var(--bg-surface);
244
- width: calc(100% - 24px);
245
- max-width: 900px;
246
- margin: 0 auto;
247
- border-radius: 24px;
248
- overflow: hidden;
249
- display: flex;
250
- flex-direction: column;
251
- border: 1px solid var(--border-color);
252
- color: var(--text-main);
253
- }
254
-
255
- @media (min-width: 768px) {
256
- .qr-card {
257
- flex-direction: row;
258
- min-height: 520px;
259
- }
260
- }
261
-
262
- .qr-left {
263
- flex: 1;
264
- padding: 32px;
265
- border-bottom: 1px solid var(--border-color);
266
- display: flex;
267
- flex-direction: column;
268
- gap: 24px;
269
- }
270
-
271
- @media (min-width: 768px) {
272
- .qr-left {
273
- border-bottom: none;
274
- border-right: 1px solid var(--border-color);
275
- }
276
- }
277
-
278
- .qr-right {
279
- flex: 0 0 auto;
280
- width: 100%;
281
- background: var(--bg-muted);
282
- padding: 40px 32px;
283
- display: flex;
284
- flex-direction: column;
285
- align-items: center;
286
- justify-content: center;
287
- gap: 24px;
288
- position: relative;
289
- }
290
-
291
- @media (min-width: 768px) {
292
- .qr-right {
293
- width: 340px;
294
- }
295
- }
296
-
297
- .tab-bar {
298
- display: flex;
299
- background: var(--bg-muted);
300
- padding: 4px;
301
- border-radius: 14px;
302
- gap: 2px;
303
- }
304
-
305
- .tab-btn {
306
- flex: 1;
307
- padding: 10px;
308
- border: none;
309
- background: transparent;
310
- border-radius: 10px;
311
- font-size: 11px;
312
- font-weight: 800;
313
- text-transform: uppercase;
314
- letter-spacing: 0.12em;
315
- color: var(--text-muted);
316
- cursor: pointer;
317
- transition: all 0.2s;
318
- }
319
-
320
- .tab-btn.active {
321
- background: var(--bg-surface);
322
- color: var(--text-main);
323
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
324
- }
325
-
326
- .qr-form {
327
- display: flex;
328
- flex-direction: column;
329
- gap: 16px;
330
- }
331
-
332
- .qr-form.hidden {
333
- display: none;
334
- }
335
-
336
- .field-group {
337
- display: flex;
338
- flex-direction: column;
339
- gap: 6px;
340
- }
341
-
342
- .field-label {
343
- font-size: 12px;
344
- font-weight: 700;
345
- color: var(--text-muted);
346
- }
347
-
348
- .field-input {
349
- width: 100%;
350
- padding: 10px 14px;
351
- background: var(--bg-muted);
352
- border: 1px solid var(--border-color);
353
- border-radius: 10px;
354
- font-size: 14px;
355
- font-weight: 500;
356
- color: var(--text-main);
357
- transition: border-color 0.2s, box-shadow 0.2s;
358
- box-sizing: border-box;
359
- }
360
-
361
- .field-input:focus {
362
- outline: none;
363
- border-color: var(--qr-p);
364
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
365
- }
366
-
367
- .input-row {
368
- position: relative;
369
- }
370
-
371
- .input-row .field-input {
372
- padding-right: 44px;
373
- }
374
-
375
- .eye-btn {
376
- position: absolute;
377
- right: 10px;
378
- top: 50%;
379
- transform: translateY(-50%);
380
- background: none;
381
- border: none;
382
- cursor: pointer;
383
- color: var(--text-muted);
384
- padding: 4px;
385
- display: flex;
386
- }
387
-
388
- .eye-btn svg {
389
- width: 18px;
390
- height: 18px;
391
- }
392
-
393
- .two-col {
394
- display: grid;
395
- grid-template-columns: 1fr 1fr;
396
- gap: 12px;
397
- }
398
-
399
- .check-group {
400
- justify-content: flex-end;
401
- padding-bottom: 2px;
402
- }
403
-
404
- .check-label {
405
- display: flex;
406
- align-items: center;
407
- gap: 8px;
408
- cursor: pointer;
409
- font-size: 13px;
410
- color: var(--text-muted);
411
- padding-top: 22px;
412
- }
413
-
414
- .check-input {
415
- width: 16px;
416
- height: 16px;
417
- accent-color: var(--qr-p);
418
- }
419
-
420
- .qr-preview-area {
421
- position: relative;
422
- width: 100%;
423
- max-width: 260px;
424
- }
425
-
426
- .canvas-glow {
427
- position: relative;
428
- }
429
-
430
- .canvas-glow::before {
431
- content: "";
432
- position: absolute;
433
- inset: -4px;
434
- background: linear-gradient(135deg, #3b82f6, #06b6d4);
435
- border-radius: 20px;
436
- filter: blur(12px);
437
- opacity: 0.3;
438
- transition: opacity 0.3s;
439
- }
440
-
441
- .canvas-glow:hover::before {
442
- opacity: 0.55;
443
- }
444
-
445
- .canvas-box {
446
- position: relative;
447
- background: var(--bg-surface);
448
- border: 1px solid var(--border-color);
449
- border-radius: 16px;
450
- padding: 16px;
451
- display: flex;
452
- align-items: center;
453
- justify-content: center;
454
- }
455
-
456
- .canvas-box canvas {
457
- width: 100%;
458
- height: auto;
459
- }
460
-
461
- .download-btn {
462
- display: flex;
463
- align-items: center;
464
- gap: 8px;
465
- padding: 12px 24px;
466
- background: var(--qr-p);
467
- color: #fff;
468
- border: none;
469
- border-radius: 12px;
470
- font-size: 13px;
471
- font-weight: 700;
472
- cursor: pointer;
473
- transition: all 0.2s;
474
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
475
- }
476
-
477
- .download-btn:hover {
478
- filter: brightness(1.1);
479
- box-shadow: 0 6px 16px rgba(59, 130, 246, 0.4);
480
- transform: translateY(-1px);
481
- }
482
-
483
- .download-btn svg {
484
- width: 18px;
485
- height: 18px;
486
- }
487
-
488
- .privacy-msg {
489
- font-size: 12px;
490
- color: var(--text-muted);
491
- text-align: center;
492
- max-width: 220px;
493
- line-height: 1.5;
494
- }
495
-
496
- .theme-dark .canvas-box {
497
- background: #020617;
498
- }
499
- </style>
@@ -0,0 +1,30 @@
1
+ import type { HomeToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ import type { QRGeneratorUI } from './ui';
4
+
5
+ export type QRGeneratorLocaleContent = ToolLocaleContent<QRGeneratorUI>;
6
+
7
+ export const qrGenerator: HomeToolEntry<QRGeneratorUI> = {
8
+ id: 'qr-generator',
9
+ icons: {
10
+ bg: 'mdi:qrcode-scan',
11
+ fg: 'mdi:shield-check',
12
+ },
13
+ i18n: {
14
+ de: async () => (await import('./i18n/de')).content,
15
+ en: async () => (await import('./i18n/en')).content,
16
+ es: async () => (await import('./i18n/es')).content,
17
+ fr: async () => (await import('./i18n/fr')).content,
18
+ id: async () => (await import('./i18n/id')).content,
19
+ it: async () => (await import('./i18n/it')).content,
20
+ ja: async () => (await import('./i18n/ja')).content,
21
+ ko: async () => (await import('./i18n/ko')).content,
22
+ nl: async () => (await import('./i18n/nl')).content,
23
+ pl: async () => (await import('./i18n/pl')).content,
24
+ pt: async () => (await import('./i18n/pt')).content,
25
+ ru: async () => (await import('./i18n/ru')).content,
26
+ sv: async () => (await import('./i18n/sv')).content,
27
+ tr: async () => (await import('./i18n/tr')).content,
28
+ zh: async () => (await import('./i18n/zh')).content,
29
+ },
30
+ };
@@ -1,35 +1,5 @@
1
- import type { HomeToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
-
3
- import type { QRGeneratorUI } from './ui';
4
-
5
- export type QRGeneratorLocaleContent = ToolLocaleContent<QRGeneratorUI>;
6
-
7
- export const qrGenerator: HomeToolEntry<QRGeneratorUI> = {
8
- id: 'qr-generator',
9
- icons: {
10
- bg: 'mdi:qrcode-scan',
11
- fg: 'mdi:shield-check',
12
- },
13
- i18n: {
14
- de: async () => (await import('./i18n/de')).content,
15
- en: async () => (await import('./i18n/en')).content,
16
- es: async () => (await import('./i18n/es')).content,
17
- fr: async () => (await import('./i18n/fr')).content,
18
- id: async () => (await import('./i18n/id')).content,
19
- it: async () => (await import('./i18n/it')).content,
20
- ja: async () => (await import('./i18n/ja')).content,
21
- ko: async () => (await import('./i18n/ko')).content,
22
- nl: async () => (await import('./i18n/nl')).content,
23
- pl: async () => (await import('./i18n/pl')).content,
24
- pt: async () => (await import('./i18n/pt')).content,
25
- ru: async () => (await import('./i18n/ru')).content,
26
- sv: async () => (await import('./i18n/sv')).content,
27
- tr: async () => (await import('./i18n/tr')).content,
28
- zh: async () => (await import('./i18n/zh')).content,
29
- },
30
- };
31
-
32
-
1
+ import { qrGenerator } from './entry';
2
+ export * from './entry';
33
3
  export const QR_GENERATOR_TOOL: ToolDefinition = {
34
4
  entry: qrGenerator,
35
5
  Component: () => import('./component.astro'),