@jjlmoya/utils-babies 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 (82) hide show
  1. package/package.json +69 -0
  2. package/src/category/i18n/en.ts +48 -0
  3. package/src/category/i18n/es.ts +48 -0
  4. package/src/category/i18n/fr.ts +48 -0
  5. package/src/category/index.ts +24 -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 +30 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +19 -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/seo_length.test.ts +23 -0
  21. package/src/tests/tool_validation.test.ts +17 -0
  22. package/src/tool/baby-feeding-calculator/bibliography.astro +7 -0
  23. package/src/tool/baby-feeding-calculator/component.astro +210 -0
  24. package/src/tool/baby-feeding-calculator/i18n/en.ts +162 -0
  25. package/src/tool/baby-feeding-calculator/i18n/es.ts +162 -0
  26. package/src/tool/baby-feeding-calculator/i18n/fr.ts +162 -0
  27. package/src/tool/baby-feeding-calculator/index.ts +47 -0
  28. package/src/tool/baby-feeding-calculator/logic.ts +85 -0
  29. package/src/tool/baby-feeding-calculator/seo.astro +58 -0
  30. package/src/tool/baby-feeding-calculator/style.css +329 -0
  31. package/src/tool/baby-percentile-calculator/bibliography.astro +7 -0
  32. package/src/tool/baby-percentile-calculator/component.astro +388 -0
  33. package/src/tool/baby-percentile-calculator/i18n/en.ts +244 -0
  34. package/src/tool/baby-percentile-calculator/i18n/es.ts +244 -0
  35. package/src/tool/baby-percentile-calculator/i18n/fr.ts +244 -0
  36. package/src/tool/baby-percentile-calculator/index.ts +54 -0
  37. package/src/tool/baby-percentile-calculator/lmsData.ts +80 -0
  38. package/src/tool/baby-percentile-calculator/logic.ts +85 -0
  39. package/src/tool/baby-percentile-calculator/seo.astro +36 -0
  40. package/src/tool/baby-percentile-calculator/style.css +393 -0
  41. package/src/tool/baby-size-converter/bibliography.astro +7 -0
  42. package/src/tool/baby-size-converter/component.astro +289 -0
  43. package/src/tool/baby-size-converter/data.json +11 -0
  44. package/src/tool/baby-size-converter/i18n/en.ts +203 -0
  45. package/src/tool/baby-size-converter/i18n/es.ts +203 -0
  46. package/src/tool/baby-size-converter/i18n/fr.ts +203 -0
  47. package/src/tool/baby-size-converter/index.ts +53 -0
  48. package/src/tool/baby-size-converter/logic.ts +44 -0
  49. package/src/tool/baby-size-converter/seo.astro +36 -0
  50. package/src/tool/baby-size-converter/style.css +394 -0
  51. package/src/tool/fertile-days-estimator/bibliography.astro +7 -0
  52. package/src/tool/fertile-days-estimator/component.astro +265 -0
  53. package/src/tool/fertile-days-estimator/i18n/en.ts +258 -0
  54. package/src/tool/fertile-days-estimator/i18n/es.ts +262 -0
  55. package/src/tool/fertile-days-estimator/i18n/fr.ts +258 -0
  56. package/src/tool/fertile-days-estimator/index.ts +47 -0
  57. package/src/tool/fertile-days-estimator/logic.ts +58 -0
  58. package/src/tool/fertile-days-estimator/seo.astro +36 -0
  59. package/src/tool/fertile-days-estimator/style.css +419 -0
  60. package/src/tool/pregnancy-calculator/bibliography.astro +7 -0
  61. package/src/tool/pregnancy-calculator/calculator.ts +41 -0
  62. package/src/tool/pregnancy-calculator/component.astro +432 -0
  63. package/src/tool/pregnancy-calculator/i18n/en.ts +315 -0
  64. package/src/tool/pregnancy-calculator/i18n/es.ts +319 -0
  65. package/src/tool/pregnancy-calculator/i18n/fr.ts +315 -0
  66. package/src/tool/pregnancy-calculator/index.ts +55 -0
  67. package/src/tool/pregnancy-calculator/milestones.ts +153 -0
  68. package/src/tool/pregnancy-calculator/seo.astro +36 -0
  69. package/src/tool/pregnancy-calculator/store.ts +60 -0
  70. package/src/tool/pregnancy-calculator/style.css +807 -0
  71. package/src/tool/vaccination-calendar/bibliography.astro +7 -0
  72. package/src/tool/vaccination-calendar/component.astro +286 -0
  73. package/src/tool/vaccination-calendar/i18n/en.ts +170 -0
  74. package/src/tool/vaccination-calendar/i18n/es.ts +174 -0
  75. package/src/tool/vaccination-calendar/i18n/fr.ts +170 -0
  76. package/src/tool/vaccination-calendar/index.ts +47 -0
  77. package/src/tool/vaccination-calendar/logic.ts +59 -0
  78. package/src/tool/vaccination-calendar/seo.astro +36 -0
  79. package/src/tool/vaccination-calendar/style.css +316 -0
  80. package/src/tool/vaccination-calendar/vaccinationData.ts +21 -0
  81. package/src/tools.ts +17 -0
  82. package/src/types.ts +72 -0
@@ -0,0 +1,419 @@
1
+ .fertile-days-estimator {
2
+ --fde-bg: #fff;
3
+ --fde-bg-step: #fff;
4
+ --fde-bg-sidebar: #fdf2f8;
5
+ --fde-bg-dark: #18181b;
6
+ --fde-text: #111827;
7
+ --fde-text-muted: #64748b;
8
+ --fde-text-pink: #9d174d;
9
+ --fde-border: #e5e7eb;
10
+ --fde-border-pink: #fbcfe8;
11
+ --fde-shadow: rgba(219, 39, 119, 0.08);
12
+ --fde-primary: #db2777;
13
+ --fde-primary-dark: #be123c;
14
+ --fde-primary-soft: #fdf2f8;
15
+ --fde-primary-on: #fff;
16
+ --fde-period-bg: #ffe4e6;
17
+ --fde-period-text: #be123c;
18
+ --fde-fertile-bg: #fdf2f8;
19
+ --fde-fertile-text: #db2777;
20
+ --fde-calendar-day: #374151;
21
+ --fde-calendar-day-bg: #fff;
22
+ --fde-legend-bg: #f9fafb;
23
+ --fde-legend-text: #4b5563;
24
+ --fde-range-accent: #db2777;
25
+
26
+ width: 100%;
27
+ color: var(--fde-text);
28
+ }
29
+
30
+ .theme-dark .fertile-days-estimator {
31
+ --fde-bg: #18181b;
32
+ --fde-bg-step: #18181b;
33
+ --fde-bg-sidebar: #111113;
34
+ --fde-bg-dark: #18181b;
35
+ --fde-text: #fff;
36
+ --fde-text-muted: #9ca3af;
37
+ --fde-text-pink: #f472b6;
38
+ --fde-border: #27272a;
39
+ --fde-border-pink: #27272a;
40
+ --fde-shadow: rgba(0, 0, 0, 0.5);
41
+ --fde-primary: #f472b6;
42
+ --fde-primary-dark: #ec4899;
43
+ --fde-primary-soft: #18181b;
44
+ --fde-primary-on: #fff;
45
+ --fde-period-bg: #ffe4e6;
46
+ --fde-period-text: #be123c;
47
+ --fde-fertile-bg: #27272a;
48
+ --fde-fertile-text: #f472b6;
49
+ --fde-calendar-day: #e5e7eb;
50
+ --fde-calendar-day-bg: #1e1e21;
51
+ --fde-legend-bg: #111113;
52
+ --fde-legend-text: #9ca3af;
53
+ --fde-range-accent: #f472b6;
54
+ }
55
+
56
+ .fertile-days-estimator-step-indicator {
57
+ display: flex;
58
+ gap: 1.5rem;
59
+ margin-bottom: 1.5rem;
60
+ }
61
+
62
+ .fertile-days-estimator-step-item {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 0.5rem;
66
+ font-size: 0.875rem;
67
+ font-weight: 500;
68
+ color: var(--fde-text-muted);
69
+ opacity: 0.5;
70
+ transition: opacity 0.2s;
71
+ }
72
+
73
+ .fertile-days-estimator-step-item.active {
74
+ color: var(--fde-primary);
75
+ opacity: 1;
76
+ }
77
+
78
+ .fertile-days-estimator-step-number {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ width: 1.75rem;
83
+ height: 1.75rem;
84
+ border-radius: 50%;
85
+ background: var(--fde-primary-soft);
86
+ color: var(--fde-primary);
87
+ font-size: 0.8125rem;
88
+ font-weight: 700;
89
+ border: 2px solid var(--fde-border-pink);
90
+ }
91
+
92
+ .fertile-days-estimator-step-item.active .fertile-days-estimator-step-number {
93
+ background: var(--fde-primary);
94
+ color: var(--fde-primary-on);
95
+ border-color: var(--fde-primary);
96
+ }
97
+
98
+ .fertile-days-estimator-step-first {
99
+ background: var(--fde-bg-step);
100
+ border: 1px solid var(--fde-border);
101
+ border-radius: 1rem;
102
+ padding: 1.5rem;
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 1rem;
106
+ }
107
+
108
+ .fertile-days-estimator-step-first.hidden {
109
+ display: none;
110
+ }
111
+
112
+ .fertile-days-estimator-step-title {
113
+ font-size: 1.25rem;
114
+ font-weight: 700;
115
+ color: var(--fde-text);
116
+ margin: 0;
117
+ }
118
+
119
+ .fertile-days-estimator-step-subtitle {
120
+ font-size: 0.9375rem;
121
+ color: var(--fde-text-muted);
122
+ margin: 0;
123
+ }
124
+
125
+ .fertile-days-estimator-pulse-hint {
126
+ font-size: 0.8125rem;
127
+ color: var(--fde-primary);
128
+ margin: 0;
129
+ font-style: italic;
130
+ }
131
+
132
+ .fertile-days-estimator-layout {
133
+ display: none;
134
+ grid-template-columns: 18rem 1fr;
135
+ gap: 1.5rem;
136
+ margin-top: 1.5rem;
137
+ }
138
+
139
+ .fertile-days-estimator-layout.active {
140
+ display: grid;
141
+ }
142
+
143
+ @media (max-width: 720px) {
144
+ .fertile-days-estimator-layout.active {
145
+ grid-template-columns: 1fr;
146
+ }
147
+ }
148
+
149
+ .fertile-days-estimator-sidebar {
150
+ background: var(--fde-bg-sidebar);
151
+ border: 1px solid var(--fde-border-pink);
152
+ border-radius: 1rem;
153
+ padding: 1.25rem;
154
+ display: flex;
155
+ flex-direction: column;
156
+ gap: 1.25rem;
157
+ }
158
+
159
+ .fertile-days-estimator-sidebar-header strong {
160
+ display: block;
161
+ font-size: 1rem;
162
+ font-weight: 700;
163
+ color: var(--fde-text-pink);
164
+ margin-bottom: 0.25rem;
165
+ }
166
+
167
+ .fertile-days-estimator-sidebar-header p {
168
+ font-size: 0.8125rem;
169
+ color: var(--fde-text-muted);
170
+ margin: 0;
171
+ }
172
+
173
+ .fertile-days-estimator-input-card {
174
+ background: var(--fde-bg);
175
+ border: 1px solid var(--fde-border);
176
+ border-radius: 0.75rem;
177
+ padding: 1rem;
178
+ display: flex;
179
+ flex-direction: column;
180
+ gap: 0.75rem;
181
+ }
182
+
183
+ .fertile-days-estimator-range-label {
184
+ font-size: 0.8125rem;
185
+ font-weight: 600;
186
+ color: var(--fde-text-muted);
187
+ }
188
+
189
+ .fertile-days-estimator-range-control {
190
+ display: flex;
191
+ align-items: center;
192
+ gap: 0.75rem;
193
+ }
194
+
195
+ .fertile-days-estimator-range-input {
196
+ flex: 1;
197
+ accent-color: var(--fde-range-accent);
198
+ cursor: pointer;
199
+ }
200
+
201
+ .fertile-days-estimator-range-value {
202
+ font-size: 0.875rem;
203
+ font-weight: 700;
204
+ color: var(--fde-primary);
205
+ white-space: nowrap;
206
+ }
207
+
208
+ .fertile-days-estimator-results {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 0.875rem;
212
+ }
213
+
214
+ .fertile-days-estimator-stat {
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 0.75rem;
218
+ background: var(--fde-bg);
219
+ border: 1px solid var(--fde-border);
220
+ border-radius: 0.625rem;
221
+ padding: 0.75rem;
222
+ }
223
+
224
+ .fertile-days-estimator-stat-dot {
225
+ width: 0.875rem;
226
+ height: 0.875rem;
227
+ border-radius: 50%;
228
+ flex-shrink: 0;
229
+ }
230
+
231
+ .fertile-days-estimator-stat-dot-ovulation {
232
+ background: var(--fde-primary);
233
+ }
234
+
235
+ .fertile-days-estimator-stat-dot-fertile {
236
+ background: var(--fde-fertile-text);
237
+ opacity: 0.6;
238
+ }
239
+
240
+ .fertile-days-estimator-stat-dot-period {
241
+ background: var(--fde-period-text);
242
+ }
243
+
244
+ .fertile-days-estimator-stat-info {
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 0.125rem;
248
+ }
249
+
250
+ .fertile-days-estimator-stat-label {
251
+ font-size: 0.75rem;
252
+ color: var(--fde-text-muted);
253
+ font-weight: 500;
254
+ }
255
+
256
+ .fertile-days-estimator-stat-value {
257
+ font-size: 0.875rem;
258
+ font-weight: 700;
259
+ color: var(--fde-text);
260
+ }
261
+
262
+ .fertile-days-estimator-content {
263
+ display: flex;
264
+ flex-direction: column;
265
+ gap: 1rem;
266
+ }
267
+
268
+ .fertile-days-estimator-calendar {
269
+ background: var(--fde-bg);
270
+ border: 1px solid var(--fde-border);
271
+ border-radius: 1rem;
272
+ padding: 1.25rem;
273
+ display: flex;
274
+ flex-direction: column;
275
+ gap: 1rem;
276
+ }
277
+
278
+ .fertile-days-estimator-calendar-nav {
279
+ display: flex;
280
+ align-items: center;
281
+ justify-content: space-between;
282
+ }
283
+
284
+ .fertile-days-estimator-month-label {
285
+ font-size: 0.9375rem;
286
+ font-weight: 700;
287
+ color: var(--fde-text);
288
+ text-transform: capitalize;
289
+ }
290
+
291
+ .fertile-days-estimator-nav-buttons {
292
+ display: flex;
293
+ gap: 0.375rem;
294
+ }
295
+
296
+ .fertile-days-estimator-nav-btn {
297
+ display: inline-flex;
298
+ align-items: center;
299
+ justify-content: center;
300
+ width: 2rem;
301
+ height: 2rem;
302
+ border-radius: 50%;
303
+ background: var(--fde-primary-soft);
304
+ color: var(--fde-primary);
305
+ border: none;
306
+ cursor: pointer;
307
+ transition: background 0.15s;
308
+ }
309
+
310
+ .fertile-days-estimator-nav-btn:hover {
311
+ background: var(--fde-border-pink);
312
+ }
313
+
314
+ .fertile-days-estimator-calendar-grid {
315
+ display: grid;
316
+ grid-template-columns: repeat(7, 1fr);
317
+ gap: 0.25rem;
318
+ }
319
+
320
+ .fertile-days-estimator-day-header {
321
+ text-align: center;
322
+ font-size: 0.75rem;
323
+ font-weight: 700;
324
+ color: var(--fde-text-muted);
325
+ padding: 0.25rem 0;
326
+ }
327
+
328
+ .fertile-days-estimator-day {
329
+ display: flex;
330
+ align-items: center;
331
+ justify-content: center;
332
+ aspect-ratio: 1;
333
+ border-radius: 50%;
334
+ font-size: 0.8125rem;
335
+ font-weight: 500;
336
+ color: var(--fde-calendar-day);
337
+ background: transparent;
338
+ border: none;
339
+ cursor: pointer;
340
+ transition: background 0.1s, color 0.1s;
341
+ }
342
+
343
+ .fertile-days-estimator-day:hover {
344
+ background: var(--fde-primary-soft);
345
+ color: var(--fde-primary);
346
+ }
347
+
348
+ .fertile-days-estimator-day-empty {
349
+ pointer-events: none;
350
+ }
351
+
352
+ .fertile-days-estimator-day-today {
353
+ border: 2px solid var(--fde-primary);
354
+ color: var(--fde-primary);
355
+ }
356
+
357
+ .fertile-days-estimator-day-selected {
358
+ background: var(--fde-period-bg);
359
+ color: var(--fde-period-text);
360
+ font-weight: 700;
361
+ }
362
+
363
+ .fertile-days-estimator-day-fertile {
364
+ background: var(--fde-fertile-bg);
365
+ color: var(--fde-fertile-text);
366
+ }
367
+
368
+ .fertile-days-estimator-day-ovulation {
369
+ background: var(--fde-primary);
370
+ color: var(--fde-primary-on);
371
+ font-weight: 700;
372
+ }
373
+
374
+ .fertile-days-estimator-day-period {
375
+ background: var(--fde-period-bg);
376
+ color: var(--fde-period-text);
377
+ }
378
+
379
+ .fertile-days-estimator-legend {
380
+ display: flex;
381
+ flex-wrap: wrap;
382
+ gap: 0.75rem;
383
+ background: var(--fde-legend-bg);
384
+ border-radius: 0.75rem;
385
+ padding: 0.875rem 1rem;
386
+ }
387
+
388
+ .fertile-days-estimator-legend-item {
389
+ display: flex;
390
+ align-items: center;
391
+ gap: 0.375rem;
392
+ font-size: 0.75rem;
393
+ color: var(--fde-legend-text);
394
+ }
395
+
396
+ .fertile-days-estimator-legend-dot {
397
+ width: 0.75rem;
398
+ height: 0.75rem;
399
+ border-radius: 50%;
400
+ flex-shrink: 0;
401
+ }
402
+
403
+ .fertile-days-estimator-legend-dot-selected {
404
+ background: var(--fde-period-bg);
405
+ border: 2px solid var(--fde-period-text);
406
+ }
407
+
408
+ .fertile-days-estimator-legend-dot-period {
409
+ background: var(--fde-period-bg);
410
+ }
411
+
412
+ .fertile-days-estimator-legend-dot-fertile {
413
+ background: var(--fde-fertile-bg);
414
+ border: 2px solid var(--fde-fertile-text);
415
+ }
416
+
417
+ .fertile-days-estimator-legend-dot-ovulation {
418
+ background: var(--fde-primary);
419
+ }
@@ -0,0 +1,7 @@
1
+ ---
2
+ import { Bibliography as BibliographyUI } from '@jjlmoya/utils-shared';
3
+ import type { BibliographyEntry } from '../../types';
4
+ interface Props { links?: BibliographyEntry[]; title: string; }
5
+ const { links = [], title } = Astro.props;
6
+ ---
7
+ <BibliographyUI links={links} title={title} />
@@ -0,0 +1,41 @@
1
+ export type Method = 'fur' | 'conception';
2
+
3
+ export interface CalcInput {
4
+ method: Method;
5
+ date: string;
6
+ cycle: number;
7
+ }
8
+
9
+ export interface CalcResult {
10
+ weeks: number;
11
+ days: number;
12
+ trimester: 1 | 2 | 3;
13
+ edd: Date;
14
+ valid: boolean;
15
+ outOfRange?: 'future' | 'too-old';
16
+ }
17
+
18
+ export function calculate(input: CalcInput): CalcResult | null {
19
+ if (!input.date) return null;
20
+ const inputDate = new Date(input.date);
21
+ if (isNaN(inputDate.getTime())) return null;
22
+ const now = new Date();
23
+ now.setHours(0, 0, 0, 0);
24
+ const gestStart = new Date(inputDate);
25
+ const edd = new Date(inputDate);
26
+ if (input.method === 'fur') {
27
+ edd.setDate(edd.getDate() + 280 + (input.cycle - 28));
28
+ } else {
29
+ gestStart.setDate(gestStart.getDate() - 14);
30
+ edd.setDate(edd.getDate() + 266);
31
+ }
32
+ const totalDays = Math.floor((now.getTime() - gestStart.getTime()) / 86400000);
33
+ if (totalDays < 0) return { weeks: 0, days: 0, trimester: 1, edd, valid: false, outOfRange: 'future' };
34
+ if (totalDays > 300) return { weeks: 0, days: 0, trimester: 1, edd, valid: false, outOfRange: 'too-old' };
35
+ const weeks = Math.floor(totalDays / 7);
36
+ const days = totalDays % 7;
37
+ let trimester: 1 | 2 | 3 = 3;
38
+ if (weeks < 13) trimester = 1;
39
+ else if (weeks < 27) trimester = 2;
40
+ return { weeks, days, trimester, edd, valid: true };
41
+ }