@jjlmoya/utils-tools 1.1.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 (134) hide show
  1. package/package.json +63 -0
  2. package/src/category/i18n/en.ts +172 -0
  3. package/src/category/i18n/es.ts +172 -0
  4. package/src/category/i18n/fr.ts +172 -0
  5. package/src/category/index.ts +23 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +90 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +23 -0
  22. package/src/tests/title_quality.test.ts +56 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/date-diff-calculator/bibliography.astro +14 -0
  25. package/src/tool/date-diff-calculator/component.astro +370 -0
  26. package/src/tool/date-diff-calculator/i18n/en.ts +132 -0
  27. package/src/tool/date-diff-calculator/i18n/es.ts +132 -0
  28. package/src/tool/date-diff-calculator/i18n/fr.ts +132 -0
  29. package/src/tool/date-diff-calculator/index.ts +22 -0
  30. package/src/tool/date-diff-calculator/seo.astro +14 -0
  31. package/src/tool/date-diff-calculator/ui.ts +17 -0
  32. package/src/tool/drive-direct-link/bibliography.astro +14 -0
  33. package/src/tool/drive-direct-link/component.astro +280 -0
  34. package/src/tool/drive-direct-link/i18n/en.ts +118 -0
  35. package/src/tool/drive-direct-link/i18n/es.ts +118 -0
  36. package/src/tool/drive-direct-link/i18n/fr.ts +118 -0
  37. package/src/tool/drive-direct-link/index.ts +22 -0
  38. package/src/tool/drive-direct-link/seo.astro +14 -0
  39. package/src/tool/drive-direct-link/ui.ts +10 -0
  40. package/src/tool/email-list-cleaner/bibliography.astro +14 -0
  41. package/src/tool/email-list-cleaner/component.astro +375 -0
  42. package/src/tool/email-list-cleaner/i18n/en.ts +140 -0
  43. package/src/tool/email-list-cleaner/i18n/es.ts +140 -0
  44. package/src/tool/email-list-cleaner/i18n/fr.ts +140 -0
  45. package/src/tool/email-list-cleaner/index.ts +22 -0
  46. package/src/tool/email-list-cleaner/seo.astro +14 -0
  47. package/src/tool/email-list-cleaner/ui.ts +15 -0
  48. package/src/tool/env-badge-spain/bibliography.astro +14 -0
  49. package/src/tool/env-badge-spain/component.astro +303 -0
  50. package/src/tool/env-badge-spain/components/BadgeForm.astro +243 -0
  51. package/src/tool/env-badge-spain/components/BadgeResult.astro +151 -0
  52. package/src/tool/env-badge-spain/i18n/en.ts +153 -0
  53. package/src/tool/env-badge-spain/i18n/es.ts +153 -0
  54. package/src/tool/env-badge-spain/i18n/fr.ts +153 -0
  55. package/src/tool/env-badge-spain/index.ts +22 -0
  56. package/src/tool/env-badge-spain/seo.astro +14 -0
  57. package/src/tool/env-badge-spain/ui.ts +53 -0
  58. package/src/tool/morse-beacon/bibliography.astro +14 -0
  59. package/src/tool/morse-beacon/component.astro +534 -0
  60. package/src/tool/morse-beacon/i18n/en.ts +157 -0
  61. package/src/tool/morse-beacon/i18n/es.ts +157 -0
  62. package/src/tool/morse-beacon/i18n/fr.ts +157 -0
  63. package/src/tool/morse-beacon/index.ts +22 -0
  64. package/src/tool/morse-beacon/logic/MorseEngine.ts +124 -0
  65. package/src/tool/morse-beacon/seo.astro +14 -0
  66. package/src/tool/morse-beacon/ui.ts +18 -0
  67. package/src/tool/password-generator/bibliography.astro +14 -0
  68. package/src/tool/password-generator/component.astro +259 -0
  69. package/src/tool/password-generator/components/Config.astro +227 -0
  70. package/src/tool/password-generator/components/Display.astro +147 -0
  71. package/src/tool/password-generator/components/Strength.astro +70 -0
  72. package/src/tool/password-generator/i18n/en.ts +166 -0
  73. package/src/tool/password-generator/i18n/es.ts +166 -0
  74. package/src/tool/password-generator/i18n/fr.ts +166 -0
  75. package/src/tool/password-generator/index.ts +22 -0
  76. package/src/tool/password-generator/seo.astro +14 -0
  77. package/src/tool/password-generator/ui.ts +16 -0
  78. package/src/tool/routes/bibliography.astro +14 -0
  79. package/src/tool/routes/component.astro +543 -0
  80. package/src/tool/routes/i18n/en.ts +157 -0
  81. package/src/tool/routes/i18n/es.ts +157 -0
  82. package/src/tool/routes/i18n/fr.ts +157 -0
  83. package/src/tool/routes/index.ts +22 -0
  84. package/src/tool/routes/logic/GeocodingService.ts +60 -0
  85. package/src/tool/routes/logic/RouteManager.ts +192 -0
  86. package/src/tool/routes/logic/RouteService.ts +66 -0
  87. package/src/tool/routes/seo.astro +14 -0
  88. package/src/tool/routes/ui.ts +16 -0
  89. package/src/tool/rule-of-three/bibliography.astro +14 -0
  90. package/src/tool/rule-of-three/component.astro +369 -0
  91. package/src/tool/rule-of-three/i18n/en.ts +171 -0
  92. package/src/tool/rule-of-three/i18n/es.ts +171 -0
  93. package/src/tool/rule-of-three/i18n/fr.ts +171 -0
  94. package/src/tool/rule-of-three/index.ts +22 -0
  95. package/src/tool/rule-of-three/seo.astro +14 -0
  96. package/src/tool/rule-of-three/ui.ts +13 -0
  97. package/src/tool/seo-content-optimizer/bibliography.astro +14 -0
  98. package/src/tool/seo-content-optimizer/component.astro +552 -0
  99. package/src/tool/seo-content-optimizer/i18n/en.ts +136 -0
  100. package/src/tool/seo-content-optimizer/i18n/es.ts +136 -0
  101. package/src/tool/seo-content-optimizer/i18n/fr.ts +136 -0
  102. package/src/tool/seo-content-optimizer/index.ts +22 -0
  103. package/src/tool/seo-content-optimizer/seo.astro +14 -0
  104. package/src/tool/seo-content-optimizer/ui.ts +29 -0
  105. package/src/tool/speed-reader/bibliography.astro +14 -0
  106. package/src/tool/speed-reader/component.astro +586 -0
  107. package/src/tool/speed-reader/i18n/en.ts +152 -0
  108. package/src/tool/speed-reader/i18n/es.ts +152 -0
  109. package/src/tool/speed-reader/i18n/fr.ts +152 -0
  110. package/src/tool/speed-reader/index.ts +22 -0
  111. package/src/tool/speed-reader/logic/RSVPEngine.ts +106 -0
  112. package/src/tool/speed-reader/seo.astro +14 -0
  113. package/src/tool/speed-reader/ui.ts +14 -0
  114. package/src/tool/text-pixel-calculator/bibliography.astro +14 -0
  115. package/src/tool/text-pixel-calculator/component.astro +315 -0
  116. package/src/tool/text-pixel-calculator/components/Editor.astro +240 -0
  117. package/src/tool/text-pixel-calculator/components/Preview.astro +155 -0
  118. package/src/tool/text-pixel-calculator/components/Stats.astro +87 -0
  119. package/src/tool/text-pixel-calculator/i18n/en.ts +133 -0
  120. package/src/tool/text-pixel-calculator/i18n/es.ts +133 -0
  121. package/src/tool/text-pixel-calculator/i18n/fr.ts +133 -0
  122. package/src/tool/text-pixel-calculator/index.ts +22 -0
  123. package/src/tool/text-pixel-calculator/seo.astro +14 -0
  124. package/src/tool/text-pixel-calculator/ui.ts +15 -0
  125. package/src/tool/whatsapp-link/bibliography.astro +14 -0
  126. package/src/tool/whatsapp-link/component.astro +455 -0
  127. package/src/tool/whatsapp-link/i18n/en.ts +128 -0
  128. package/src/tool/whatsapp-link/i18n/es.ts +128 -0
  129. package/src/tool/whatsapp-link/i18n/fr.ts +128 -0
  130. package/src/tool/whatsapp-link/index.ts +22 -0
  131. package/src/tool/whatsapp-link/seo.astro +14 -0
  132. package/src/tool/whatsapp-link/ui.ts +15 -0
  133. package/src/tools.ts +15 -0
  134. package/src/types.ts +72 -0
@@ -0,0 +1,370 @@
1
+ ---
2
+ import type { DateDiffCalculatorUI } from './ui';
3
+
4
+ interface Props {
5
+ ui?: Record<string, unknown>;
6
+ }
7
+
8
+ const { ui } = Astro.props;
9
+ const t = (ui ?? {}) as DateDiffCalculatorUI;
10
+ ---
11
+
12
+ <div class="dd-root" data-ui={JSON.stringify(t)}>
13
+ <div class="dd-card">
14
+ <div class="dd-inputs">
15
+ <div class="dd-field">
16
+ <label class="dd-label" for="dd-start">{t.startLabel}</label>
17
+ <input class="dd-input" type="datetime-local" id="dd-start" />
18
+ <div class="dd-quick">
19
+ <button class="dd-quick-btn" type="button" data-action="now" data-target="dd-start">{t.nowBtn}</button>
20
+ <button class="dd-quick-btn" type="button" data-action="today" data-target="dd-start">{t.todayBtn}</button>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="dd-field">
25
+ <label class="dd-label" for="dd-end">{t.endLabel}</label>
26
+ <input class="dd-input" type="datetime-local" id="dd-end" />
27
+ <div class="dd-quick">
28
+ <button class="dd-quick-btn" type="button" data-action="now" data-target="dd-end">{t.nowBtn}</button>
29
+ <button class="dd-quick-btn" type="button" data-action="tomorrow" data-target="dd-end">{t.tomorrowBtn}</button>
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <div class="dd-result">
35
+ <div class="dd-result-header">
36
+ <span class="dd-result-title" id="dd-direction">{t.elapsed}</span>
37
+ </div>
38
+
39
+ <div class="dd-diff-grid">
40
+ <div class="dd-diff-item">
41
+ <span class="dd-diff-value" id="dd-days">0</span>
42
+ <span class="dd-diff-label">{t.daysLabel}</span>
43
+ </div>
44
+ <div class="dd-diff-item">
45
+ <span class="dd-diff-value" id="dd-hours">0</span>
46
+ <span class="dd-diff-label">{t.hoursLabel}</span>
47
+ </div>
48
+ <div class="dd-diff-item">
49
+ <span class="dd-diff-value" id="dd-mins">0</span>
50
+ <span class="dd-diff-label">{t.minsLabel}</span>
51
+ </div>
52
+ <div class="dd-diff-item">
53
+ <span class="dd-diff-value" id="dd-secs">0</span>
54
+ <span class="dd-diff-label">{t.secsLabel}</span>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="dd-totals">
59
+ <div class="dd-total-item">
60
+ <span class="dd-total-value" id="dd-total-weeks">0</span>
61
+ <span class="dd-total-label">{t.weeksLabel}</span>
62
+ </div>
63
+ <div class="dd-total-item">
64
+ <span class="dd-total-value" id="dd-total-hours">0</span>
65
+ <span class="dd-total-label">{t.totalHoursLabel}</span>
66
+ </div>
67
+ <div class="dd-total-item">
68
+ <span class="dd-total-value" id="dd-total-mins">0</span>
69
+ <span class="dd-total-label">{t.totalMinsLabel}</span>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <style>
77
+ .dd-root {
78
+ --dd-indigo: #6366f1;
79
+ --dd-indigo-dark: #4f46e5;
80
+ --dd-rose: #f43f5e;
81
+ --dd-card-bg: #fff;
82
+ --dd-card-border: rgba(0, 0, 0, 0.05);
83
+ --dd-field-bg: #f8fafc;
84
+ --dd-field-border: #e2e8f0;
85
+ --dd-text-main: #1e293b;
86
+ --dd-text-label: #64748b;
87
+ --dd-result-bg: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
88
+ --dd-result-text: #fff;
89
+ --dd-quick-bg: #f1f5f9;
90
+ --dd-quick-color: #475569;
91
+
92
+ width: 100%;
93
+ max-width: 860px;
94
+ margin: 0 auto;
95
+ }
96
+
97
+ :global(.theme-dark) .dd-root {
98
+ --dd-card-bg: #1e293b;
99
+ --dd-card-border: rgba(255, 255, 255, 0.05);
100
+ --dd-field-bg: #0f172a;
101
+ --dd-field-border: #334155;
102
+ --dd-text-main: #f1f5f9;
103
+ --dd-text-label: #94a3b8;
104
+ --dd-quick-bg: #334155;
105
+ --dd-quick-color: #e2e8f0;
106
+ }
107
+
108
+ .dd-card {
109
+ background: var(--dd-card-bg);
110
+ border: 1px solid var(--dd-card-border);
111
+ border-radius: 2rem;
112
+ padding: 2.5rem;
113
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.1);
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: 2rem;
117
+ }
118
+
119
+ .dd-inputs {
120
+ display: grid;
121
+ grid-template-columns: 1fr 1fr;
122
+ gap: 1.5rem;
123
+ }
124
+
125
+ .dd-field {
126
+ display: flex;
127
+ flex-direction: column;
128
+ gap: 0.5rem;
129
+ }
130
+
131
+ .dd-label {
132
+ font-size: 0.8125rem;
133
+ font-weight: 600;
134
+ color: var(--dd-text-label);
135
+ text-transform: uppercase;
136
+ letter-spacing: 0.05em;
137
+ }
138
+
139
+ .dd-input {
140
+ background: var(--dd-field-bg);
141
+ border: 1px solid var(--dd-field-border);
142
+ border-radius: 0.75rem;
143
+ padding: 0.75rem 1rem;
144
+ color: var(--dd-text-main);
145
+ font-size: 0.9375rem;
146
+ outline: none;
147
+ transition: border-color 0.2s;
148
+ width: 100%;
149
+ box-sizing: border-box;
150
+ }
151
+
152
+ .dd-input:focus {
153
+ border-color: var(--dd-indigo);
154
+ }
155
+
156
+ .dd-quick {
157
+ display: flex;
158
+ gap: 0.5rem;
159
+ }
160
+
161
+ .dd-quick-btn {
162
+ background: var(--dd-quick-bg);
163
+ color: var(--dd-quick-color);
164
+ border: none;
165
+ border-radius: 0.5rem;
166
+ padding: 0.375rem 0.75rem;
167
+ font-size: 0.8125rem;
168
+ font-weight: 600;
169
+ cursor: pointer;
170
+ transition: background 0.15s;
171
+ }
172
+
173
+ .dd-quick-btn:hover {
174
+ background: var(--dd-indigo);
175
+ color: #fff;
176
+ }
177
+
178
+ .dd-result {
179
+ background: var(--dd-result-bg);
180
+ border-radius: 1.5rem;
181
+ padding: 2rem;
182
+ display: flex;
183
+ flex-direction: column;
184
+ gap: 1.5rem;
185
+ }
186
+
187
+ .dd-result-header {
188
+ text-align: center;
189
+ }
190
+
191
+ .dd-result-title {
192
+ font-size: 0.875rem;
193
+ font-weight: 700;
194
+ color: rgba(255, 255, 255, 0.8);
195
+ text-transform: uppercase;
196
+ letter-spacing: 0.1em;
197
+ }
198
+
199
+ .dd-diff-grid {
200
+ display: grid;
201
+ grid-template-columns: repeat(4, 1fr);
202
+ gap: 1rem;
203
+ }
204
+
205
+ .dd-diff-item {
206
+ background: rgba(255, 255, 255, 0.15);
207
+ border-radius: 1rem;
208
+ padding: 1rem;
209
+ display: flex;
210
+ flex-direction: column;
211
+ align-items: center;
212
+ gap: 0.25rem;
213
+ }
214
+
215
+ .dd-diff-value {
216
+ font-size: 2rem;
217
+ font-weight: 800;
218
+ color: var(--dd-result-text);
219
+ line-height: 1;
220
+ }
221
+
222
+ .dd-diff-label {
223
+ font-size: 0.75rem;
224
+ font-weight: 600;
225
+ color: rgba(255, 255, 255, 0.7);
226
+ text-transform: uppercase;
227
+ letter-spacing: 0.05em;
228
+ }
229
+
230
+ .dd-totals {
231
+ display: grid;
232
+ grid-template-columns: repeat(3, 1fr);
233
+ gap: 1rem;
234
+ }
235
+
236
+ .dd-total-item {
237
+ display: flex;
238
+ flex-direction: column;
239
+ align-items: center;
240
+ gap: 0.2rem;
241
+ }
242
+
243
+ .dd-total-value {
244
+ font-size: 1.125rem;
245
+ font-weight: 700;
246
+ color: var(--dd-result-text);
247
+ }
248
+
249
+ .dd-total-label {
250
+ font-size: 0.6875rem;
251
+ font-weight: 500;
252
+ color: rgba(255, 255, 255, 0.65);
253
+ text-transform: uppercase;
254
+ letter-spacing: 0.04em;
255
+ text-align: center;
256
+ }
257
+
258
+ @media (max-width: 640px) {
259
+ .dd-card {
260
+ padding: 1.5rem;
261
+ }
262
+
263
+ .dd-inputs {
264
+ grid-template-columns: 1fr;
265
+ }
266
+
267
+ .dd-diff-grid {
268
+ grid-template-columns: repeat(2, 1fr);
269
+ }
270
+
271
+ .dd-diff-value {
272
+ font-size: 1.5rem;
273
+ }
274
+ }
275
+ </style>
276
+
277
+ <script>
278
+ import type { DateDiffCalculatorUI } from './ui';
279
+
280
+ const root = document.querySelector('.dd-root') as HTMLElement;
281
+ const t = JSON.parse(root?.dataset.ui ?? '{}') as DateDiffCalculatorUI;
282
+
283
+ const startInput = document.getElementById('dd-start') as HTMLInputElement;
284
+ const endInput = document.getElementById('dd-end') as HTMLInputElement;
285
+ const directionEl = document.getElementById('dd-direction') as HTMLElement;
286
+ const daysEl = document.getElementById('dd-days') as HTMLElement;
287
+ const hoursEl = document.getElementById('dd-hours') as HTMLElement;
288
+ const minsEl = document.getElementById('dd-mins') as HTMLElement;
289
+ const secsEl = document.getElementById('dd-secs') as HTMLElement;
290
+ const totalWeeksEl = document.getElementById('dd-total-weeks') as HTMLElement;
291
+ const totalHoursEl = document.getElementById('dd-total-hours') as HTMLElement;
292
+ const totalMinsEl = document.getElementById('dd-total-mins') as HTMLElement;
293
+
294
+ function formatDateTimeLocal(date: Date): string {
295
+ const pad = (n: number) => String(n).padStart(2, '0');
296
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
297
+ }
298
+
299
+ function calculate(): void {
300
+ const start = new Date(startInput.value);
301
+ const end = new Date(endInput.value);
302
+
303
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
304
+ directionEl.textContent = t.invalidDates;
305
+ daysEl.textContent = '0';
306
+ hoursEl.textContent = '0';
307
+ minsEl.textContent = '0';
308
+ secsEl.textContent = '0';
309
+ totalWeeksEl.textContent = '0';
310
+ totalHoursEl.textContent = '0';
311
+ totalMinsEl.textContent = '0';
312
+ return;
313
+ }
314
+
315
+ const isPast = end < start;
316
+ directionEl.textContent = isPast ? t.past : t.elapsed;
317
+
318
+ const diffMs = Math.abs(end.getTime() - start.getTime());
319
+
320
+ const totalMins = Math.floor(diffMs / (1000 * 60));
321
+ const totalHours = Math.floor(diffMs / (1000 * 60 * 60));
322
+ const totalWeeks = Math.floor(diffMs / (1000 * 60 * 60 * 24 * 7));
323
+
324
+ const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
325
+ const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
326
+ const mins = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
327
+ const secs = Math.floor((diffMs % (1000 * 60)) / 1000);
328
+
329
+ daysEl.textContent = days.toLocaleString();
330
+ hoursEl.textContent = String(hours);
331
+ minsEl.textContent = String(mins);
332
+ secsEl.textContent = String(secs);
333
+ totalWeeksEl.textContent = totalWeeks.toLocaleString();
334
+ totalHoursEl.textContent = totalHours.toLocaleString();
335
+ totalMinsEl.textContent = totalMins.toLocaleString();
336
+ }
337
+
338
+ function handleQuickBtn(btn: HTMLButtonElement): void {
339
+ const action = btn.dataset.action;
340
+ const targetId = btn.dataset.target;
341
+ if (!targetId) return;
342
+ const target = document.getElementById(targetId) as HTMLInputElement;
343
+ if (!target) return;
344
+
345
+ const now = new Date();
346
+ if (action === 'now') {
347
+ target.value = formatDateTimeLocal(now);
348
+ } else if (action === 'today') {
349
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
350
+ target.value = formatDateTimeLocal(today);
351
+ } else if (action === 'tomorrow') {
352
+ const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
353
+ target.value = formatDateTimeLocal(tomorrow);
354
+ }
355
+ calculate();
356
+ }
357
+
358
+ startInput.addEventListener('input', calculate);
359
+ endInput.addEventListener('input', calculate);
360
+
361
+ document.querySelectorAll<HTMLButtonElement>('.dd-quick-btn').forEach((btn) => {
362
+ btn.addEventListener('click', () => handleQuickBtn(btn));
363
+ });
364
+
365
+ const now = new Date();
366
+ const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
367
+ startInput.value = formatDateTimeLocal(now);
368
+ endInput.value = formatDateTimeLocal(tomorrow);
369
+ calculate();
370
+ </script>
@@ -0,0 +1,132 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
3
+ import type { DateDiffCalculatorUI } from '../ui';
4
+
5
+ const faqData = [
6
+ {
7
+ question: 'Is this date difference calculator free?',
8
+ answer: 'Yes, it is a 100% free tool accessible from any browser with no registration or downloads required.',
9
+ },
10
+ {
11
+ question: 'How are leap years handled in the total time?',
12
+ answer: 'The tool uses the standard JavaScript chronology (UTC), which automatically handles leap years and the variable number of days in each month to give an exact result.',
13
+ },
14
+ {
15
+ question: 'Can I calculate the difference between hours and minutes too?',
16
+ answer: 'Yes. The input fields allow you to select the exact time. The result gives you a breakdown in days, hours, minutes and seconds, as well as accumulated totals.',
17
+ },
18
+ {
19
+ question: 'Are my date inputs sent to any server?',
20
+ answer: 'No. All processing is done locally in your browser. We do not store or receive any information about the dates you calculate.',
21
+ },
22
+ ];
23
+
24
+ const howToData = [
25
+ { name: 'Select the start date', text: "Enter the starting date and time, or click 'Today' to set it instantly." },
26
+ { name: 'Select the end date', text: "Define the target moment. Use 'Now' to measure the time elapsed up to this exact instant." },
27
+ { name: 'Read the results', text: 'Check the breakdown into days, hours, minutes and seconds, plus the accumulated totals for weeks and hours.' },
28
+ ];
29
+
30
+ const faqSchema: WithContext<FAQPage> = {
31
+ '@context': 'https://schema.org',
32
+ '@type': 'FAQPage',
33
+ mainEntity: faqData.map((item) => ({
34
+ '@type': 'Question',
35
+ name: item.question,
36
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
37
+ })),
38
+ };
39
+
40
+ const howToSchema: WithContext<HowTo> = {
41
+ '@context': 'https://schema.org',
42
+ '@type': 'HowTo',
43
+ name: 'How to calculate the difference between two dates',
44
+ step: howToData.map((s) => ({ '@type': 'HowToStep', name: s.name, text: s.text })),
45
+ };
46
+
47
+ const appSchema: WithContext<SoftwareApplication> = {
48
+ '@context': 'https://schema.org',
49
+ '@type': 'SoftwareApplication',
50
+ name: 'Date Difference Calculator',
51
+ applicationCategory: 'UtilitiesApplication',
52
+ operatingSystem: 'Web',
53
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
54
+ description: 'Calculate exactly how much time has passed between two dates or how long until an event. Results in days, hours and minutes.',
55
+ };
56
+
57
+ const ui: DateDiffCalculatorUI = {
58
+ startLabel: 'Start Date',
59
+ endLabel: 'End Date',
60
+ nowBtn: 'Now',
61
+ todayBtn: 'Today',
62
+ tomorrowBtn: 'Tomorrow',
63
+ daysLabel: 'Days',
64
+ hoursLabel: 'Hours',
65
+ minsLabel: 'Min',
66
+ secsLabel: 'Sec',
67
+ weeksLabel: 'Total Weeks',
68
+ totalHoursLabel: 'Total Hours',
69
+ totalMinsLabel: 'Total Minutes',
70
+ elapsed: 'Elapsed Time',
71
+ past: 'Time in the Past',
72
+ invalidDates: 'Invalid dates',
73
+ };
74
+
75
+ export const content: ToolLocaleContent<DateDiffCalculatorUI> = {
76
+ slug: 'date-difference-calculator',
77
+ title: 'Date Difference Calculator',
78
+ description: 'Calculate exactly how much time has passed between two dates or how long until an event. Free tool with results in days, hours and minutes.',
79
+ ui,
80
+ faqTitle: 'Frequently Asked Questions',
81
+ faq: faqData,
82
+ howTo: howToData,
83
+ bibliographyTitle: 'References',
84
+ bibliography: [
85
+ { name: 'Time and Date: World Clock and Time Zone Converter', url: 'https://www.timeanddate.com/worldclock/' },
86
+ { name: 'Wikipedia: History of the Gregorian Calendar', url: 'https://en.wikipedia.org/wiki/Gregorian_calendar' },
87
+ { name: 'Wikipedia: Eisenhower Matrix and Time Management', url: 'https://en.wikipedia.org/wiki/Time_management#The_Eisenhower_Method' },
88
+ ],
89
+ schemas: [faqSchema, howToSchema, appSchema],
90
+ seo: [
91
+ { type: 'title', level: 2, text: 'Date difference calculator with days, hours and minutes' },
92
+ {
93
+ type: 'paragraph',
94
+ html: 'Calculating the <strong>difference between two dates</strong> is one of the most common and underrated tasks in both everyday life and professional environments. Whether you are planning a product launch, calculating a person\'s exact age or measuring the time left until a special event, having a precise tool is essential for efficient time management.',
95
+ },
96
+ { type: 'title', level: 3, text: 'What is the date difference calculator used for?' },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'The usefulness of this tool extends to multiple fields. In the workplace, project managers use it to define delivery deadlines and track milestone progress. In legal and administrative contexts, it is essential for calculating limitation periods or contract durations.',
100
+ },
101
+ {
102
+ type: 'list',
103
+ items: [
104
+ '<strong>Event planning:</strong> Know how many weeks and days remain until a wedding, conference or trip.',
105
+ '<strong>Project management:</strong> Calculate the time elapsed from the start of a phase to its completion.',
106
+ '<strong>Finance:</strong> Determine the number of days for interest calculations or invoice due dates.',
107
+ '<strong>Human Resources:</strong> Measure employee tenure or accumulated vacation days.',
108
+ '<strong>Health:</strong> Track the progress of a treatment or recovery time after a procedure.',
109
+ ],
110
+ },
111
+ { type: 'title', level: 3, text: 'Time perception and digital precision' },
112
+ {
113
+ type: 'paragraph',
114
+ html: 'We often tend to round time. We say "about a month" when it is actually 27 days and 14 hours away. By using a digital calculator, we eliminate subjectivity and obtain clean data for informed decision-making.',
115
+ },
116
+ { type: 'title', level: 3, text: 'Natural days versus working days' },
117
+ {
118
+ type: 'paragraph',
119
+ html: 'This tool calculates <strong>calendar days</strong>, including weekends and public holidays. For astronomical and general civil calculation, time is measured continuously. If you need to estimate project time, remember that the days shown represent the full real calendar.',
120
+ },
121
+ { type: 'title', level: 3, text: 'The impact of time on productivity' },
122
+ {
123
+ type: 'paragraph',
124
+ html: 'Parkinson\'s Law states that work expands to fill the time available for its completion. By visualizing exactly how many hours and minutes remain until a deadline, teams tend to optimize their efforts and stay focused.',
125
+ },
126
+ {
127
+ type: 'tip',
128
+ title: 'Future and past dates',
129
+ html: 'You can use the calculator for both future and past dates. If the end date is earlier than the start date, the system automatically detects it is time elapsed in the past, maintaining precision in the absolute difference values.',
130
+ },
131
+ ],
132
+ };
@@ -0,0 +1,132 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
3
+ import type { DateDiffCalculatorUI } from '../ui';
4
+
5
+ const faqData = [
6
+ {
7
+ question: '¿Es gratuita esta calculadora de diferencia de fechas?',
8
+ answer: 'Sí, es una herramienta 100% gratuita y accesible desde cualquier navegador sin necesidad de registro ni descargas.',
9
+ },
10
+ {
11
+ question: '¿Cómo se calculan los años bisiestos en el tiempo total?',
12
+ answer: 'La herramienta utiliza la cronología estándar de JavaScript (UTC), que maneja automáticamente los años bisiestos y la duración variable de cada mes para dar un resultado de días exacto.',
13
+ },
14
+ {
15
+ question: '¿Puedo calcular la diferencia entre horas y minutos también?',
16
+ answer: 'Sí. Los campos de entrada permiten seleccionar la hora exacta. El resultado te devuelve el desglose en días, horas, minutos y segundos, además de los totales acumulados.',
17
+ },
18
+ {
19
+ question: '¿Mis datos de fechas se envían a algún servidor?',
20
+ answer: 'No. Todo el procesamiento se realiza localmente en tu navegador. No almacenamos ni recibimos información sobre las fechas que calculas.',
21
+ },
22
+ ];
23
+
24
+ const howToData = [
25
+ { name: 'Seleccionar la fecha de inicio', text: "Introduce la fecha y hora de partida o usa el botón 'Hoy' para fijarla al instante." },
26
+ { name: 'Seleccionar la fecha de fin', text: "Define el momento de destino. Puedes usar 'Ahora' para medir el tiempo hasta este preciso instante." },
27
+ { name: 'Leer los resultados', text: 'Consulta el desglose en días, horas, minutos y segundos, y los totales acumulados de semanas y horas.' },
28
+ ];
29
+
30
+ const faqSchema: WithContext<FAQPage> = {
31
+ '@context': 'https://schema.org',
32
+ '@type': 'FAQPage',
33
+ mainEntity: faqData.map((item) => ({
34
+ '@type': 'Question',
35
+ name: item.question,
36
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
37
+ })),
38
+ };
39
+
40
+ const howToSchema: WithContext<HowTo> = {
41
+ '@context': 'https://schema.org',
42
+ '@type': 'HowTo',
43
+ name: 'Cómo calcular la diferencia entre dos fechas',
44
+ step: howToData.map((s) => ({ '@type': 'HowToStep', name: s.name, text: s.text })),
45
+ };
46
+
47
+ const appSchema: WithContext<SoftwareApplication> = {
48
+ '@context': 'https://schema.org',
49
+ '@type': 'SoftwareApplication',
50
+ name: 'Calculadora de Diferencia entre Fechas',
51
+ applicationCategory: 'UtilitiesApplication',
52
+ operatingSystem: 'Web',
53
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
54
+ description: 'Calcula exactamente cuánto tiempo ha pasado entre dos fechas o cuánto falta para un evento. Resultados en días, horas y minutos.',
55
+ };
56
+
57
+ const ui: DateDiffCalculatorUI = {
58
+ startLabel: 'Fecha de Inicio',
59
+ endLabel: 'Fecha de Fin',
60
+ nowBtn: 'Ahora',
61
+ todayBtn: 'Hoy',
62
+ tomorrowBtn: 'Mañana',
63
+ daysLabel: 'Días',
64
+ hoursLabel: 'Horas',
65
+ minsLabel: 'Min',
66
+ secsLabel: 'Seg',
67
+ weeksLabel: 'Semanas Totales',
68
+ totalHoursLabel: 'Horas Totales',
69
+ totalMinsLabel: 'Minutos Totales',
70
+ elapsed: 'Tiempo Transcurrido',
71
+ past: 'Tiempo en el Pasado',
72
+ invalidDates: 'Fechas no válidas',
73
+ };
74
+
75
+ export const content: ToolLocaleContent<DateDiffCalculatorUI> = {
76
+ slug: 'calculadora-diferencia-fechas',
77
+ title: 'Calculadora de Diferencia entre Fechas',
78
+ description: 'Calcula exactamente cuánto tiempo ha pasado entre dos fechas o cuánto falta para un evento. Resultados en días, horas y minutos de forma gratuita y segura.',
79
+ ui,
80
+ faqTitle: 'Preguntas Frecuentes',
81
+ faq: faqData,
82
+ howTo: howToData,
83
+ bibliographyTitle: 'Referencias',
84
+ bibliography: [
85
+ { name: 'Time and Date: Reloj Mundial y Conversor de Husos Horarios', url: 'https://www.timeanddate.com/worldclock/' },
86
+ { name: 'Wikipedia: Historia del Calendario Gregoriano', url: 'https://es.wikipedia.org/wiki/Calendario_gregoriano' },
87
+ { name: 'Wikipedia: Matriz de Eisenhower y Gestión del Tiempo', url: 'https://es.wikipedia.org/wiki/Matriz_de_Eisenhower' },
88
+ ],
89
+ schemas: [faqSchema, howToSchema, appSchema],
90
+ seo: [
91
+ { type: 'title', level: 2, text: 'Calculadora de diferencia entre fechas con días, horas y minutos' },
92
+ {
93
+ type: 'paragraph',
94
+ html: 'Calcular la <strong>diferencia entre dos fechas</strong> es una de las tareas más comunes y subestimadas tanto en la vida cotidiana como en entornos profesionales. Ya sea para planificar el lanzamiento de un producto, calcular la edad exacta de una persona o medir el tiempo que falta para un evento, contar con una herramienta precisa es fundamental para una gestión del tiempo eficiente.',
95
+ },
96
+ { type: 'title', level: 3, text: '¿Para qué sirve calcular la diferencia de fechas?' },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'La utilidad de esta herramienta se extiende a múltiples campos. En el sector laboral, los gestores de proyectos la utilizan para definir plazos de entrega y controlar el progreso de los hitos. En el ámbito legal, es esencial para calcular plazos de prescripción o la duración de contratos.',
100
+ },
101
+ {
102
+ type: 'list',
103
+ items: [
104
+ '<strong>Planificación de eventos:</strong> Saber cuántas semanas y días faltan para una boda, conferencia o viaje.',
105
+ '<strong>Gestión de proyectos:</strong> Calcular el tiempo transcurrido desde el inicio de una fase hasta su finalización.',
106
+ '<strong>Finanzas:</strong> Determinar el número de días para el cálculo de intereses o vencimientos de facturas.',
107
+ '<strong>Recursos Humanos:</strong> Medir la antigüedad de un empleado o los días de vacaciones acumulados.',
108
+ '<strong>Salud:</strong> Seguir el progreso de un tratamiento o el tiempo de recuperación.',
109
+ ],
110
+ },
111
+ { type: 'title', level: 3, text: 'La percepción del tiempo y la precisión digital' },
112
+ {
113
+ type: 'paragraph',
114
+ html: 'A menudo tendemos a redondear el tiempo. Decimos "falta un mes" cuando en realidad faltan 27 días y 14 horas. Al utilizar una calculadora digital, eliminamos la subjetividad y obtenemos datos puros que permiten una toma de decisiones informada.',
115
+ },
116
+ { type: 'title', level: 3, text: 'Diferencia entre días naturales y días hábiles' },
117
+ {
118
+ type: 'paragraph',
119
+ html: 'Es importante distinguir que esta herramienta calcula <strong>días naturales</strong>, incluyendo fines de semana y festivos. Para el cálculo astronómico y civil general, el tiempo se mide de forma continua. Si necesitas calcular el tiempo total de un proyecto, recuerda que los días obtenidos representan el calendario real completo.',
120
+ },
121
+ { type: 'title', level: 3, text: 'El impacto del tiempo en la productividad' },
122
+ {
123
+ type: 'paragraph',
124
+ html: 'La Ley de Parkinson afirma que el trabajo se expande hasta llenar el tiempo disponible para su realización. Al visualizar exactamente cuántas horas y minutos quedan para una entrega, los equipos tienden a optimizar sus esfuerzos.',
125
+ },
126
+ {
127
+ type: 'tip',
128
+ title: 'Fechas futuras y pasadas',
129
+ html: 'Puedes usar la calculadora tanto para fechas futuras como pasadas. Si la fecha de fin es anterior a la de inicio, el sistema detecta automáticamente que se trata de tiempo transcurrido en el pasado, manteniendo la precisión en los valores absolutos.',
130
+ },
131
+ ],
132
+ };