@jjlmoya/utils-drones 1.36.0 → 1.38.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 (72) hide show
  1. package/package.json +17 -5
  2. package/scripts/postinstall.mjs +2 -4
  3. package/src/category/index.ts +4 -0
  4. package/src/components/ProductionBreadcrumb.astro +134 -0
  5. package/src/components/ProductionStructuredData.astro +46 -0
  6. package/src/components/ProductionWidget.astro +182 -0
  7. package/src/entries.ts +4 -0
  8. package/src/i18n/header-ui.ts +15 -0
  9. package/src/i18n/language-ui.ts +9 -0
  10. package/src/i18n/languages.ts +24 -0
  11. package/src/identity/brands.ts +5 -0
  12. package/src/layouts/ProductionCategoryPage.astro +184 -0
  13. package/src/layouts/ProductionPage.astro +218 -0
  14. package/src/layouts/ProductionUtilityPage.astro +283 -0
  15. package/src/mfe/assets.ts +39 -0
  16. package/src/mfe/category-ui.ts +34 -0
  17. package/src/mfe/manifest.ts +45 -0
  18. package/src/mfe/routes.ts +50 -0
  19. package/src/pages/[locale]/[utilities]/[categories]/[category]/[slug]/manifest.json.ts +49 -0
  20. package/src/pages/[locale]/[utilities]/[categories]/[category]/[slug].astro +100 -0
  21. package/src/pages/[locale]/[utilities]/[categories]/[category].astro +44 -0
  22. package/src/pages/index.astro +3 -4
  23. package/src/pages/utilidades/[slug]/manifest.json.ts +28 -0
  24. package/src/pages/utilidades/[slug].astro +90 -0
  25. package/src/pages/utilidades/categorias/[category].astro +38 -0
  26. package/src/tests/diacritics_density.test.ts +1 -1
  27. package/src/tests/inverted_punctuation.test.ts +1 -1
  28. package/src/tests/locale_completeness.test.ts +2 -2
  29. package/src/tests/mfe_cache_contract.test.ts +11 -0
  30. package/src/tests/mfe_manifest.test.ts +28 -0
  31. package/src/tests/registry_contract.test.ts +67 -0
  32. package/src/tests/script_density.test.ts +1 -1
  33. package/src/tests/seo_length.test.ts +1 -0
  34. package/src/tests/tool_validation.test.ts +2 -2
  35. package/src/tests/translation_copy.test.ts +2 -2
  36. package/src/tool/antenna-length-calculator/index.ts +1 -0
  37. package/src/tool/drone-flight-time/index.ts +1 -0
  38. package/src/tool/drone-mission-battery-reserve-planner/bibliography.astro +6 -0
  39. package/src/tool/drone-mission-battery-reserve-planner/bibliography.ts +7 -0
  40. package/src/tool/drone-mission-battery-reserve-planner/component.astro +229 -0
  41. package/src/tool/drone-mission-battery-reserve-planner/controller.ts +124 -0
  42. package/src/tool/drone-mission-battery-reserve-planner/dom-views.ts +114 -0
  43. package/src/tool/drone-mission-battery-reserve-planner/drone-mission-battery-reserve-planner.css +392 -0
  44. package/src/tool/drone-mission-battery-reserve-planner/entry.ts +27 -0
  45. package/src/tool/drone-mission-battery-reserve-planner/evaluator.ts +23 -0
  46. package/src/tool/drone-mission-battery-reserve-planner/i18n/de.ts +223 -0
  47. package/src/tool/drone-mission-battery-reserve-planner/i18n/en.ts +223 -0
  48. package/src/tool/drone-mission-battery-reserve-planner/i18n/es.ts +223 -0
  49. package/src/tool/drone-mission-battery-reserve-planner/i18n/fr.ts +223 -0
  50. package/src/tool/drone-mission-battery-reserve-planner/i18n/id.ts +223 -0
  51. package/src/tool/drone-mission-battery-reserve-planner/i18n/it.ts +223 -0
  52. package/src/tool/drone-mission-battery-reserve-planner/i18n/ja.ts +223 -0
  53. package/src/tool/drone-mission-battery-reserve-planner/i18n/ko.ts +223 -0
  54. package/src/tool/drone-mission-battery-reserve-planner/i18n/nl.ts +223 -0
  55. package/src/tool/drone-mission-battery-reserve-planner/i18n/pl.ts +223 -0
  56. package/src/tool/drone-mission-battery-reserve-planner/i18n/pt.ts +223 -0
  57. package/src/tool/drone-mission-battery-reserve-planner/i18n/ru.ts +223 -0
  58. package/src/tool/drone-mission-battery-reserve-planner/i18n/sv.ts +223 -0
  59. package/src/tool/drone-mission-battery-reserve-planner/i18n/tr.ts +223 -0
  60. package/src/tool/drone-mission-battery-reserve-planner/i18n/zh.ts +223 -0
  61. package/src/tool/drone-mission-battery-reserve-planner/index.ts +11 -0
  62. package/src/tool/drone-mission-battery-reserve-planner/logic.test.ts +94 -0
  63. package/src/tool/drone-mission-battery-reserve-planner/logic.ts +203 -0
  64. package/src/tool/drone-mission-battery-reserve-planner/seo.astro +15 -0
  65. package/src/tool/drone-mission-battery-reserve-planner/storage.ts +59 -0
  66. package/src/tool/drone-mission-battery-reserve-planner/ui.ts +78 -0
  67. package/src/tool/gps-coordinates-converter/index.ts +1 -0
  68. package/src/tools.ts +4 -0
  69. package/src/types.ts +4 -6
  70. package/src/worker.ts +25 -0
  71. package/src/pages/[locale]/[slug].astro +0 -161
  72. package/src/pages/[locale].astro +0 -251
@@ -1,251 +0,0 @@
1
- ---
2
- import PreviewLayout from '../layouts/PreviewLayout.astro';
3
- import PreviewNavSidebar from '../components/PreviewNavSidebar.astro';
4
- import { dronesCategory, ALL_TOOLS } from '../index';
5
- import { Icon } from 'astro-icon/components';
6
- import type { KnownLocale, ToolLocaleContent } from '../types';
7
-
8
- export async function getStaticPaths() {
9
- const locales = ['en', 'es', 'fr'] as KnownLocale[];
10
- return locales.map(locale => ({ params: { locale } }));
11
- }
12
-
13
- const { locale: currentLocale } = Astro.params as { locale: KnownLocale };
14
-
15
- const categoryContent = await dronesCategory.i18n[currentLocale]!();
16
-
17
- const tools = ALL_TOOLS || [];
18
-
19
- const toolsWithContent = tools.length > 0
20
- ? await Promise.all(
21
- tools.map(async ({ entry, Component }) => {
22
- const languages = Object.keys(entry.i18n);
23
- const localeEntries = await Promise.all(
24
- languages.map(async (l) => {
25
- const content = await entry.i18n[l as KnownLocale]!();
26
- return [l, content];
27
- })
28
- );
29
-
30
- const localeContents = Object.fromEntries(localeEntries) as Record<string, ToolLocaleContent<Record<string, string>>>;
31
-
32
- const currentLocaleContent = localeContents[currentLocale] || localeContents['en'] || localeContents['es'];
33
- const availableLocales: Record<string, string> = {};
34
-
35
- for (const l of languages) {
36
- const lCont = localeContents[l];
37
- if (lCont) {
38
- availableLocales[l] = `/${l}/${lCont.slug}`;
39
- }
40
- }
41
-
42
- return { entry, Component, locale: currentLocaleContent, availableLocales };
43
- })
44
- )
45
- : [];
46
- ---
47
-
48
- <PreviewLayout
49
- title={categoryContent.title}
50
- currentLocale={currentLocale}
51
- hasSidebar={true}
52
- >
53
- <PreviewNavSidebar
54
- slot="sidebar"
55
- categoryTitle={categoryContent.title}
56
- tools={toolsWithContent.map(({ entry, locale, availableLocales }) => {
57
- const href = availableLocales[currentLocale] || (locale ? `/${currentLocale}/${locale.slug}` : '#');
58
- return {
59
- id: entry.id,
60
- title: locale?.title || entry.id,
61
- href: href,
62
- };
63
- })}
64
- />
65
- <div class="dashboard">
66
- <header class="preview-header">
67
- <span class="badge">preview · @jjlmoya/utils-template</span>
68
- <h1>{categoryContent.title}</h1>
69
- <p>{categoryContent.description}</p>
70
- </header>
71
-
72
- <div class="tool-list">
73
- {toolsWithContent?.map(({ entry, locale, availableLocales }) => (
74
- <article class="tool-card">
75
- <a href={availableLocales?.[currentLocale] || (locale ? `/${currentLocale}/${locale.slug}` : '#')} class="tool-card-link">
76
- <div class="tool-icons">
77
- <div class="icon-wrapper bg">
78
- <Icon name={entry.icons.bg} />
79
- </div>
80
- <div class="icon-wrapper fg">
81
- <Icon name={entry.icons.fg} />
82
- </div>
83
- </div>
84
- <div class="tool-card-content">
85
- <h2 class="tool-title">{locale?.title}</h2>
86
- <p class="tool-description">{locale?.description}</p>
87
- </div>
88
- <div class="tool-card-meta">
89
- <span class="tool-id">{entry.id}</span>
90
- </div>
91
- </a>
92
-
93
- {availableLocales && Object.keys(availableLocales).length > 1 && (
94
- <div class="tool-locales">
95
- {Object.entries(availableLocales).map(([l, url]) => (
96
- <a href={url} class="locale-badge" title={`Ver en ${l.toUpperCase()}`} class:list={{ active: l === currentLocale }}>
97
- {l.toUpperCase()}
98
- </a>
99
- ))}
100
- </div>
101
- )}
102
- </article>
103
- ))}
104
- </div>
105
- </div>
106
- </PreviewLayout>
107
-
108
- <style>
109
- .dashboard {
110
- display: flex;
111
- flex-direction: column;
112
- gap: 5rem;
113
- }
114
- .preview-header {
115
- text-align: center;
116
- padding-bottom: 3rem;
117
- border-bottom: 1px solid var(--border-color);
118
- }
119
- .badge {
120
- display: inline-block;
121
- padding: 0.25rem 0.75rem;
122
- background: var(--accent);
123
- border-radius: 99px;
124
- font-size: 0.7rem;
125
- font-weight: 800;
126
- margin-bottom: 1.5rem;
127
- color: var(--text-base);
128
- letter-spacing: 0.05em;
129
- }
130
- h1 {
131
- font-size: clamp(2rem, 6vw, 3.5rem);
132
- font-weight: 900;
133
- margin: 0 0 1rem;
134
- background: linear-gradient(to bottom, var(--text-base), var(--text-muted));
135
- -webkit-background-clip: text;
136
- -webkit-text-fill-color: transparent;
137
- background-clip: text;
138
- }
139
- .preview-header p {
140
- color: var(--text-muted);
141
- font-size: 1.1rem;
142
- margin: 0;
143
- }
144
- .tool-list {
145
- display: grid;
146
- grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
147
- gap: 2rem;
148
- }
149
- .tool-card {
150
- display: flex;
151
- flex-direction: column;
152
- gap: 1rem;
153
- }
154
- .tool-card-link {
155
- flex: 1;
156
- display: flex;
157
- flex-direction: column;
158
- padding: 1.5rem;
159
- background: var(--bg-surface);
160
- border: 1px solid var(--border-color);
161
- border-radius: 0.75rem;
162
- text-decoration: none;
163
- transition: all 0.2s ease;
164
- }
165
- .tool-card-link:hover {
166
- border-color: var(--accent);
167
- background: rgba(244, 63, 94, 0.05);
168
- transform: translateY(-2px);
169
- }
170
- .tool-icons {
171
- display: flex;
172
- align-items: center;
173
- gap: 1rem;
174
- margin-bottom: 1.25rem;
175
- }
176
- .icon-wrapper {
177
- display: flex;
178
- align-items: center;
179
- justify-content: center;
180
- width: 3rem;
181
- height: 3rem;
182
- border-radius: 0.5rem;
183
- font-size: 1.5rem;
184
- }
185
- .icon-wrapper.bg {
186
- background: var(--accent);
187
- color: var(--text-base);
188
- }
189
- .icon-wrapper.fg {
190
- background: var(--bg-page);
191
- border: 1px solid var(--border-color);
192
- color: var(--accent);
193
- }
194
- .tool-card-content {
195
- flex: 1;
196
- display: flex;
197
- flex-direction: column;
198
- }
199
- .tool-title {
200
- font-size: 1.25rem;
201
- font-weight: 700;
202
- margin: 0 0 0.5rem;
203
- color: var(--text-base);
204
- }
205
- .tool-description {
206
- font-size: 0.9375rem;
207
- color: var(--text-muted);
208
- line-height: 1.5;
209
- margin: 0;
210
- }
211
- .tool-card-meta {
212
- padding-top: 1rem;
213
- border-top: 1px solid var(--border-color);
214
- margin-top: 1.5rem;
215
- }
216
- .tool-id {
217
- display: inline-block;
218
- font-size: 0.7rem;
219
- background: var(--bg-page);
220
- border: 1px solid var(--border-color);
221
- padding: 0.35rem 0.75rem;
222
- border-radius: 0.4rem;
223
- color: var(--accent);
224
- font-weight: 600;
225
- }
226
- .tool-locales {
227
- display: flex;
228
- gap: 0.5rem;
229
- flex-wrap: wrap;
230
- }
231
- .locale-badge {
232
- display: inline-block;
233
- padding: 0.4rem 0.85rem;
234
- background: var(--bg-page);
235
- border: 1px solid var(--border-color);
236
- border-radius: 0.4rem;
237
- color: var(--text-muted);
238
- text-decoration: none;
239
- font-size: 0.75rem;
240
- font-weight: 600;
241
- text-transform: uppercase;
242
- letter-spacing: 0.05em;
243
- transition: all 0.15s ease;
244
- }
245
- .locale-badge:hover,
246
- .locale-badge.active {
247
- color: var(--accent);
248
- border-color: var(--accent);
249
- background: rgba(244, 63, 94, 0.1);
250
- }
251
- </style>