@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.
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-nautical",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
- "./data": "./src/data.ts"
9
+ "./data": "./src/data.ts",
10
+ "./entries": "./src/entries.ts"
10
11
  },
11
12
  "files": [
12
- "src"
13
+ "src",
14
+ "scripts"
13
15
  ],
14
16
  "publishConfig": {
15
17
  "access": "public"
@@ -28,7 +30,8 @@
28
30
  "postversion": "git push && git push --tags",
29
31
  "patch": "npm version patch",
30
32
  "minor": "npm version minor",
31
- "major": "npm version major"
33
+ "major": "npm version major",
34
+ "postinstall": "node scripts/postinstall.mjs"
32
35
  },
33
36
  "lint-staged": {
34
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
+ }
@@ -1,10 +1,10 @@
1
1
  import type { NauticalCategoryEntry, CategoryLocaleContent } from '../types';
2
- import { tideCalculator } from '../tool/tideCalculator';
3
- import { underKeel } from '../tool/underKeel';
4
- import { nauticalConverter } from '../tool/nauticalConverter';
5
- import { sailArea } from '../tool/sailArea';
6
- import { speedConverter } from '../tool/speedConverter';
7
- import { endurance } from '../tool/endurance';
2
+ import { tideCalculator } from '../tool/tideCalculator/entry';
3
+ import { underKeel } from '../tool/underKeel/entry';
4
+ import { nauticalConverter } from '../tool/nauticalConverter/entry';
5
+ import { sailArea } from '../tool/sailArea/entry';
6
+ import { speedConverter } from '../tool/speedConverter/entry';
7
+ import { endurance } from '../tool/endurance/entry';
8
8
 
9
9
  export type { CategoryLocaleContent };
10
10
 
package/src/entries.ts ADDED
@@ -0,0 +1,20 @@
1
+ export { endurance } from './tool/endurance/entry';
2
+ export type { EnduranceUI, EnduranceLocaleContent } from './tool/endurance/entry';
3
+ export { nauticalConverter } from './tool/nauticalConverter/entry';
4
+ export type { NauticalConverterUI, NauticalConverterLocaleContent } from './tool/nauticalConverter/entry';
5
+ export { sailArea } from './tool/sailArea/entry';
6
+ export type { SailAreaUI, SailAreaLocaleContent } from './tool/sailArea/entry';
7
+ export { speedConverter } from './tool/speedConverter/entry';
8
+ export type { SpeedConverterUI, SpeedConverterLocaleContent } from './tool/speedConverter/entry';
9
+ export { tideCalculator } from './tool/tideCalculator/entry';
10
+ export type { TideCalculatorUI, TideCalculatorLocaleContent } from './tool/tideCalculator/entry';
11
+ export { underKeel } from './tool/underKeel/entry';
12
+ export type { UnderKeelUI, UnderKeelLocaleContent } from './tool/underKeel/entry';
13
+ export { nauticalCategory } from './category';
14
+ import { endurance } from './tool/endurance/entry';
15
+ import { nauticalConverter } from './tool/nauticalConverter/entry';
16
+ import { sailArea } from './tool/sailArea/entry';
17
+ import { speedConverter } from './tool/speedConverter/entry';
18
+ import { tideCalculator } from './tool/tideCalculator/entry';
19
+ import { underKeel } from './tool/underKeel/entry';
20
+ export const ALL_ENTRIES = [endurance, nauticalConverter, sailArea, speedConverter, tideCalculator, underKeel];
@@ -308,342 +308,3 @@ const { ui } = Astro.props;
308
308
  new EnduranceCalculator();
309
309
  </script>
310
310
 
311
- <style>
312
- .endurance-calculator {
313
- --n-bg: #fff;
314
- --n-bg-muted: #f1f5f9;
315
- --n-text: #0f172a;
316
- --n-text-muted: #475569;
317
- --n-text-dim: #64748b;
318
- --n-border: #e2e8f0;
319
- --n-shadow: rgba(0, 0, 0, 0.05);
320
- --n-primary: #3b82f6;
321
- --n-primary-on: #fff;
322
- --n-accent: #6366f1;
323
- --n-cyan: #0891b2;
324
- --n-success: #10b981;
325
- --n-warning: #f59e0b;
326
- --n-error: #f43f5e;
327
- --ec-hero-bg: #0f172a;
328
- --ec-hero-label: #22d3ee;
329
-
330
- max-width: 1000px;
331
- margin: 0 auto;
332
- }
333
-
334
- :global(.theme-dark) .endurance-calculator {
335
- --n-bg: #0f172a;
336
- --n-bg-muted: #1e293b;
337
- --n-text: #f8fafc;
338
- --n-text-muted: #94a3b8;
339
- --n-text-dim: #64748b;
340
- --n-border: #334155;
341
- --n-shadow: rgba(0, 0, 0, 0.3);
342
- --n-primary: #60a5fa;
343
- --n-primary-on: #fff;
344
- --n-accent: #818cf8;
345
- --n-cyan: #22d3ee;
346
- --n-success: #34d399;
347
- --n-warning: #fbbf24;
348
- --n-error: #fb7185;
349
- --ec-hero-bg: #020617;
350
- --ec-hero-label: #22d3ee;
351
- }
352
-
353
- .ec-main-container {
354
- background: var(--n-bg);
355
- border: 1px solid var(--n-border);
356
- border-radius: 1.5rem;
357
- display: grid;
358
- grid-template-columns: 360px 1fr;
359
- overflow: hidden;
360
- box-shadow: 0 20px 40px var(--n-shadow);
361
- }
362
-
363
- .ec-sidebar-inputs {
364
- padding: 1.5rem;
365
- border-right: 1px solid var(--n-border);
366
- background: var(--n-bg-muted);
367
- display: flex;
368
- flex-direction: column;
369
- gap: 1.2rem;
370
- }
371
-
372
- .ec-compact-group {
373
- display: flex;
374
- flex-direction: column;
375
- gap: 0.4rem;
376
- }
377
-
378
- .ec-compact-group label {
379
- font-size: 0.7rem;
380
- font-weight: 800;
381
- text-transform: uppercase;
382
- color: var(--n-text-muted);
383
- letter-spacing: 0.06em;
384
- }
385
-
386
- .ec-dual-row {
387
- display: grid;
388
- grid-template-columns: 1fr 1fr;
389
- gap: 0.5rem;
390
- }
391
-
392
- .ec-sub-label {
393
- font-size: 0.65rem;
394
- color: var(--n-text-muted);
395
- font-weight: 700;
396
- margin-bottom: 0.2rem;
397
- display: block;
398
- }
399
-
400
- .ec-field-wrapper {
401
- position: relative;
402
- display: flex;
403
- align-items: center;
404
- }
405
-
406
- .ec-field-icon {
407
- position: absolute;
408
- left: 8px;
409
- font-size: 0.9rem;
410
- color: var(--n-text-muted);
411
- pointer-events: none;
412
- }
413
-
414
- .ec-compact-input,
415
- .ec-compact-select {
416
- width: 100%;
417
- background: var(--n-bg);
418
- border: 1px solid var(--n-border);
419
- border-radius: 0.5rem;
420
- padding: 0.6rem 2.4rem 0.6rem 2.2rem;
421
- font-size: 0.95rem;
422
- font-weight: 700;
423
- color: var(--n-text);
424
- outline: none;
425
- transition: border-color 0.2s;
426
- }
427
-
428
- .ec-compact-input:focus,
429
- .ec-compact-select:focus {
430
- border-color: var(--n-primary);
431
- }
432
-
433
- .ec-compact-select {
434
- padding-right: 0.6rem;
435
- cursor: pointer;
436
- }
437
-
438
- .ec-unit-tag {
439
- position: absolute;
440
- right: 8px;
441
- font-size: 0.65rem;
442
- font-weight: 800;
443
- color: var(--n-text-muted);
444
- pointer-events: none;
445
- }
446
-
447
- .ec-dashboard-panel {
448
- padding: 2rem;
449
- display: flex;
450
- flex-direction: column;
451
- gap: 2rem;
452
- }
453
-
454
- .ec-hero-display {
455
- background: var(--ec-hero-bg);
456
- border-radius: 1rem;
457
- padding: 2rem;
458
- color: var(--n-primary-on);
459
- display: flex;
460
- flex-direction: column;
461
- gap: 1.5rem;
462
- }
463
-
464
- .ec-hero-top {
465
- display: flex;
466
- justify-content: space-between;
467
- align-items: flex-start;
468
- }
469
-
470
- .ec-display-title {
471
- font-size: 0.65rem;
472
- font-weight: 900;
473
- text-transform: uppercase;
474
- color: var(--ec-hero-label);
475
- letter-spacing: 0.1em;
476
- }
477
-
478
- .ec-main-value-row {
479
- display: flex;
480
- align-items: baseline;
481
- gap: 0.5rem;
482
- }
483
-
484
- .ec-main-value {
485
- font-size: 5rem;
486
- font-weight: 900;
487
- color: var(--n-primary-on);
488
- line-height: 1;
489
- }
490
-
491
- .ec-main-unit {
492
- font-size: 1.2rem;
493
- font-weight: 700;
494
- opacity: 0.4;
495
- color: var(--n-primary-on);
496
- }
497
-
498
- .ec-fuel-badge {
499
- font-size: 0.85rem;
500
- font-weight: 900;
501
- color: var(--ec-hero-label);
502
- letter-spacing: 0.05em;
503
- }
504
-
505
- .ec-progress-track {
506
- height: 10px;
507
- background: rgba(255, 255, 255, 0.1);
508
- border-radius: 5px;
509
- position: relative;
510
- overflow: hidden;
511
- }
512
-
513
- .ec-progress-fill {
514
- height: 100%;
515
- background: linear-gradient(90deg, var(--n-error) 0%, var(--n-cyan) 100%);
516
- width: 0%;
517
- transition: width 0.8s ease-out;
518
- }
519
-
520
- .ec-marker {
521
- position: absolute;
522
- top: 0;
523
- bottom: 0;
524
- width: 2px;
525
- background: var(--n-primary-on);
526
- z-index: 2;
527
- }
528
-
529
- .ec-stats-grid {
530
- display: grid;
531
- grid-template-columns: repeat(2, 1fr);
532
- gap: 1rem;
533
- }
534
-
535
- .ec-stat-card {
536
- background: var(--n-bg-muted);
537
- border: 1px solid var(--n-border);
538
- border-radius: 0.75rem;
539
- padding: 1rem;
540
- display: flex;
541
- flex-direction: column;
542
- gap: 0.2rem;
543
- }
544
-
545
- .ec-stat-label {
546
- font-size: 0.6rem;
547
- font-weight: 800;
548
- text-transform: uppercase;
549
- color: var(--n-text-muted);
550
- letter-spacing: 0.06em;
551
- }
552
-
553
- .ec-stat-value {
554
- font-size: 1.4rem;
555
- font-weight: 900;
556
- color: var(--n-text);
557
- }
558
-
559
- .ec-stat-value.danger {
560
- color: var(--n-error);
561
- }
562
-
563
- .ec-stat-card.hidden {
564
- display: none;
565
- }
566
-
567
- .ec-inverter-card {
568
- padding: 1.5rem;
569
- background: var(--n-bg-muted);
570
- border: 1px dashed var(--n-border);
571
- border-radius: 1rem;
572
- display: flex;
573
- flex-direction: column;
574
- gap: 1rem;
575
- }
576
-
577
- .ec-inverter-header {
578
- font-size: 0.75rem;
579
- font-weight: 900;
580
- text-transform: uppercase;
581
- color: var(--n-cyan);
582
- letter-spacing: 0.06em;
583
- }
584
-
585
- .ec-inverter-row {
586
- display: grid;
587
- grid-template-columns: 1fr 1fr;
588
- gap: 1.5rem;
589
- align-items: center;
590
- }
591
-
592
- .ec-inverter-label {
593
- font-size: 0.65rem;
594
- font-weight: 800;
595
- text-transform: uppercase;
596
- color: var(--n-text-muted);
597
- margin-bottom: 0.3rem;
598
- }
599
-
600
- .ec-inverter-value {
601
- font-size: 2rem;
602
- font-weight: 900;
603
- color: var(--n-cyan);
604
- }
605
-
606
- .ec-inverter-unit {
607
- font-size: 0.85rem;
608
- color: var(--n-text-muted);
609
- font-weight: 700;
610
- }
611
-
612
- .ec-warning-bar {
613
- background: color-mix(in srgb, var(--n-error), transparent 90%);
614
- padding: 0.8rem 1.2rem;
615
- border-radius: 0.5rem;
616
- display: flex;
617
- align-items: center;
618
- gap: 0.6rem;
619
- font-size: 0.75rem;
620
- font-weight: 600;
621
- color: var(--n-error);
622
- }
623
-
624
- .ec-warning-icon {
625
- font-size: 1rem;
626
- flex-shrink: 0;
627
- }
628
-
629
- @media (max-width: 800px) {
630
- .ec-main-container {
631
- grid-template-columns: 1fr;
632
- }
633
-
634
- .ec-sidebar-inputs {
635
- border-right: none;
636
- border-bottom: 1px solid var(--n-border);
637
- }
638
- }
639
-
640
- @media (max-width: 480px) {
641
- .ec-main-value {
642
- font-size: 2.8rem;
643
- }
644
-
645
- .ec-stats-grid {
646
- grid-template-columns: 1fr;
647
- }
648
- }
649
- </style>
@@ -0,0 +1,56 @@
1
+ import type { NauticalToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ export interface EnduranceUI {
4
+ [key: string]: string;
5
+ tankCapacityLabel: string;
6
+ mainTankLabel: string;
7
+ auxTankLabel: string;
8
+ currentFuelLabel: string;
9
+ seaConditionsLabel: string;
10
+ consumptionLabel: string;
11
+ cruiseSpeedLabel: string;
12
+ reserveLabel: string;
13
+ fuelPriceLabel: string;
14
+ maxRangeLabel: string;
15
+ realPerformanceLabel: string;
16
+ hoursLabel: string;
17
+ safeMilesLabel: string;
18
+ tankValueLabel: string;
19
+ inverseCalcLabel: string;
20
+ desiredDistLabel: string;
21
+ minFuelLabel: string;
22
+ warningLabel: string;
23
+ seaCalm: string;
24
+ seaLight: string;
25
+ seaModerate: string;
26
+ seaStorm: string;
27
+ faqTitle: string;
28
+ bibliographyTitle: string;
29
+ }
30
+
31
+ export type EnduranceLocaleContent = ToolLocaleContent<EnduranceUI>;
32
+
33
+ export const endurance: NauticalToolEntry<EnduranceUI> = {
34
+ id: 'endurance',
35
+ icons: {
36
+ bg: 'mdi:fuel',
37
+ fg: 'mdi:map-marker-distance',
38
+ },
39
+ i18n: {
40
+ es: () => import('./i18n/es').then((m) => m.content),
41
+ en: () => import('./i18n/en').then((m) => m.content),
42
+ fr: () => import('./i18n/fr').then((m) => m.content),
43
+ de: () => import('./i18n/de').then((m) => m.content),
44
+ id: () => import('./i18n/id').then((m) => m.content),
45
+ it: () => import('./i18n/it').then((m) => m.content),
46
+ ja: () => import('./i18n/ja').then((m) => m.content),
47
+ ko: () => import('./i18n/ko').then((m) => m.content),
48
+ nl: () => import('./i18n/nl').then((m) => m.content),
49
+ pl: () => import('./i18n/pl').then((m) => m.content),
50
+ pt: () => import('./i18n/pt').then((m) => m.content),
51
+ ru: () => import('./i18n/ru').then((m) => m.content),
52
+ sv: () => import('./i18n/sv').then((m) => m.content),
53
+ tr: () => import('./i18n/tr').then((m) => m.content),
54
+ zh: () => import('./i18n/zh').then((m) => m.content),
55
+ },
56
+ };
@@ -1,61 +1,5 @@
1
- import type { NauticalToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
-
3
- export interface EnduranceUI {
4
- [key: string]: string;
5
- tankCapacityLabel: string;
6
- mainTankLabel: string;
7
- auxTankLabel: string;
8
- currentFuelLabel: string;
9
- seaConditionsLabel: string;
10
- consumptionLabel: string;
11
- cruiseSpeedLabel: string;
12
- reserveLabel: string;
13
- fuelPriceLabel: string;
14
- maxRangeLabel: string;
15
- realPerformanceLabel: string;
16
- hoursLabel: string;
17
- safeMilesLabel: string;
18
- tankValueLabel: string;
19
- inverseCalcLabel: string;
20
- desiredDistLabel: string;
21
- minFuelLabel: string;
22
- warningLabel: string;
23
- seaCalm: string;
24
- seaLight: string;
25
- seaModerate: string;
26
- seaStorm: string;
27
- faqTitle: string;
28
- bibliographyTitle: string;
29
- }
30
-
31
- export type EnduranceLocaleContent = ToolLocaleContent<EnduranceUI>;
32
-
33
- export const endurance: NauticalToolEntry<EnduranceUI> = {
34
- id: 'endurance',
35
- icons: {
36
- bg: 'mdi:fuel',
37
- fg: 'mdi:map-marker-distance',
38
- },
39
- i18n: {
40
- es: () => import('./i18n/es').then((m) => m.content),
41
- en: () => import('./i18n/en').then((m) => m.content),
42
- fr: () => import('./i18n/fr').then((m) => m.content),
43
- de: () => import('./i18n/de').then((m) => m.content),
44
- id: () => import('./i18n/id').then((m) => m.content),
45
- it: () => import('./i18n/it').then((m) => m.content),
46
- ja: () => import('./i18n/ja').then((m) => m.content),
47
- ko: () => import('./i18n/ko').then((m) => m.content),
48
- nl: () => import('./i18n/nl').then((m) => m.content),
49
- pl: () => import('./i18n/pl').then((m) => m.content),
50
- pt: () => import('./i18n/pt').then((m) => m.content),
51
- ru: () => import('./i18n/ru').then((m) => m.content),
52
- sv: () => import('./i18n/sv').then((m) => m.content),
53
- tr: () => import('./i18n/tr').then((m) => m.content),
54
- zh: () => import('./i18n/zh').then((m) => m.content),
55
- },
56
- };
57
-
58
-
1
+ import { endurance } from './entry';
2
+ export * from './entry';
59
3
  export const ENDURANCE_TOOL: ToolDefinition = {
60
4
  entry: endurance,
61
5
  Component: () => import('./component.astro'),