@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.
- package/package.json +69 -0
- package/src/category/i18n/en.ts +48 -0
- package/src/category/i18n/es.ts +48 -0
- package/src/category/i18n/fr.ts +48 -0
- package/src/category/index.ts +24 -0
- package/src/category/seo.astro +15 -0
- package/src/components/PreviewNavSidebar.astro +116 -0
- package/src/components/PreviewToolbar.astro +143 -0
- package/src/data.ts +30 -0
- package/src/env.d.ts +5 -0
- package/src/index.ts +19 -0
- package/src/layouts/PreviewLayout.astro +117 -0
- package/src/pages/[locale]/[slug].astro +146 -0
- package/src/pages/[locale].astro +251 -0
- package/src/pages/index.astro +4 -0
- package/src/tests/faq_count.test.ts +19 -0
- package/src/tests/locale_completeness.test.ts +42 -0
- package/src/tests/mocks/astro_mock.js +2 -0
- package/src/tests/no_h1_in_components.test.ts +48 -0
- package/src/tests/seo_length.test.ts +23 -0
- package/src/tests/tool_validation.test.ts +17 -0
- package/src/tool/baby-feeding-calculator/bibliography.astro +7 -0
- package/src/tool/baby-feeding-calculator/component.astro +210 -0
- package/src/tool/baby-feeding-calculator/i18n/en.ts +162 -0
- package/src/tool/baby-feeding-calculator/i18n/es.ts +162 -0
- package/src/tool/baby-feeding-calculator/i18n/fr.ts +162 -0
- package/src/tool/baby-feeding-calculator/index.ts +47 -0
- package/src/tool/baby-feeding-calculator/logic.ts +85 -0
- package/src/tool/baby-feeding-calculator/seo.astro +58 -0
- package/src/tool/baby-feeding-calculator/style.css +329 -0
- package/src/tool/baby-percentile-calculator/bibliography.astro +7 -0
- package/src/tool/baby-percentile-calculator/component.astro +388 -0
- package/src/tool/baby-percentile-calculator/i18n/en.ts +244 -0
- package/src/tool/baby-percentile-calculator/i18n/es.ts +244 -0
- package/src/tool/baby-percentile-calculator/i18n/fr.ts +244 -0
- package/src/tool/baby-percentile-calculator/index.ts +54 -0
- package/src/tool/baby-percentile-calculator/lmsData.ts +80 -0
- package/src/tool/baby-percentile-calculator/logic.ts +85 -0
- package/src/tool/baby-percentile-calculator/seo.astro +36 -0
- package/src/tool/baby-percentile-calculator/style.css +393 -0
- package/src/tool/baby-size-converter/bibliography.astro +7 -0
- package/src/tool/baby-size-converter/component.astro +289 -0
- package/src/tool/baby-size-converter/data.json +11 -0
- package/src/tool/baby-size-converter/i18n/en.ts +203 -0
- package/src/tool/baby-size-converter/i18n/es.ts +203 -0
- package/src/tool/baby-size-converter/i18n/fr.ts +203 -0
- package/src/tool/baby-size-converter/index.ts +53 -0
- package/src/tool/baby-size-converter/logic.ts +44 -0
- package/src/tool/baby-size-converter/seo.astro +36 -0
- package/src/tool/baby-size-converter/style.css +394 -0
- package/src/tool/fertile-days-estimator/bibliography.astro +7 -0
- package/src/tool/fertile-days-estimator/component.astro +265 -0
- package/src/tool/fertile-days-estimator/i18n/en.ts +258 -0
- package/src/tool/fertile-days-estimator/i18n/es.ts +262 -0
- package/src/tool/fertile-days-estimator/i18n/fr.ts +258 -0
- package/src/tool/fertile-days-estimator/index.ts +47 -0
- package/src/tool/fertile-days-estimator/logic.ts +58 -0
- package/src/tool/fertile-days-estimator/seo.astro +36 -0
- package/src/tool/fertile-days-estimator/style.css +419 -0
- package/src/tool/pregnancy-calculator/bibliography.astro +7 -0
- package/src/tool/pregnancy-calculator/calculator.ts +41 -0
- package/src/tool/pregnancy-calculator/component.astro +432 -0
- package/src/tool/pregnancy-calculator/i18n/en.ts +315 -0
- package/src/tool/pregnancy-calculator/i18n/es.ts +319 -0
- package/src/tool/pregnancy-calculator/i18n/fr.ts +315 -0
- package/src/tool/pregnancy-calculator/index.ts +55 -0
- package/src/tool/pregnancy-calculator/milestones.ts +153 -0
- package/src/tool/pregnancy-calculator/seo.astro +36 -0
- package/src/tool/pregnancy-calculator/store.ts +60 -0
- package/src/tool/pregnancy-calculator/style.css +807 -0
- package/src/tool/vaccination-calendar/bibliography.astro +7 -0
- package/src/tool/vaccination-calendar/component.astro +286 -0
- package/src/tool/vaccination-calendar/i18n/en.ts +170 -0
- package/src/tool/vaccination-calendar/i18n/es.ts +174 -0
- package/src/tool/vaccination-calendar/i18n/fr.ts +170 -0
- package/src/tool/vaccination-calendar/index.ts +47 -0
- package/src/tool/vaccination-calendar/logic.ts +59 -0
- package/src/tool/vaccination-calendar/seo.astro +36 -0
- package/src/tool/vaccination-calendar/style.css +316 -0
- package/src/tool/vaccination-calendar/vaccinationData.ts +21 -0
- package/src/tools.ts +17 -0
- package/src/types.ts +72 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import type { FertileDaysEstimatorLocaleContent } from '../index';
|
|
2
|
+
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
3
|
+
|
|
4
|
+
const slug = 'calculatrice-jours-fertiles';
|
|
5
|
+
const title = 'Calculatrice de Jours Fertiles';
|
|
6
|
+
const description = "Calculez votre fenêtre fertile et la date d'ovulation en fonction de votre cycle menstruel.";
|
|
7
|
+
const faq = [
|
|
8
|
+
{
|
|
9
|
+
question: "Comment la fenêtre fertile est-elle calculée ?",
|
|
10
|
+
answer: "La fenêtre fertile est calculée à partir du premier jour de vos dernières règles. L'ovulation survient environ 14 jours avant le début du cycle suivant. Les jours fertiles incluent les 5 jours précédant l'ovulation et le jour de l'ovulation lui-même.",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
question: "Quelle est la précision de cette calculatrice ?",
|
|
14
|
+
answer: "La calculatrice est une estimation basée sur le modèle standard de cycle de 28 jours (ou celui que vous indiquez). Elle est indicative et peut ne pas refléter les variations individuelles. Pour plus de précision, combinez-la avec le suivi de la température basale ou les tests d'ovulation.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
question: "Que faire si mon cycle est irrégulier ?",
|
|
18
|
+
answer: "Si vos cycles varient beaucoup d'un mois à l'autre, le calcul peut être moins précis. Dans ce cas, le suivi de la température basale ou les tests de LH sont des méthodes plus fiables pour identifier l'ovulation.",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
question: "Combien de temps l'ovule survit-il après l'ovulation ?",
|
|
22
|
+
answer: "L'ovule a une durée de vie de 12 à 24 heures. Cependant, les spermatozoïdes peuvent survivre jusqu'à 5 jours dans le tractus reproducteur féminin, ce qui explique que la fenêtre fertile réelle s'étend sur plusieurs jours avant l'ovulation.",
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
const howTo = [
|
|
26
|
+
{
|
|
27
|
+
name: "Sélectionnez le premier jour de vos dernières règles",
|
|
28
|
+
text: "Cliquez sur le jour du calendrier correspondant au début de votre dernière menstruation.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "Ajustez la durée de votre cycle",
|
|
32
|
+
text: "Déplacez le curseur pour indiquer combien de jours dure habituellement votre cycle menstruel.",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "Consultez les résultats",
|
|
36
|
+
text: "La calculatrice affiche automatiquement la date d'ovulation estimée, la fenêtre fertile et le début des prochaines règles.",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Naviguez dans le calendrier",
|
|
40
|
+
text: "Utilisez les flèches de navigation pour voir les jours marqués dans les mois précédents ou suivants.",
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
45
|
+
'@context': 'https://schema.org',
|
|
46
|
+
'@type': 'FAQPage',
|
|
47
|
+
mainEntity: faq.map((item) => ({
|
|
48
|
+
'@type': 'Question',
|
|
49
|
+
name: item.question,
|
|
50
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
51
|
+
})),
|
|
52
|
+
};
|
|
53
|
+
const howToSchema: WithContext<HowTo> = {
|
|
54
|
+
'@context': 'https://schema.org',
|
|
55
|
+
'@type': 'HowTo',
|
|
56
|
+
name: title,
|
|
57
|
+
description,
|
|
58
|
+
step: howTo.map((step) => ({
|
|
59
|
+
'@type': 'HowToStep',
|
|
60
|
+
name: step.name,
|
|
61
|
+
text: step.text,
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
65
|
+
'@context': 'https://schema.org',
|
|
66
|
+
'@type': 'SoftwareApplication',
|
|
67
|
+
name: title,
|
|
68
|
+
description,
|
|
69
|
+
applicationCategory: 'UtilitiesApplication',
|
|
70
|
+
operatingSystem: 'Web',
|
|
71
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
|
|
72
|
+
inLanguage: 'fr',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const content: FertileDaysEstimatorLocaleContent = {
|
|
76
|
+
slug,
|
|
77
|
+
title,
|
|
78
|
+
description,
|
|
79
|
+
ui: {
|
|
80
|
+
step1Title: "Quand a commencé vos dernières règles ?",
|
|
81
|
+
step1Desc: "Sélectionnez le premier jour de vos dernières règles sur le calendrier.",
|
|
82
|
+
pulseHint: "Cliquez sur un jour du calendrier pour continuer",
|
|
83
|
+
step1Indicator: "Date de début",
|
|
84
|
+
step2Indicator: "Votre Calendrier",
|
|
85
|
+
sidebarTitle: "Votre Cycle",
|
|
86
|
+
sidebarDesc: "Personnalisez les résultats en ajustant la durée de votre cycle.",
|
|
87
|
+
labelCycleLength: "Durée du cycle",
|
|
88
|
+
unitDays: "jours",
|
|
89
|
+
labelOvulation: "Prochaine ovulation",
|
|
90
|
+
labelFertileWindow: "Fenêtre fertile",
|
|
91
|
+
labelNextPeriod: "Prochaines règles",
|
|
92
|
+
legendSelection: "Votre sélection",
|
|
93
|
+
legendPeriod: "Règles",
|
|
94
|
+
legendFertile: "Fertile",
|
|
95
|
+
legendOvulation: "Ovulation",
|
|
96
|
+
faqTitle: "Questions fréquentes",
|
|
97
|
+
bibliographyTitle: "Références",
|
|
98
|
+
},
|
|
99
|
+
seo: [
|
|
100
|
+
{
|
|
101
|
+
type: 'title',
|
|
102
|
+
text: "Calculatrice de Jours Fertiles : Guide Complet sur le Cycle et l'Ovulation",
|
|
103
|
+
level: 2,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: 'summary',
|
|
107
|
+
title: "5 points clés sur la fenêtre fertile",
|
|
108
|
+
items: [
|
|
109
|
+
"L'ovulation survient environ 14 jours avant le début des prochaines règles.",
|
|
110
|
+
"La fenêtre fertile comprend les 5 jours précédant l'ovulation ainsi que le jour de l'ovulation.",
|
|
111
|
+
"Les spermatozoïdes peuvent survivre jusqu'à 5 jours dans le tractus reproducteur féminin.",
|
|
112
|
+
"Les cycles irréguliers réduisent la fiabilité du calcul basé sur le calendrier.",
|
|
113
|
+
"Combiner cet outil avec la température basale ou les tests de LH améliore la précision.",
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'title',
|
|
118
|
+
text: "Comment fonctionne le calcul de la fenêtre fertile",
|
|
119
|
+
level: 3,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
type: 'paragraph',
|
|
123
|
+
html: "La méthode repose sur la règle d'Ogino-Knaus et le modèle standard d'ovulation. Avec un cycle de 28 jours, l'ovulation survient généralement autour du 14e jour. La calculatrice identifie ce point et indique les jours de fertilité maximale autour de lui.",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'stats',
|
|
127
|
+
columns: 3,
|
|
128
|
+
items: [
|
|
129
|
+
{ value: "14 jours", label: "Avant les prochaines règles" },
|
|
130
|
+
{ value: "5 jours", label: "Durée de la fenêtre fertile" },
|
|
131
|
+
{ value: "12-24 h", label: "Durée de vie de l'ovule" },
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'title',
|
|
136
|
+
text: "Phases du cycle menstruel",
|
|
137
|
+
level: 3,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'comparative',
|
|
141
|
+
columns: 2,
|
|
142
|
+
items: [
|
|
143
|
+
{
|
|
144
|
+
title: "Phase folliculaire",
|
|
145
|
+
description: "Commence avec les règles et dure jusqu'à l'ovulation.",
|
|
146
|
+
points: [
|
|
147
|
+
"Les follicules ovariens mûrissent sous l'influence de la FSH.",
|
|
148
|
+
"Dure entre 10 et 14 jours dans les cycles réguliers.",
|
|
149
|
+
"Les taux d'oestrogènes augmentent progressivement.",
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
title: "Phase lutéale",
|
|
154
|
+
description: "Commence après l'ovulation et se termine avec les règles.",
|
|
155
|
+
points: [
|
|
156
|
+
"Le corps jaune produit de la progestérone pour préparer l'endomètre.",
|
|
157
|
+
"Dure environ 14 jours dans les cycles normaux.",
|
|
158
|
+
"En l'absence de fécondation, le corps jaune dégénère.",
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
type: 'tip',
|
|
165
|
+
html: "Bien que la calculatrice utilise un modèle standard, les cycles menstruels peuvent varier d'un mois à l'autre. Pour plus de précision, combinez cet outil avec le suivi de la température basale ou les tests d'ovulation.",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'title',
|
|
169
|
+
text: "Signes biologiques de l'ovulation",
|
|
170
|
+
level: 3,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
type: 'list',
|
|
174
|
+
items: [
|
|
175
|
+
"Modifications de la glaire cervicale : pendant les jours fertiles, elle devient transparente et élastique, semblable au blanc d'œuf cru.",
|
|
176
|
+
"Légère hausse de la température basale (0,2-0,4 °C) juste après l'ovulation.",
|
|
177
|
+
"Douleur ou gêne légère du côté de l'ovaire actif (Mittelschmerz) pendant l'ovulation.",
|
|
178
|
+
"Légère augmentation de la libido proche de l'ovulation, due aux changements hormonaux.",
|
|
179
|
+
"Ballonnements ou légère sensation de plénitude abdominale pendant les jours fertiles.",
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: 'title',
|
|
184
|
+
text: "Mode de vie et fertilité",
|
|
185
|
+
level: 3,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: 'list',
|
|
189
|
+
items: [
|
|
190
|
+
"Le stress chronique peut perturber l'ovulation et allonger ou raccourcir le cycle menstruel.",
|
|
191
|
+
"Le poids corporel a un impact direct : le sous-poids comme le surpoids peuvent affecter l'ovulation.",
|
|
192
|
+
"L'exercice modéré favorise la régularité du cycle ; l'exercice intense peut le supprimer.",
|
|
193
|
+
"Le tabac réduit la réserve ovarienne et avance la ménopause de plusieurs années.",
|
|
194
|
+
"Une alimentation riche en acide folique, en fer et en antioxydants soutient la santé reproductive.",
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'title',
|
|
199
|
+
text: "Méthodes de suivi du cycle",
|
|
200
|
+
level: 3,
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
type: 'table',
|
|
204
|
+
headers: ["Méthode", "Fiabilité", "Coût"],
|
|
205
|
+
rows: [
|
|
206
|
+
["Calculatrice de calendrier", "Moyenne", "Gratuit"],
|
|
207
|
+
["Température basale", "Élevée avec pratique", "Faible"],
|
|
208
|
+
["Test de LH urinaire", "Élevée", "Modéré"],
|
|
209
|
+
["Moniteur de fertilité numérique", "Très élevée", "Élevé"],
|
|
210
|
+
["Échographie folliculaire", "Maximale", "Clinique"],
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
type: 'glossary',
|
|
215
|
+
items: [
|
|
216
|
+
{
|
|
217
|
+
term: "Ovulation",
|
|
218
|
+
definition: "Libération de l'ovule mature depuis le follicule ovarien, déclenchée par un pic de LH. Elle survient une fois par cycle.",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
term: "Fenêtre fertile",
|
|
222
|
+
definition: "Période de plus grande probabilité de conception, couvrant les 5 jours précédant l'ovulation et le jour de l'ovulation lui-même.",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
term: "Glaire cervicale",
|
|
226
|
+
definition: "Sécrétion du col utérin dont la texture varie au cours du cycle. Pendant les jours fertiles, elle devient transparente, élastique et filante, facilitant le passage des spermatozoïdes.",
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
term: "Température basale",
|
|
230
|
+
definition: "Température corporelle au repos absolu, mesurée au réveil avant toute activité. Elle augmente légèrement (0,2-0,4 °C) après l'ovulation sous l'effet de la progestérone.",
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
faqTitle: "Questions fréquentes",
|
|
236
|
+
faq,
|
|
237
|
+
bibliographyTitle: "Références",
|
|
238
|
+
bibliography: [
|
|
239
|
+
{
|
|
240
|
+
name: "OMS - Planification familiale",
|
|
241
|
+
url: "https://www.who.int/fr/health-topics/family-planning-contraception",
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "American College of Obstetricians and Gynecologists - Fertility Awareness",
|
|
245
|
+
url: "https://www.acog.org/womens-health/faqs/fertility-awareness-based-methods-of-family-planning",
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "Wilcox AJ et al. - Timing of Sexual Intercourse in Relation to Ovulation (NEJM, 1995)",
|
|
249
|
+
url: "https://www.nejm.org/doi/10.1056/NEJM199512073332301",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "NICE - Fertility problems: assessment and treatment",
|
|
253
|
+
url: "https://www.nice.org.uk/guidance/cg156",
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
howTo,
|
|
257
|
+
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
258
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { BabiesToolEntry, ToolDefinition, ToolLocaleContent } from '../../types';
|
|
2
|
+
import FertileDaysEstimatorComponent from './component.astro';
|
|
3
|
+
import FertileDaysEstimatorSEO from './seo.astro';
|
|
4
|
+
import FertileDaysEstimatorBibliography from './bibliography.astro';
|
|
5
|
+
|
|
6
|
+
export interface FertileDaysEstimatorUI {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
step1Title: string;
|
|
9
|
+
step1Desc: string;
|
|
10
|
+
pulseHint: string;
|
|
11
|
+
step1Indicator: string;
|
|
12
|
+
step2Indicator: string;
|
|
13
|
+
sidebarTitle: string;
|
|
14
|
+
sidebarDesc: string;
|
|
15
|
+
labelCycleLength: string;
|
|
16
|
+
unitDays: string;
|
|
17
|
+
labelOvulation: string;
|
|
18
|
+
labelFertileWindow: string;
|
|
19
|
+
labelNextPeriod: string;
|
|
20
|
+
legendSelection: string;
|
|
21
|
+
legendPeriod: string;
|
|
22
|
+
legendFertile: string;
|
|
23
|
+
legendOvulation: string;
|
|
24
|
+
faqTitle: string;
|
|
25
|
+
bibliographyTitle: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type FertileDaysEstimatorLocaleContent = ToolLocaleContent<FertileDaysEstimatorUI>;
|
|
29
|
+
|
|
30
|
+
export const fertileDaysEstimator: BabiesToolEntry<FertileDaysEstimatorUI> = {
|
|
31
|
+
id: 'fertile-days-estimator',
|
|
32
|
+
icons: { bg: 'mdi:calendar-heart', fg: 'mdi:calendar-heart' },
|
|
33
|
+
i18n: {
|
|
34
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
35
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
36
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { FertileDaysEstimatorComponent, FertileDaysEstimatorSEO, FertileDaysEstimatorBibliography };
|
|
41
|
+
|
|
42
|
+
export const FERTILE_DAYS_ESTIMATOR_TOOL: ToolDefinition = {
|
|
43
|
+
entry: fertileDaysEstimator,
|
|
44
|
+
Component: FertileDaysEstimatorComponent,
|
|
45
|
+
SEOComponent: FertileDaysEstimatorSEO,
|
|
46
|
+
BibliographyComponent: FertileDaysEstimatorBibliography,
|
|
47
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface CycleCalcResult {
|
|
2
|
+
ovulationDate: Date;
|
|
3
|
+
fertileStart: Date;
|
|
4
|
+
nextPeriod: Date;
|
|
5
|
+
nextPeriodEnd: Date;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function calculateCycle(selectedDate: Date, cycleLength: number): CycleCalcResult {
|
|
9
|
+
const ovulationDate = new Date(selectedDate);
|
|
10
|
+
ovulationDate.setDate(selectedDate.getDate() + (cycleLength - 14));
|
|
11
|
+
const fertileStart = new Date(ovulationDate);
|
|
12
|
+
fertileStart.setDate(ovulationDate.getDate() - 5);
|
|
13
|
+
const nextPeriod = new Date(selectedDate);
|
|
14
|
+
nextPeriod.setDate(selectedDate.getDate() + cycleLength);
|
|
15
|
+
const nextPeriodEnd = new Date(nextPeriod);
|
|
16
|
+
nextPeriodEnd.setDate(nextPeriod.getDate() + 4);
|
|
17
|
+
return { ovulationDate, fertileStart, nextPeriod, nextPeriodEnd };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getDaysInMonth(year: number, month: number): number {
|
|
21
|
+
return new Date(year, month + 1, 0).getDate();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getMonthStartOffset(year: number, month: number): number {
|
|
25
|
+
const firstDay = new Date(year, month, 1).getDay();
|
|
26
|
+
return firstDay === 0 ? 6 : firstDay - 1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type DayType = 'selected-period' | 'ovulation' | 'fertile' | 'period' | 'today' | '';
|
|
30
|
+
|
|
31
|
+
function isFertileWindow(day: Date, result: CycleCalcResult): boolean {
|
|
32
|
+
return day >= result.fertileStart && day < result.ovulationDate;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isPeriodWindow(day: Date, result: CycleCalcResult): boolean {
|
|
36
|
+
return day >= result.nextPeriod && day <= result.nextPeriodEnd;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getTypedDay(day: Date, selected: Date, result: CycleCalcResult): DayType {
|
|
40
|
+
if (day.getTime() === selected.getTime()) return 'selected-period';
|
|
41
|
+
if (day.getTime() === result.ovulationDate.getTime()) return 'ovulation';
|
|
42
|
+
if (isFertileWindow(day, result)) return 'fertile';
|
|
43
|
+
if (isPeriodWindow(day, result)) return 'period';
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getDayType(
|
|
48
|
+
currentDay: Date,
|
|
49
|
+
selectedDate: Date | null,
|
|
50
|
+
result: CycleCalcResult | null,
|
|
51
|
+
today: Date
|
|
52
|
+
): DayType {
|
|
53
|
+
const isToday = currentDay.getTime() === today.getTime();
|
|
54
|
+
if (!selectedDate || !result) return isToday ? 'today' : '';
|
|
55
|
+
const typed = getTypedDay(currentDay, selectedDate, result);
|
|
56
|
+
if (typed) return typed;
|
|
57
|
+
return isToday ? 'today' : '';
|
|
58
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
SEOTitle, SEOStats, SEOTip, SEOTable,
|
|
4
|
+
SEOList, SEOSummary, SEOComparative, SEOGlossary, SEOArticle,
|
|
5
|
+
} from '@jjlmoya/utils-shared';
|
|
6
|
+
import { fertileDaysEstimator } from './index';
|
|
7
|
+
import type { KnownLocale } from '../../types';
|
|
8
|
+
|
|
9
|
+
interface Props { locale?: KnownLocale; }
|
|
10
|
+
const { locale = 'es' } = Astro.props;
|
|
11
|
+
const content = await fertileDaysEstimator.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
const { seo } = content;
|
|
14
|
+
---
|
|
15
|
+
<SEOArticle>
|
|
16
|
+
{seo.map((section: any) => {
|
|
17
|
+
switch (section.type) {
|
|
18
|
+
case 'summary': return <SEOSummary title={section.title} items={section.items} />;
|
|
19
|
+
case 'title': return <SEOTitle title={section.text} level={section.level || 2} />;
|
|
20
|
+
case 'paragraph': return <p set:html={section.html} />;
|
|
21
|
+
case 'stats': return <SEOStats stats={section.items} columns={section.columns} />;
|
|
22
|
+
case 'tip': return <SEOTip><Fragment set:html={section.html} /></SEOTip>;
|
|
23
|
+
case 'table': return (
|
|
24
|
+
<SEOTable headers={section.headers}>
|
|
25
|
+
{section.rows.map((row: string[]) => (
|
|
26
|
+
<tr>{row.map((cell: string) => <td set:html={cell} />)}</tr>
|
|
27
|
+
))}
|
|
28
|
+
</SEOTable>
|
|
29
|
+
);
|
|
30
|
+
case 'list': return <SEOList items={section.items} />;
|
|
31
|
+
case 'comparative': return <SEOComparative items={section.items} columns={section.columns} />;
|
|
32
|
+
case 'glossary': return <SEOGlossary items={section.items} />;
|
|
33
|
+
default: return null;
|
|
34
|
+
}
|
|
35
|
+
})}
|
|
36
|
+
</SEOArticle>
|