@jjlmoya/utils-nautical 1.12.0 → 1.14.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.
@@ -0,0 +1,205 @@
1
+ .nautical-converter {
2
+ --n-bg: #fff;
3
+ --n-bg-muted: #f1f5f9;
4
+ --n-text: #0f172a;
5
+ --n-text-muted: #475569;
6
+ --n-text-dim: #64748b;
7
+ --n-border: #e2e8f0;
8
+ --n-shadow: rgba(0, 0, 0, 0.05);
9
+ --n-primary: #3b82f6;
10
+ --n-primary-on: #fff;
11
+ --n-accent: #6366f1;
12
+ --n-cyan: #0891b2;
13
+ --n-success: #10b981;
14
+ --n-warning: #f59e0b;
15
+ --n-error: #f43f5e;
16
+
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: 1.5rem;
20
+ max-width: 900px;
21
+ margin: 0 auto;
22
+ }
23
+
24
+ :global(.theme-dark) .nautical-converter {
25
+ --n-bg: #0f172a;
26
+ --n-bg-muted: #1e293b;
27
+ --n-text: #f8fafc;
28
+ --n-text-muted: #94a3b8;
29
+ --n-text-dim: #64748b;
30
+ --n-border: #334155;
31
+ --n-shadow: rgba(0, 0, 0, 0.3);
32
+ --n-primary: #60a5fa;
33
+ --n-primary-on: #fff;
34
+ --n-accent: #818cf8;
35
+ --n-cyan: #22d3ee;
36
+ --n-success: #34d399;
37
+ --n-warning: #fbbf24;
38
+ --n-error: #fb7185;
39
+ }
40
+
41
+ .nc-category-tabs {
42
+ display: flex;
43
+ gap: 0.5rem;
44
+ flex-wrap: wrap;
45
+ background: var(--n-bg);
46
+ border: 1px solid var(--n-border);
47
+ border-radius: 1rem;
48
+ padding: 0.5rem;
49
+ }
50
+
51
+ .nc-tab-btn {
52
+ flex: 1;
53
+ min-width: 120px;
54
+ padding: 0.7rem 1.2rem;
55
+ border: none;
56
+ border-radius: 0.7rem;
57
+ background: transparent;
58
+ color: var(--n-text-muted);
59
+ font-size: 0.9rem;
60
+ font-weight: 600;
61
+ cursor: pointer;
62
+ transition: background 0.2s, color 0.2s;
63
+ }
64
+
65
+ .nc-tab-btn:hover {
66
+ background: var(--n-bg-muted);
67
+ color: var(--n-text);
68
+ }
69
+
70
+ .nc-tab-btn.active {
71
+ background: var(--n-primary);
72
+ color: var(--n-primary-on);
73
+ }
74
+
75
+ .nc-tab-panel {
76
+ display: none;
77
+ }
78
+
79
+ .nc-tab-panel.active {
80
+ display: block;
81
+ }
82
+
83
+ .nc-converter-card {
84
+ background: var(--n-bg);
85
+ border: 1px solid var(--n-border);
86
+ border-radius: 1.5rem;
87
+ padding: 2rem;
88
+ box-shadow: 0 8px 24px var(--n-shadow);
89
+ }
90
+
91
+ .nc-input-grid {
92
+ display: grid;
93
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
94
+ gap: 1.2rem;
95
+ }
96
+
97
+ .nc-input-group {
98
+ display: flex;
99
+ flex-direction: column;
100
+ gap: 0.4rem;
101
+ }
102
+
103
+ .nc-input-group label {
104
+ font-size: 0.8rem;
105
+ font-weight: 700;
106
+ color: var(--n-text-muted);
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.05em;
109
+ }
110
+
111
+ .nc-input-wrapper {
112
+ position: relative;
113
+ display: flex;
114
+ align-items: center;
115
+ }
116
+
117
+ .nc-elegant-input {
118
+ width: 100%;
119
+ background: var(--n-bg);
120
+ color: var(--n-text);
121
+ border: 2px solid var(--n-border);
122
+ border-radius: 0.8rem;
123
+ padding: 0.75rem 2.8rem 0.75rem 1rem;
124
+ font-size: 1rem;
125
+ outline: none;
126
+ transition: border-color 0.2s;
127
+ }
128
+
129
+ .nc-elegant-input:focus {
130
+ border-color: var(--n-cyan);
131
+ }
132
+
133
+ .nc-copy-btn {
134
+ position: absolute;
135
+ right: 0.5rem;
136
+ background: none;
137
+ border: none;
138
+ cursor: pointer;
139
+ color: var(--n-cyan);
140
+ padding: 0.2rem;
141
+ display: flex;
142
+ align-items: center;
143
+ opacity: 0.5;
144
+ transition: opacity 0.2s;
145
+ }
146
+
147
+ .nc-copy-btn:hover {
148
+ opacity: 1;
149
+ }
150
+
151
+ .nc-beaufort-card {
152
+ margin-top: 1.5rem;
153
+ background: var(--n-bg);
154
+ border: 1px solid var(--n-border);
155
+ border-radius: 1rem;
156
+ padding: 1.2rem 1.5rem;
157
+ display: none;
158
+ align-items: center;
159
+ gap: 1.2rem;
160
+ }
161
+
162
+ .nc-beaufort-card.visible {
163
+ display: flex;
164
+ }
165
+
166
+ .nc-beaufort-badge {
167
+ display: flex;
168
+ align-items: center;
169
+ justify-content: center;
170
+ width: 56px;
171
+ height: 56px;
172
+ border-radius: 50%;
173
+ font-size: 1.6rem;
174
+ font-weight: 900;
175
+ color: var(--n-primary-on);
176
+ flex-shrink: 0;
177
+ }
178
+
179
+ .nc-beaufort-info {
180
+ display: flex;
181
+ flex-direction: column;
182
+ gap: 0.2rem;
183
+ }
184
+
185
+ .nc-beaufort-name {
186
+ font-size: 1.1rem;
187
+ font-weight: 700;
188
+ color: var(--n-text);
189
+ }
190
+
191
+ .nc-beaufort-sea {
192
+ font-size: 0.9rem;
193
+ color: var(--n-text-muted);
194
+ }
195
+
196
+ @media (max-width: 600px) {
197
+ .nc-input-grid {
198
+ grid-template-columns: 1fr 1fr;
199
+ }
200
+
201
+ .nc-tab-btn {
202
+ font-size: 0.8rem;
203
+ padding: 0.6rem 0.8rem;
204
+ }
205
+ }
@@ -416,356 +416,3 @@ const { ui } = Astro.props;
416
416
  loadFromLocal();
417
417
  </script>
418
418
 
419
- <style>
420
- .sail-area-calculator {
421
- --sa-primary: #003b73;
422
- --sa-primary-light: #0055a4;
423
- --sa-secondary: #ef4135;
424
- --sa-radius: 16px;
425
- --n-bg: #fff;
426
- --n-bg-muted: #f1f5f9;
427
- --n-text: #0f172a;
428
- --n-text-muted: #475569;
429
- --n-text-dim: #64748b;
430
- --n-border: #e2e8f0;
431
- --n-shadow: rgba(0, 0, 0, 0.05);
432
- --n-primary: #3b82f6;
433
- --n-primary-on: #fff;
434
- --n-accent: #6366f1;
435
- --n-cyan: #0891b2;
436
- --n-success: #10b981;
437
- --n-warning: #f59e0b;
438
- --n-error: #f43f5e;
439
-
440
- padding: 1rem;
441
- max-width: 1200px;
442
- margin: 0 auto;
443
- }
444
-
445
- :global(.theme-dark) .sail-area-calculator {
446
- --n-bg: #0f172a;
447
- --n-bg-muted: #1e293b;
448
- --n-text: #f8fafc;
449
- --n-text-muted: #94a3b8;
450
- --n-text-dim: #64748b;
451
- --n-border: #334155;
452
- --n-shadow: rgba(0, 0, 0, 0.3);
453
- --n-primary: #60a5fa;
454
- --n-primary-on: #fff;
455
- --n-accent: #818cf8;
456
- --n-cyan: #22d3ee;
457
- --n-success: #34d399;
458
- --n-warning: #fbbf24;
459
- --n-error: #fb7185;
460
- }
461
-
462
- .sa-calculator-wrapper {
463
- background: var(--n-bg);
464
- border: 1px solid var(--n-border);
465
- border-radius: var(--sa-radius);
466
- padding: 1.5rem;
467
- display: flex;
468
- flex-direction: column;
469
- gap: 2rem;
470
- }
471
-
472
- .sa-main-controls {
473
- display: flex;
474
- flex-direction: column;
475
- gap: 1.5rem;
476
- }
477
-
478
- .sa-section-group h3 {
479
- font-size: 0.75rem;
480
- text-transform: uppercase;
481
- letter-spacing: 0.1em;
482
- color: var(--n-text-muted);
483
- margin-bottom: 1rem;
484
- display: flex;
485
- align-items: center;
486
- gap: 0.5rem;
487
- opacity: 0.8;
488
- border-bottom: 1px solid var(--n-border);
489
- padding-bottom: 0.4rem;
490
- }
491
-
492
- .sa-compact-grid {
493
- display: grid;
494
- grid-template-columns: repeat(2, 1fr);
495
- gap: 1rem;
496
- }
497
-
498
- .sa-input-row {
499
- display: flex;
500
- flex-direction: column;
501
- gap: 0.4rem;
502
- }
503
-
504
- .sa-input-row label {
505
- font-size: 0.7rem;
506
- font-weight: 700;
507
- color: var(--n-text-muted);
508
- }
509
-
510
- .sa-elegant-input {
511
- background: var(--n-bg-muted);
512
- border: 1.5px solid var(--n-border);
513
- border-radius: 10px;
514
- padding: 0.7rem 0.9rem;
515
- font-size: 0.95rem;
516
- color: var(--n-text);
517
- font-weight: 600;
518
- width: 100%;
519
- }
520
-
521
- .sa-elegant-input:focus {
522
- border-color: var(--sa-primary-light);
523
- outline: none;
524
- }
525
-
526
- .sa-input-with-unit {
527
- position: relative;
528
- display: flex;
529
- align-items: center;
530
- }
531
-
532
- .sa-unit-tag {
533
- position: absolute;
534
- right: 10px;
535
- font-size: 0.65rem;
536
- font-weight: 900;
537
- color: var(--n-text-muted);
538
- background: var(--n-bg);
539
- border: 1px solid var(--n-border);
540
- padding: 2px 6px;
541
- border-radius: 4px;
542
- }
543
-
544
- .sa-unit-tag select {
545
- color: var(--n-text-muted);
546
- }
547
-
548
- .sa-sidebar-results {
549
- background: var(--n-bg-muted);
550
- padding: 1.5rem;
551
- border-radius: var(--sa-radius);
552
- border: 1px solid var(--n-border);
553
- text-align: center;
554
- }
555
-
556
- .sad-value-large {
557
- font-size: 3.5rem;
558
- font-weight: 950;
559
- letter-spacing: -0.04em;
560
- color: var(--sa-primary);
561
- line-height: 1;
562
- }
563
-
564
- :global(.theme-dark) .sail-area-calculator .sad-value-large {
565
- color: var(--n-accent);
566
- }
567
-
568
- .sad-label {
569
- font-size: 0.75rem;
570
- font-weight: 850;
571
- color: var(--n-text-muted);
572
- text-transform: uppercase;
573
- letter-spacing: 0.15em;
574
- }
575
-
576
- .sa-gauge-track {
577
- height: 4px;
578
- background: var(--n-border);
579
- border-radius: 2px;
580
- margin: 1.5rem 0;
581
- position: relative;
582
- }
583
-
584
- .sa-gauge-indicator {
585
- position: absolute;
586
- top: 50%;
587
- width: 14px;
588
- height: 14px;
589
- background: var(--sa-secondary);
590
- border: 3px solid var(--n-bg-muted);
591
- border-radius: 50%;
592
- transform: translate(-50%, -50%);
593
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
594
- transition: left 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
595
- }
596
-
597
- .sa-verdict-box {
598
- background: var(--n-bg);
599
- padding: 1rem;
600
- border-radius: 12px;
601
- border: 1px solid var(--n-border);
602
- }
603
-
604
- .sa-verdict-box h4 {
605
- font-size: 0.95rem;
606
- margin-bottom: 0.4rem;
607
- color: var(--n-text);
608
- }
609
-
610
- .sa-verdict-box p {
611
- font-size: 0.8rem;
612
- line-height: 1.5;
613
- color: var(--n-text-muted);
614
- }
615
-
616
- .sa-stats-summary {
617
- display: grid;
618
- grid-template-columns: 1fr 1fr;
619
- gap: 1rem;
620
- margin-top: 1.5rem;
621
- padding-top: 1.5rem;
622
- border-top: 1px dashed var(--n-border);
623
- }
624
-
625
- .sa-stat-item span {
626
- font-size: 0.75rem;
627
- color: var(--n-text-muted);
628
- display: block;
629
- }
630
-
631
- .sa-stat-item span:last-child {
632
- font-size: 1.2rem;
633
- font-weight: 900;
634
- color: var(--n-text);
635
- }
636
-
637
- .sa-export-btn-premium {
638
- width: 100%;
639
- margin-top: 1.5rem;
640
- padding: 1rem;
641
- background: var(--sa-primary);
642
- color: var(--n-primary-on);
643
- border: none;
644
- border-radius: 10px;
645
- font-size: 0.75rem;
646
- font-weight: 800;
647
- letter-spacing: 0.05em;
648
- cursor: pointer;
649
- display: flex;
650
- align-items: center;
651
- justify-content: center;
652
- gap: 0.5rem;
653
- }
654
-
655
- .sa-slider-box {
656
- background: var(--n-bg-muted);
657
- padding: 1.5rem;
658
- border-radius: 12px;
659
- border: 1px solid var(--n-border);
660
- }
661
-
662
- .sa-slider-header {
663
- display: flex;
664
- justify-content: space-between;
665
- align-items: center;
666
- margin-bottom: 1.5rem;
667
- }
668
-
669
- .sa-slider-header label {
670
- font-size: 0.85rem;
671
- font-weight: 800;
672
- color: var(--n-text);
673
- }
674
-
675
- .sa-percentage-badge {
676
- background: var(--sa-primary);
677
- color: var(--n-primary-on);
678
- padding: 4px 10px;
679
- border-radius: 20px;
680
- font-size: 0.8rem;
681
- font-weight: 900;
682
- }
683
-
684
- .sa-slider-wrapper {
685
- padding: 0 5px;
686
- }
687
-
688
- .sa-modern-slider {
689
- appearance: none;
690
- width: 100%;
691
- height: 6px;
692
- background: var(--n-border);
693
- border-radius: 10px;
694
- outline: none;
695
- margin: 1rem 0;
696
- }
697
-
698
- .sa-modern-slider::-webkit-slider-thumb {
699
- appearance: none;
700
- width: 24px;
701
- height: 24px;
702
- background: var(--sa-primary);
703
- border: 4px solid var(--n-bg-muted);
704
- border-radius: 50%;
705
- cursor: pointer;
706
- box-shadow: 0 2px 10px rgba(0, 59, 115, 0.2);
707
- transition: transform 0.2s;
708
- }
709
-
710
- .sa-modern-slider::-webkit-slider-thumb:hover {
711
- transform: scale(1.1);
712
- }
713
-
714
- .sa-modern-slider::-moz-range-thumb {
715
- width: 24px;
716
- height: 24px;
717
- background: var(--sa-primary);
718
- border: 4px solid var(--n-bg-muted);
719
- border-radius: 50%;
720
- cursor: pointer;
721
- }
722
-
723
- .sa-modern-slider::-moz-range-track {
724
- height: 6px;
725
- background: var(--n-border);
726
- border-radius: 10px;
727
- }
728
-
729
- .sa-slider-ticks {
730
- display: flex;
731
- justify-content: space-between;
732
- margin-top: 0.5rem;
733
- }
734
-
735
- .sa-slider-ticks span {
736
- font-size: 0.65rem;
737
- font-weight: 700;
738
- color: var(--n-text-muted);
739
- }
740
-
741
- @media (min-width: 1024px) {
742
- .sail-area-calculator {
743
- padding: 2rem;
744
- }
745
-
746
- .sa-calculator-wrapper {
747
- display: grid;
748
- grid-template-columns: 1fr 400px;
749
- gap: 3rem;
750
- padding: 2.5rem;
751
- }
752
-
753
- .sa-compact-grid {
754
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
755
- }
756
-
757
- .sa-main-controls {
758
- gap: 2.5rem;
759
- }
760
-
761
- .sa-sidebar-results {
762
- position: sticky;
763
- top: 2rem;
764
- padding: 2.5rem;
765
- }
766
-
767
- .sad-value-large {
768
- font-size: 5.5rem;
769
- }
770
- }
771
- </style>
@@ -0,0 +1,53 @@
1
+ import type { NauticalToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ export interface SailAreaUI {
4
+ [key: string]: string;
5
+ hullSectionLabel: string;
6
+ totalMassLabel: string;
7
+ rigSystemLabel: string;
8
+ intendedUseLabel: string;
9
+ rigGeometryLabel: string;
10
+ sailConfigLabel: string;
11
+ genoaOverlapLabel: string;
12
+ foqueLabel: string;
13
+ genovaLabel: string;
14
+ sadRatioLabel: string;
15
+ totalAreaLabel: string;
16
+ performanceLabel: string;
17
+ sloopLabel: string;
18
+ cutterLabel: string;
19
+ ketchLabel: string;
20
+ cruiserLabel: string;
21
+ performanceTypeLabel: string;
22
+ racerLabel: string;
23
+ exportPdfLabel: string;
24
+ faqTitle: string;
25
+ bibliographyTitle: string;
26
+ }
27
+
28
+ export type SailAreaLocaleContent = ToolLocaleContent<SailAreaUI>;
29
+
30
+ export const sailArea: NauticalToolEntry<SailAreaUI> = {
31
+ id: 'sail-area',
32
+ icons: {
33
+ bg: 'mdi:sail-boat',
34
+ fg: 'mdi:wind-power',
35
+ },
36
+ i18n: {
37
+ es: () => import('./i18n/es').then((m) => m.content),
38
+ en: () => import('./i18n/en').then((m) => m.content),
39
+ fr: () => import('./i18n/fr').then((m) => m.content),
40
+ de: () => import('./i18n/de').then((m) => m.content),
41
+ id: () => import('./i18n/id').then((m) => m.content),
42
+ it: () => import('./i18n/it').then((m) => m.content),
43
+ ja: () => import('./i18n/ja').then((m) => m.content),
44
+ ko: () => import('./i18n/ko').then((m) => m.content),
45
+ nl: () => import('./i18n/nl').then((m) => m.content),
46
+ pl: () => import('./i18n/pl').then((m) => m.content),
47
+ pt: () => import('./i18n/pt').then((m) => m.content),
48
+ ru: () => import('./i18n/ru').then((m) => m.content),
49
+ sv: () => import('./i18n/sv').then((m) => m.content),
50
+ tr: () => import('./i18n/tr').then((m) => m.content),
51
+ zh: () => import('./i18n/zh').then((m) => m.content),
52
+ },
53
+ };
@@ -1,58 +1,5 @@
1
- import type { NauticalToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
-
3
- export interface SailAreaUI {
4
- [key: string]: string;
5
- hullSectionLabel: string;
6
- totalMassLabel: string;
7
- rigSystemLabel: string;
8
- intendedUseLabel: string;
9
- rigGeometryLabel: string;
10
- sailConfigLabel: string;
11
- genoaOverlapLabel: string;
12
- foqueLabel: string;
13
- genovaLabel: string;
14
- sadRatioLabel: string;
15
- totalAreaLabel: string;
16
- performanceLabel: string;
17
- sloopLabel: string;
18
- cutterLabel: string;
19
- ketchLabel: string;
20
- cruiserLabel: string;
21
- performanceTypeLabel: string;
22
- racerLabel: string;
23
- exportPdfLabel: string;
24
- faqTitle: string;
25
- bibliographyTitle: string;
26
- }
27
-
28
- export type SailAreaLocaleContent = ToolLocaleContent<SailAreaUI>;
29
-
30
- export const sailArea: NauticalToolEntry<SailAreaUI> = {
31
- id: 'sail-area',
32
- icons: {
33
- bg: 'mdi:sail-boat',
34
- fg: 'mdi:wind-power',
35
- },
36
- i18n: {
37
- es: () => import('./i18n/es').then((m) => m.content),
38
- en: () => import('./i18n/en').then((m) => m.content),
39
- fr: () => import('./i18n/fr').then((m) => m.content),
40
- de: () => import('./i18n/de').then((m) => m.content),
41
- id: () => import('./i18n/id').then((m) => m.content),
42
- it: () => import('./i18n/it').then((m) => m.content),
43
- ja: () => import('./i18n/ja').then((m) => m.content),
44
- ko: () => import('./i18n/ko').then((m) => m.content),
45
- nl: () => import('./i18n/nl').then((m) => m.content),
46
- pl: () => import('./i18n/pl').then((m) => m.content),
47
- pt: () => import('./i18n/pt').then((m) => m.content),
48
- ru: () => import('./i18n/ru').then((m) => m.content),
49
- sv: () => import('./i18n/sv').then((m) => m.content),
50
- tr: () => import('./i18n/tr').then((m) => m.content),
51
- zh: () => import('./i18n/zh').then((m) => m.content),
52
- },
53
- };
54
-
55
-
1
+ import { sailArea } from './entry';
2
+ export * from './entry';
56
3
  export const SAIL_AREA_TOOL: ToolDefinition = {
57
4
  entry: sailArea,
58
5
  Component: () => import('./component.astro'),