@jjlmoya/utils-finance 1.12.0 → 1.13.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 (26) hide show
  1. package/package.json +5 -3
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/tool/compoundInterest/component.astro +0 -376
  4. package/src/tool/compoundInterest/compound-interest-calculator.css +79 -0
  5. package/src/tool/courtFeeCalculator/component.astro +0 -237
  6. package/src/tool/courtFeeCalculator/spanish-court-fees-calculator.css +235 -0
  7. package/src/tool/debtSnowball/component.astro +0 -636
  8. package/src/tool/debtSnowball/debt-snowball-calculator.css +634 -0
  9. package/src/tool/fireCalculator/component.astro +0 -334
  10. package/src/tool/fireCalculator/four-percent-rule-fire-calculator.css +332 -0
  11. package/src/tool/ibanBicSwiftConverter/component.astro +0 -414
  12. package/src/tool/ibanBicSwiftConverter/iban-to-bic-swift-converter.css +412 -0
  13. package/src/tool/inflation/component.astro +0 -280
  14. package/src/tool/inflation/inflation-calculator-spain.css +278 -0
  15. package/src/tool/lateInterest/component.astro +0 -400
  16. package/src/tool/lateInterest/late-interest-calculator.css +398 -0
  17. package/src/tool/legalInterestRate/component.astro +0 -509
  18. package/src/tool/legalInterestRate/legal-interest-on-money-spain.css +507 -0
  19. package/src/tool/lotteryOptimizer/component.astro +0 -561
  20. package/src/tool/lotteryOptimizer/spain-lottery-optimizer.css +17 -0
  21. package/src/tool/mortgage/component.astro +0 -641
  22. package/src/tool/mortgage/mortgage-calculator.css +639 -0
  23. package/src/tool/percentageCalculator/component.astro +0 -336
  24. package/src/tool/percentageCalculator/percentage-calculator.css +289 -0
  25. package/src/tool/rentIncreaseCalculator/component.astro +0 -372
  26. package/src/tool/rentIncreaseCalculator/rent-increase-calculator.css +370 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-finance",
3
- "version": "1.12.0",
3
+ "version": "1.13.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
+ }
@@ -318,380 +318,4 @@ const t = (ui ?? {}) as CompoundInterestUI;
318
318
  update();
319
319
  </script>
320
320
 
321
- <style>
322
- .cic-root {
323
- --cic-accent: #10b981;
324
- --cic-accent-text: #059669;
325
- --cic-accent-icon-bg: #d1fae5;
326
- --cic-bg: #fff;
327
- --cic-bg-panel: rgba(248, 250, 252, 0.3);
328
- --cic-bg-card: #fff;
329
- --cic-bg-header: rgba(248, 250, 252, 0.5);
330
- --cic-border: #e2e8f0;
331
- --cic-border-subtle: #f1f5f9;
332
- --cic-text: #0f172a;
333
- --cic-text-muted: #64748b;
334
- --cic-text-subtle: #94a3b8;
335
- --cic-input-bg: #fff;
336
- --cic-input-border: #e2e8f0;
337
- --cic-summary-bg: #fff;
338
- --cic-insight-bg: #ecfdf5;
339
- --cic-insight-text: #065f46;
340
-
341
- background: var(--cic-bg);
342
- border-radius: 1.5rem;
343
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
344
- border: 1px solid var(--cic-border-subtle);
345
- overflow: hidden;
346
- }
347
-
348
- .cic-header {
349
- padding: 1.5rem;
350
- border-bottom: 1px solid var(--cic-border-subtle);
351
- background: var(--cic-bg-header);
352
- display: flex;
353
- flex-wrap: wrap;
354
- gap: 1rem;
355
- align-items: center;
356
- justify-content: space-between;
357
- }
358
-
359
- .cic-header-left {
360
- display: flex;
361
- align-items: center;
362
- gap: 0.75rem;
363
- }
364
-
365
- .cic-icon-wrap {
366
- padding: 0.625rem;
367
- background: var(--cic-accent-icon-bg);
368
- border-radius: 0.75rem;
369
- color: var(--cic-accent-text);
370
- display: flex;
371
- align-items: center;
372
- justify-content: center;
373
- }
374
-
375
- .cic-icon {
376
- width: 1.5rem;
377
- height: 1.5rem;
378
- }
379
-
380
- .cic-title {
381
- font-size: 1.25rem;
382
- font-weight: 700;
383
- color: var(--cic-text);
384
- }
385
-
386
- .cic-realtime {
387
- display: flex;
388
- align-items: center;
389
- gap: 0.5rem;
390
- font-size: 0.875rem;
391
- color: var(--cic-text-muted);
392
- }
393
-
394
- .cic-dot {
395
- width: 0.5rem;
396
- height: 0.5rem;
397
- border-radius: 50%;
398
- background: var(--cic-accent);
399
- animation: cic-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
400
- }
401
-
402
- @keyframes cic-pulse {
403
- 0%, 100% { opacity: 1; }
404
- 50% { opacity: 0.4; }
405
- }
406
-
407
- .cic-grid {
408
- display: grid;
409
- }
410
-
411
- .cic-panel-left {
412
- padding: 1.5rem;
413
- display: flex;
414
- flex-direction: column;
415
- gap: 1.5rem;
416
- background: var(--cic-bg-panel);
417
- border-bottom: 1px solid var(--cic-border-subtle);
418
- }
419
-
420
- .cic-fields {
421
- display: flex;
422
- flex-direction: column;
423
- gap: 1rem;
424
- }
425
-
426
- .cic-grid-2 {
427
- display: grid;
428
- grid-template-columns: 1fr 1fr;
429
- gap: 1rem;
430
- }
431
-
432
- .cic-label {
433
- display: block;
434
- font-size: 0.75rem;
435
- font-weight: 700;
436
- color: var(--cic-text-subtle);
437
- text-transform: uppercase;
438
- letter-spacing: 0.1em;
439
- margin-bottom: 0.5rem;
440
- }
441
-
442
- .cic-input-wrap {
443
- position: relative;
444
- }
445
-
446
- .cic-currency {
447
- position: absolute;
448
- left: 0.5rem;
449
- top: 50%;
450
- transform: translateY(-50%);
451
- color: var(--cic-text-subtle);
452
- font-weight: 700;
453
- pointer-events: none;
454
- font-size: 0.75rem;
455
- }
456
-
457
- .cic-currency-right {
458
- left: auto;
459
- right: 0.5rem;
460
- }
461
-
462
- .cic-input {
463
- width: 100%;
464
- padding: 0.75rem 1rem;
465
- background: var(--cic-input-bg);
466
- border: 2px solid var(--cic-input-border);
467
- border-radius: 0.75rem;
468
- outline: none;
469
- transition: border-color 0.2s;
470
- color: var(--cic-text);
471
- font-weight: 700;
472
- font-size: 1.125rem;
473
- box-sizing: border-box;
474
- }
475
-
476
- .cic-input-prefixed {
477
- padding-left: 3.5rem;
478
- }
479
-
480
- .cic-input-suffixed {
481
- padding-right: 5rem;
482
- }
483
-
484
- .cic-input:focus {
485
- border-color: var(--cic-accent);
486
- }
487
-
488
- .cic-summary {
489
- background: var(--cic-summary-bg);
490
- border-radius: 1rem;
491
- padding: 1rem;
492
- border: 1px solid var(--cic-border);
493
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
494
- display: flex;
495
- flex-direction: column;
496
- gap: 0.75rem;
497
- }
498
-
499
- .cic-summary-row {
500
- display: flex;
501
- justify-content: space-between;
502
- align-items: center;
503
- font-size: 0.875rem;
504
- }
505
-
506
- .cic-summary-label {
507
- display: flex;
508
- align-items: center;
509
- gap: 0.5rem;
510
- }
511
-
512
- .cic-dot-neutral {
513
- width: 0.75rem;
514
- height: 0.75rem;
515
- border-radius: 50%;
516
- background: var(--cic-text-subtle);
517
- flex-shrink: 0;
518
- }
519
-
520
- .cic-dot-accent {
521
- width: 0.75rem;
522
- height: 0.75rem;
523
- border-radius: 50%;
524
- background: var(--cic-accent);
525
- flex-shrink: 0;
526
- }
527
-
528
- .cic-text-muted {
529
- color: var(--cic-text-muted);
530
- }
531
-
532
- .cic-text-accent {
533
- color: var(--cic-accent-text);
534
- font-weight: 500;
535
- }
536
-
537
- .cic-summary-value {
538
- font-weight: 700;
539
- color: var(--cic-text);
540
- }
541
-
542
- .cic-summary-value-accent {
543
- color: var(--cic-accent-text);
544
- }
545
-
546
- .cic-summary-total {
547
- padding-top: 0.75rem;
548
- margin-top: 0.25rem;
549
- border-top: 1px solid var(--cic-border-subtle);
550
- display: flex;
551
- justify-content: space-between;
552
- align-items: flex-end;
553
- }
554
-
555
- .cic-total-label {
556
- color: var(--cic-text-subtle);
557
- font-size: 0.75rem;
558
- font-weight: 700;
559
- text-transform: uppercase;
560
- letter-spacing: 0.05em;
561
- }
562
-
563
- .cic-total-value {
564
- font-size: 1.5rem;
565
- font-weight: 900;
566
- color: var(--cic-text);
567
- }
568
-
569
- .cic-panel-right {
570
- padding: 1.5rem;
571
- display: flex;
572
- flex-direction: column;
573
- min-height: 500px;
574
- }
575
-
576
- .cic-canvas-wrap {
577
- position: relative;
578
- width: 100%;
579
- flex: 1;
580
- }
581
-
582
- .cic-insight {
583
- display: none;
584
- margin-top: 1rem;
585
- padding: 1rem;
586
- background: var(--cic-insight-bg);
587
- border-radius: 0.75rem;
588
- font-size: 0.875rem;
589
- color: var(--cic-insight-text);
590
- opacity: 0;
591
- transition: opacity 0.5s;
592
- }
593
-
594
- @media (min-width: 768px) {
595
- .cic-insight {
596
- display: block;
597
- }
598
- }
599
-
600
- @media (min-width: 1024px) {
601
- .cic-grid {
602
- grid-template-columns: 4fr 8fr;
603
- }
604
-
605
- .cic-panel-left {
606
- border-bottom: none;
607
- border-right: 1px solid var(--cic-border-subtle);
608
- }
609
321
 
610
- .cic-panel-right {
611
- padding: 2rem;
612
- min-height: auto;
613
- }
614
- }
615
- </style>
616
-
617
- <style is:global>
618
- .cic-insight.cic-insight-visible {
619
- opacity: 1;
620
- }
621
-
622
- .cic-insight-year {
623
- font-weight: 700;
624
- color: #10b981;
625
- }
626
-
627
- .theme-dark .cic-root {
628
- --cic-accent-text: #34d399;
629
- --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
630
- --cic-bg: #1e293b;
631
- --cic-bg-panel: rgba(15, 23, 42, 0.1);
632
- --cic-bg-card: #1e293b;
633
- --cic-bg-header: rgba(30, 41, 59, 0.5);
634
- --cic-border: #334155;
635
- --cic-border-subtle: #334155;
636
- --cic-text: #fff;
637
- --cic-text-muted: #94a3b8;
638
- --cic-text-subtle: #64748b;
639
- --cic-input-bg: #0f172a;
640
- --cic-input-border: #334155;
641
- --cic-summary-bg: #1e293b;
642
- --cic-insight-bg: rgba(16, 185, 129, 0.1);
643
- --cic-insight-text: #6ee7b7;
644
- }
645
-
646
- .theme-dark .cic-insight-year {
647
- color: #fff;
648
- }
649
-
650
- [data-theme='dark'] .cic-root {
651
- --cic-accent-text: #34d399;
652
- --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
653
- --cic-bg: #1e293b;
654
- --cic-bg-panel: rgba(15, 23, 42, 0.1);
655
- --cic-bg-card: #1e293b;
656
- --cic-bg-header: rgba(30, 41, 59, 0.5);
657
- --cic-border: #334155;
658
- --cic-border-subtle: #334155;
659
- --cic-text: #fff;
660
- --cic-text-muted: #94a3b8;
661
- --cic-text-subtle: #64748b;
662
- --cic-input-bg: #0f172a;
663
- --cic-input-border: #334155;
664
- --cic-summary-bg: #1e293b;
665
- --cic-insight-bg: rgba(16, 185, 129, 0.1);
666
- --cic-insight-text: #6ee7b7;
667
- }
668
-
669
- [data-theme='dark'] .cic-insight-year {
670
- color: #fff;
671
- }
672
-
673
- @media (prefers-color-scheme: dark) {
674
- .cic-root {
675
- --cic-accent-text: #34d399;
676
- --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
677
- --cic-bg: #1e293b;
678
- --cic-bg-panel: rgba(15, 23, 42, 0.1);
679
- --cic-bg-card: #1e293b;
680
- --cic-bg-header: rgba(30, 41, 59, 0.5);
681
- --cic-border: #334155;
682
- --cic-border-subtle: #334155;
683
- --cic-text: #fff;
684
- --cic-text-muted: #94a3b8;
685
- --cic-text-subtle: #64748b;
686
- --cic-input-bg: #0f172a;
687
- --cic-input-border: #334155;
688
- --cic-summary-bg: #1e293b;
689
- --cic-insight-bg: rgba(16, 185, 129, 0.1);
690
- --cic-insight-text: #6ee7b7;
691
- }
692
-
693
- .cic-insight-year {
694
- color: #fff;
695
- }
696
- }
697
- </style>
@@ -0,0 +1,79 @@
1
+ .cic-insight.cic-insight-visible {
2
+ opacity: 1;
3
+ }
4
+
5
+ .cic-insight-year {
6
+ font-weight: 700;
7
+ color: #10b981;
8
+ }
9
+
10
+ .theme-dark .cic-root {
11
+ --cic-accent-text: #34d399;
12
+ --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
13
+ --cic-bg: #1e293b;
14
+ --cic-bg-panel: rgba(15, 23, 42, 0.1);
15
+ --cic-bg-card: #1e293b;
16
+ --cic-bg-header: rgba(30, 41, 59, 0.5);
17
+ --cic-border: #334155;
18
+ --cic-border-subtle: #334155;
19
+ --cic-text: #fff;
20
+ --cic-text-muted: #94a3b8;
21
+ --cic-text-subtle: #64748b;
22
+ --cic-input-bg: #0f172a;
23
+ --cic-input-border: #334155;
24
+ --cic-summary-bg: #1e293b;
25
+ --cic-insight-bg: rgba(16, 185, 129, 0.1);
26
+ --cic-insight-text: #6ee7b7;
27
+ }
28
+
29
+ .theme-dark .cic-insight-year {
30
+ color: #fff;
31
+ }
32
+
33
+ [data-theme='dark'] .cic-root {
34
+ --cic-accent-text: #34d399;
35
+ --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
36
+ --cic-bg: #1e293b;
37
+ --cic-bg-panel: rgba(15, 23, 42, 0.1);
38
+ --cic-bg-card: #1e293b;
39
+ --cic-bg-header: rgba(30, 41, 59, 0.5);
40
+ --cic-border: #334155;
41
+ --cic-border-subtle: #334155;
42
+ --cic-text: #fff;
43
+ --cic-text-muted: #94a3b8;
44
+ --cic-text-subtle: #64748b;
45
+ --cic-input-bg: #0f172a;
46
+ --cic-input-border: #334155;
47
+ --cic-summary-bg: #1e293b;
48
+ --cic-insight-bg: rgba(16, 185, 129, 0.1);
49
+ --cic-insight-text: #6ee7b7;
50
+ }
51
+
52
+ [data-theme='dark'] .cic-insight-year {
53
+ color: #fff;
54
+ }
55
+
56
+ @media (prefers-color-scheme: dark) {
57
+ .cic-root {
58
+ --cic-accent-text: #34d399;
59
+ --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
60
+ --cic-bg: #1e293b;
61
+ --cic-bg-panel: rgba(15, 23, 42, 0.1);
62
+ --cic-bg-card: #1e293b;
63
+ --cic-bg-header: rgba(30, 41, 59, 0.5);
64
+ --cic-border: #334155;
65
+ --cic-border-subtle: #334155;
66
+ --cic-text: #fff;
67
+ --cic-text-muted: #94a3b8;
68
+ --cic-text-subtle: #64748b;
69
+ --cic-input-bg: #0f172a;
70
+ --cic-input-border: #334155;
71
+ --cic-summary-bg: #1e293b;
72
+ --cic-insight-bg: rgba(16, 185, 129, 0.1);
73
+ --cic-insight-text: #6ee7b7;
74
+ }
75
+
76
+ .cic-insight-year {
77
+ color: #fff;
78
+ }
79
+ }