@jjlmoya/utils-babies 1.2.0 → 1.4.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 (27) hide show
  1. package/package.json +2 -2
  2. package/src/tool/baby-feeding-calculator/bibliography.astro +8 -4
  3. package/src/tool/baby-feeding-calculator/component.astro +208 -177
  4. package/src/tool/baby-feeding-calculator/style.css +317 -229
  5. package/src/tool/baby-percentile-calculator/bibliography.astro +8 -4
  6. package/src/tool/baby-percentile-calculator/component.astro +98 -240
  7. package/src/tool/baby-percentile-calculator/i18n/en.ts +1 -0
  8. package/src/tool/baby-percentile-calculator/i18n/es.ts +1 -0
  9. package/src/tool/baby-percentile-calculator/i18n/fr.ts +1 -0
  10. package/src/tool/baby-percentile-calculator/index.ts +1 -0
  11. package/src/tool/baby-percentile-calculator/style.css +342 -268
  12. package/src/tool/baby-size-converter/bibliography.astro +8 -4
  13. package/src/tool/baby-size-converter/component.astro +221 -212
  14. package/src/tool/baby-size-converter/style.css +433 -263
  15. package/src/tool/fertile-days-estimator/bibliography.astro +8 -4
  16. package/src/tool/fertile-days-estimator/component.astro +202 -200
  17. package/src/tool/fertile-days-estimator/style.css +408 -270
  18. package/src/tool/pregnancy-calculator/bibliography.astro +8 -4
  19. package/src/tool/pregnancy-calculator/component.astro +50 -8
  20. package/src/tool/pregnancy-calculator/i18n/en.ts +8 -0
  21. package/src/tool/pregnancy-calculator/i18n/es.ts +8 -0
  22. package/src/tool/pregnancy-calculator/i18n/fr.ts +8 -0
  23. package/src/tool/pregnancy-calculator/index.ts +8 -0
  24. package/src/tool/pregnancy-calculator/style.css +351 -134
  25. package/src/tool/vaccination-calendar/bibliography.astro +8 -4
  26. package/src/tool/vaccination-calendar/component.astro +120 -124
  27. package/src/tool/vaccination-calendar/style.css +296 -209
@@ -1,7 +1,11 @@
1
1
  ---
2
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;
3
+ import { fertileDaysEstimator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props { locale?: KnownLocale; }
7
+ const { locale = 'es' } = Astro.props;
8
+ const content = await fertileDaysEstimator.i18n[locale]?.();
9
+ if (!content) return null;
6
10
  ---
7
- <BibliographyUI links={links} title={title} />
11
+ <BibliographyUI links={content.bibliography} title={content.bibliographyTitle ?? ''} />
@@ -1,265 +1,267 @@
1
1
  ---
2
2
  import './style.css';
3
+ import { Icon } from 'astro-icon/components';
3
4
  import type { FertileDaysEstimatorUI } from './index';
4
5
  interface Props { ui: FertileDaysEstimatorUI; }
5
6
  const { ui } = Astro.props;
6
7
  ---
7
- <div id="fertile-days-estimator-root" class="fertile-days-estimator" data-ui={JSON.stringify(ui)}>
8
- <div class="fertile-days-estimator-step-indicator">
9
- <div class="fertile-days-estimator-step-item active" id="fde-step-1-indicator">
10
- <span class="fertile-days-estimator-step-number">1</span>
8
+ <div id="fertile-days-estimator-root" class="fde-container" data-ui={JSON.stringify(ui)}>
9
+ <div class="fde-step-indicator">
10
+ <div class="fde-step-item fde-step-active" id="fde-indicator-1">
11
+ <div class="fde-step-number">1</div>
11
12
  <span>{ui.step1Indicator}</span>
12
13
  </div>
13
- <div class="fertile-days-estimator-step-item" id="fde-step-2-indicator">
14
- <span class="fertile-days-estimator-step-number">2</span>
14
+ <div class="fde-step-item" id="fde-indicator-2">
15
+ <div class="fde-step-number">2</div>
15
16
  <span>{ui.step2Indicator}</span>
16
17
  </div>
17
18
  </div>
18
19
 
19
- <div class="fertile-days-estimator-step-first" id="fde-step-first">
20
- <h2 class="fertile-days-estimator-step-title">{ui.step1Title}</h2>
21
- <p class="fertile-days-estimator-step-subtitle">{ui.step1Desc}</p>
22
- <p class="fertile-days-estimator-pulse-hint">{ui.pulseHint}</p>
23
- <div class="fertile-days-estimator-calendar" id="fde-calendar-initial">
24
- <div class="fertile-days-estimator-calendar-nav">
25
- <span id="fde-month-label-initial" class="fertile-days-estimator-month-label"></span>
26
- <div class="fertile-days-estimator-nav-buttons">
27
- <button class="fertile-days-estimator-nav-btn" id="fde-prev-initial" aria-label="Mes anterior">
28
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
29
- <path d="M15 18l-6-6 6-6" />
30
- </svg>
20
+ <div class="fde-step-first" id="fde-step-1">
21
+ <div class="fde-step-header">
22
+ <h2>{ui.step1Title}</h2>
23
+ <p>{ui.step1Desc}</p>
24
+ </div>
25
+
26
+ <div class="fde-calendar-card">
27
+ <div class="fde-cal-nav">
28
+ <h3 id="fde-initial-month-year">Mes Año</h3>
29
+ <div class="fde-nav-buttons">
30
+ <button class="fde-nav-btn" id="fde-initial-prev-month" aria-label="Mes anterior">
31
+ <Icon name="mdi:chevron-left" />
31
32
  </button>
32
- <button class="fertile-days-estimator-nav-btn" id="fde-next-initial" aria-label="Mes siguiente">
33
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
34
- <path d="M9 18l6-6-6-6" />
35
- </svg>
33
+ <button class="fde-nav-btn" id="fde-initial-next-month" aria-label="Mes siguiente">
34
+ <Icon name="mdi:chevron-right" />
36
35
  </button>
37
36
  </div>
38
37
  </div>
39
- <div class="fertile-days-estimator-calendar-grid" id="fde-grid-initial"></div>
38
+ <div class="fde-grid" id="fde-initial-calendar-grid"></div>
40
39
  </div>
40
+
41
+ <div class="fde-pulse-hint">{ui.pulseHint}</div>
41
42
  </div>
42
43
 
43
- <div class="fertile-days-estimator-layout" id="fde-layout">
44
- <aside class="fertile-days-estimator-sidebar">
45
- <div class="fertile-days-estimator-sidebar-header">
46
- <strong>{ui.sidebarTitle}</strong>
44
+ <div class="fde-layout" id="fde-step-2">
45
+ <aside class="fde-sidebar">
46
+ <div class="fde-sidebar-header">
47
+ <h2>{ui.sidebarTitle}</h2>
47
48
  <p>{ui.sidebarDesc}</p>
48
49
  </div>
49
- <div class="fertile-days-estimator-input-card">
50
- <label class="fertile-days-estimator-range-label" for="fde-cycle-length">{ui.labelCycleLength}</label>
51
- <div class="fertile-days-estimator-range-control">
52
- <input
53
- type="range"
54
- id="fde-cycle-length"
55
- min="21"
56
- max="35"
57
- value="28"
58
- class="fertile-days-estimator-range-input"
59
- />
60
- <span class="fertile-days-estimator-range-value" id="fde-cycle-value">28 <span>{ui.unitDays}</span></span>
50
+
51
+ <div class="fde-input-card">
52
+ <label>
53
+ <Icon name="mdi:calendar-edit" />
54
+ {ui.labelCycleLength}
55
+ </label>
56
+ <div class="fde-range-control">
57
+ <div class="fde-range-value" id="fde-cycle-value">28 <span>{ui.unitDays}</span></div>
58
+ <input type="range" id="fde-cycle-length" min="20" max="45" value="28" />
61
59
  </div>
62
60
  </div>
63
- <div class="fertile-days-estimator-results" id="fde-results">
64
- <div class="fertile-days-estimator-stat" id="fde-stat-ovulation">
65
- <div class="fertile-days-estimator-stat-dot fertile-days-estimator-stat-dot-ovulation"></div>
66
- <div class="fertile-days-estimator-stat-info">
67
- <span class="fertile-days-estimator-stat-label">{ui.labelOvulation}</span>
68
- <span class="fertile-days-estimator-stat-value" id="fde-val-ovulation">—</span>
61
+
62
+ <div class="fde-results">
63
+ <div class="fde-stat fde-stat-ovulation">
64
+ <Icon name="mdi:calendar-check" />
65
+ <div class="fde-stat-info">
66
+ <span class="fde-stat-label">{ui.labelOvulation}</span>
67
+ <span class="fde-stat-value" id="fde-val-ovulation">-</span>
69
68
  </div>
70
69
  </div>
71
- <div class="fertile-days-estimator-stat" id="fde-stat-fertile">
72
- <div class="fertile-days-estimator-stat-dot fertile-days-estimator-stat-dot-fertile"></div>
73
- <div class="fertile-days-estimator-stat-info">
74
- <span class="fertile-days-estimator-stat-label">{ui.labelFertileWindow}</span>
75
- <span class="fertile-days-estimator-stat-value" id="fde-val-fertile">—</span>
70
+ <div class="fde-stat fde-stat-fertile">
71
+ <Icon name="mdi:heart-pulse" />
72
+ <div class="fde-stat-info">
73
+ <span class="fde-stat-label">{ui.labelFertileWindow}</span>
74
+ <span class="fde-stat-value" id="fde-val-fertile">-</span>
76
75
  </div>
77
76
  </div>
78
- <div class="fertile-days-estimator-stat" id="fde-stat-period">
79
- <div class="fertile-days-estimator-stat-dot fertile-days-estimator-stat-dot-period"></div>
80
- <div class="fertile-days-estimator-stat-info">
81
- <span class="fertile-days-estimator-stat-label">{ui.labelNextPeriod}</span>
82
- <span class="fertile-days-estimator-stat-value" id="fde-val-period">—</span>
77
+ <div class="fde-stat fde-stat-period">
78
+ <Icon name="mdi:water" />
79
+ <div class="fde-stat-info">
80
+ <span class="fde-stat-label">{ui.labelNextPeriod}</span>
81
+ <span class="fde-stat-value" id="fde-val-period">-</span>
83
82
  </div>
84
83
  </div>
85
84
  </div>
86
85
  </aside>
87
86
 
88
- <div class="fertile-days-estimator-content">
89
- <div class="fertile-days-estimator-calendar" id="fde-calendar-main">
90
- <div class="fertile-days-estimator-calendar-nav">
91
- <span id="fde-month-label-main" class="fertile-days-estimator-month-label"></span>
92
- <div class="fertile-days-estimator-nav-buttons">
93
- <button class="fertile-days-estimator-nav-btn" id="fde-prev-main" aria-label="Mes anterior">
94
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
95
- <path d="M15 18l-6-6 6-6" />
96
- </svg>
87
+ <main class="fde-main">
88
+ <div class="fde-calendar-wrapper" id="fde-calendar-area">
89
+ <div class="fde-cal-nav">
90
+ <h3 id="fde-calendar-month-year">Mes Año</h3>
91
+ <div class="fde-nav-buttons">
92
+ <button class="fde-nav-btn" id="fde-prev-month" aria-label="Mes anterior">
93
+ <Icon name="mdi:chevron-left" />
97
94
  </button>
98
- <button class="fertile-days-estimator-nav-btn" id="fde-next-main" aria-label="Mes siguiente">
99
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
100
- <path d="M9 18l6-6-6-6" />
101
- </svg>
95
+ <button class="fde-nav-btn" id="fde-next-month" aria-label="Mes siguiente">
96
+ <Icon name="mdi:chevron-right" />
102
97
  </button>
103
98
  </div>
104
99
  </div>
105
- <div class="fertile-days-estimator-calendar-grid" id="fde-grid-main"></div>
106
- </div>
107
- <div class="fertile-days-estimator-legend">
108
- <div class="fertile-days-estimator-legend-item">
109
- <span class="fertile-days-estimator-legend-dot fertile-days-estimator-legend-dot-selected"></span>
110
- <span>{ui.legendSelection}</span>
111
- </div>
112
- <div class="fertile-days-estimator-legend-item">
113
- <span class="fertile-days-estimator-legend-dot fertile-days-estimator-legend-dot-period"></span>
114
- <span>{ui.legendPeriod}</span>
115
- </div>
116
- <div class="fertile-days-estimator-legend-item">
117
- <span class="fertile-days-estimator-legend-dot fertile-days-estimator-legend-dot-fertile"></span>
118
- <span>{ui.legendFertile}</span>
119
- </div>
120
- <div class="fertile-days-estimator-legend-item">
121
- <span class="fertile-days-estimator-legend-dot fertile-days-estimator-legend-dot-ovulation"></span>
122
- <span>{ui.legendOvulation}</span>
100
+ <div class="fde-grid" id="fde-calendar-grid"></div>
101
+ <div class="fde-legend">
102
+ <div class="fde-legend-item">
103
+ <div class="fde-legend-dot fde-dot-selected"></div>
104
+ <span>{ui.legendSelection}</span>
105
+ </div>
106
+ <div class="fde-legend-item">
107
+ <div class="fde-legend-dot fde-dot-period"></div>
108
+ <span>{ui.legendPeriod}</span>
109
+ </div>
110
+ <div class="fde-legend-item">
111
+ <div class="fde-legend-dot fde-dot-fertile"></div>
112
+ <span>{ui.legendFertile}</span>
113
+ </div>
114
+ <div class="fde-legend-item">
115
+ <div class="fde-legend-dot fde-dot-ovulation"></div>
116
+ <span>{ui.legendOvulation}</span>
117
+ </div>
123
118
  </div>
124
119
  </div>
125
- </div>
120
+ </main>
126
121
  </div>
127
122
  </div>
128
123
 
129
124
  <script>
130
- import { calculateCycle, getDaysInMonth, getMonthStartOffset, getDayType } from './logic';
131
- import type { CycleCalcResult } from './logic';
125
+ import { calculateCycle } from './logic';
132
126
 
133
127
  const root = document.getElementById('fertile-days-estimator-root') as HTMLElement;
134
128
  const ui = JSON.parse(root.dataset.ui as string) as Record<string, string>;
135
129
 
136
130
  let selectedDate: Date | null = null;
137
- let cycleLength = 28;
138
- let result: CycleCalcResult | null = null;
139
-
140
- const now = new Date();
141
- let viewDate = new Date(now.getFullYear(), now.getMonth(), 1);
142
-
143
- const stepFirstEl = root.querySelector('#fde-step-first') as HTMLElement;
144
- const layoutEl = root.querySelector('#fde-layout') as HTMLElement;
145
- const step1Indicator = root.querySelector('#fde-step-1-indicator') as HTMLElement;
146
- const step2Indicator = root.querySelector('#fde-step-2-indicator') as HTMLElement;
147
- const cycleLengthInput = root.querySelector('#fde-cycle-length') as HTMLInputElement;
148
- const cycleValueEl = root.querySelector('#fde-cycle-value') as HTMLElement;
149
- const gridInitial = root.querySelector('#fde-grid-initial') as HTMLElement;
150
- const gridMain = root.querySelector('#fde-grid-main') as HTMLElement;
151
- const monthLabelInitial = root.querySelector('#fde-month-label-initial') as HTMLElement;
152
- const monthLabelMain = root.querySelector('#fde-month-label-main') as HTMLElement;
153
- const valOvulation = root.querySelector('#fde-val-ovulation') as HTMLElement;
154
- const valFertile = root.querySelector('#fde-val-fertile') as HTMLElement;
155
- const valPeriod = root.querySelector('#fde-val-period') as HTMLElement;
156
-
157
- const DAY_HEADERS = ['L', 'M', 'X', 'J', 'V', 'S', 'D'];
158
-
159
- const fmt = new Intl.DateTimeFormat('es-ES', { day: 'numeric', month: 'short' });
160
- const fmtMonth = new Intl.DateTimeFormat('es-ES', { month: 'long', year: 'numeric' });
161
-
162
- function getToday(): Date {
163
- const t = new Date();
164
- t.setHours(0, 0, 0, 0);
165
- return t;
131
+ const viewDate = new Date();
132
+ viewDate.setDate(1);
133
+
134
+ const step1El = document.getElementById('fde-step-1') as HTMLElement;
135
+ const step2El = document.getElementById('fde-step-2') as HTMLElement;
136
+ const indicator1 = document.getElementById('fde-indicator-1') as HTMLElement;
137
+ const indicator2 = document.getElementById('fde-indicator-2') as HTMLElement;
138
+ const cycleLengthInput = document.getElementById('fde-cycle-length') as HTMLInputElement;
139
+ const cycleValueDisplay = document.getElementById('fde-cycle-value') as HTMLElement;
140
+ const ovulationDateEl = document.getElementById('fde-val-ovulation') as HTMLElement;
141
+ const fertileRangeEl = document.getElementById('fde-val-fertile') as HTMLElement;
142
+ const nextPeriodEl = document.getElementById('fde-val-period') as HTMLElement;
143
+ const calendarGrid = document.getElementById('fde-calendar-grid') as HTMLElement;
144
+ const calendarMonthYear = document.getElementById('fde-calendar-month-year') as HTMLElement;
145
+ const initialCalendarGrid = document.getElementById('fde-initial-calendar-grid') as HTMLElement;
146
+ const initialMonthYear = document.getElementById('fde-initial-month-year') as HTMLElement;
147
+ const prevMonthBtn = document.getElementById('fde-prev-month') as HTMLButtonElement;
148
+ const nextMonthBtn = document.getElementById('fde-next-month') as HTMLButtonElement;
149
+ const initialPrevBtn = document.getElementById('fde-initial-prev-month') as HTMLButtonElement;
150
+ const initialNextBtn = document.getElementById('fde-initial-next-month') as HTMLButtonElement;
151
+
152
+ const DAY_NAMES = ['Lun', 'Mar', 'Mié', 'Juv', 'Vie', 'Sáb', 'Dom'];
153
+
154
+ function updateCalculations(): void {
155
+ if (!selectedDate) return;
156
+ const cycleLength = parseInt(cycleLengthInput.value);
157
+ if (cycleValueDisplay) cycleValueDisplay.innerHTML = `${cycleLength} <span>${ui['unitDays'] ?? ''}</span>`;
158
+
159
+ const result = calculateCycle(selectedDate, cycleLength);
160
+
161
+ const dtf = new Intl.DateTimeFormat('es-ES', { day: 'numeric', month: 'long' });
162
+ if (ovulationDateEl) ovulationDateEl.textContent = dtf.format(result.ovulationDate);
163
+ if (fertileRangeEl) fertileRangeEl.textContent = `${dtf.format(result.fertileStart)} – ${dtf.format(result.ovulationDate)}`;
164
+ if (nextPeriodEl) nextPeriodEl.textContent = dtf.format(result.nextPeriod);
165
+
166
+ renderCalendars();
167
+ }
168
+
169
+ function renderCalendars(): void {
170
+ renderGrid(initialCalendarGrid, initialMonthYear, true);
171
+ renderGrid(calendarGrid, calendarMonthYear, false);
166
172
  }
167
173
 
168
- function buildGrid(container: HTMLElement, isInitial: boolean): void {
169
- container.innerHTML = '';
174
+ function renderGrid(grid: HTMLElement | null, monthYearEl: HTMLElement | null, isInitial: boolean): void {
175
+ if (!grid || !monthYearEl) return;
176
+ grid.innerHTML = '';
177
+
170
178
  const year = viewDate.getFullYear();
171
179
  const month = viewDate.getMonth();
172
- const daysInMonth = getDaysInMonth(year, month);
173
- const offset = getMonthStartOffset(year, month);
174
- const today = getToday();
175
- const frag = document.createDocumentFragment();
176
- DAY_HEADERS.forEach((h) => {
177
- const el = document.createElement('div');
178
- el.className = 'fertile-days-estimator-day-header';
179
- el.textContent = h;
180
- frag.appendChild(el);
180
+
181
+ monthYearEl.textContent = new Intl.DateTimeFormat('es-ES', { month: 'long', year: 'numeric' }).format(viewDate);
182
+
183
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
184
+ const firstDay = new Date(year, month, 1).getDay();
185
+ const startOffset = firstDay === 0 ? 6 : firstDay - 1;
186
+
187
+ DAY_NAMES.forEach((day) => {
188
+ const header = document.createElement('div');
189
+ header.className = 'fde-day-header';
190
+ header.textContent = day;
191
+ grid.appendChild(header);
181
192
  });
182
- for (let i = 0; i < offset; i++) {
193
+
194
+ for (let i = 0; i < startOffset; i++) {
183
195
  const el = document.createElement('div');
184
- el.className = 'fertile-days-estimator-day fertile-days-estimator-day-empty';
185
- frag.appendChild(el);
196
+ el.className = 'fde-day fde-day-empty';
197
+ grid.appendChild(el);
186
198
  }
199
+
200
+ const cycleLength = parseInt(cycleLengthInput ? cycleLengthInput.value : '28');
201
+ const today = new Date();
202
+ today.setHours(0, 0, 0, 0);
203
+
187
204
  for (let d = 1; d <= daysInMonth; d++) {
188
- const dayDate = new Date(year, month, d);
189
- dayDate.setHours(0, 0, 0, 0);
190
- const dayType = getDayType(dayDate, selectedDate, result, today);
191
- const el = document.createElement('button');
192
- el.className = 'fertile-days-estimator-day';
193
- if (dayType) el.classList.add(`fertile-days-estimator-day--${dayType}`);
194
- el.textContent = String(d);
195
- el.addEventListener('click', () => onDayClick(dayDate, isInitial));
196
- frag.appendChild(el);
197
- }
198
- container.appendChild(frag);
199
- }
205
+ const currentDay = new Date(year, month, d);
206
+ currentDay.setHours(0, 0, 0, 0);
200
207
 
201
- function updateMonthLabel(): void {
202
- const label = fmtMonth.format(viewDate);
203
- monthLabelInitial.textContent = label;
204
- monthLabelMain.textContent = label;
205
- }
208
+ const dayEl = document.createElement('div');
209
+ dayEl.className = 'fde-day';
210
+ dayEl.textContent = String(d);
206
211
 
207
- function updateResults(): void {
208
- if (!selectedDate || !result) return;
209
- valOvulation.textContent = fmt.format(result.ovulationDate);
210
- valFertile.textContent = `${fmt.format(result.fertileStart)} – ${fmt.format(result.ovulationDate)}`;
211
- valPeriod.textContent = fmt.format(result.nextPeriod);
212
- }
212
+ if (currentDay.getTime() === today.getTime()) dayEl.classList.add('fde-day-today');
213
+
214
+ if (selectedDate && currentDay.getTime() === selectedDate.getTime()) {
215
+ dayEl.classList.add('fde-day-selected');
216
+ }
217
+
218
+ if (selectedDate) {
219
+ const result = calculateCycle(selectedDate, cycleLength);
220
+ const nextPeriodEnd = new Date(result.nextPeriod);
221
+ nextPeriodEnd.setDate(result.nextPeriod.getDate() + 4);
222
+
223
+ if (currentDay.getTime() === result.ovulationDate.getTime()) {
224
+ dayEl.classList.add('fde-day-ovulation');
225
+ } else if (currentDay >= result.fertileStart && currentDay < result.ovulationDate) {
226
+ dayEl.classList.add('fde-day-fertile');
227
+ } else if (currentDay >= result.nextPeriod && currentDay <= nextPeriodEnd) {
228
+ dayEl.classList.add('fde-day-period');
229
+ }
230
+ }
231
+
232
+ dayEl.addEventListener('click', () => {
233
+ selectedDate = new Date(currentDay);
234
+ if (isInitial) goToStep2();
235
+ else updateCalculations();
236
+ });
213
237
 
214
- function renderAll(): void {
215
- updateMonthLabel();
216
- buildGrid(gridInitial, true);
217
- buildGrid(gridMain, false);
218
- updateResults();
238
+ grid.appendChild(dayEl);
239
+ }
219
240
  }
220
241
 
221
242
  function goToStep2(): void {
222
- stepFirstEl.classList.add('hidden');
223
- layoutEl.classList.add('active');
224
- step1Indicator.classList.remove('active');
225
- step2Indicator.classList.add('active');
243
+ if (step1El) step1El.classList.add('fde-hidden');
244
+ if (step2El) step2El.classList.add('fde-active');
245
+ if (indicator1) indicator1.classList.remove('fde-step-active');
246
+ if (indicator2) indicator2.classList.add('fde-step-active');
247
+ updateCalculations();
226
248
  }
227
249
 
228
- function onDayClick(day: Date, isInitial: boolean): void {
229
- selectedDate = day;
230
- result = calculateCycle(day, cycleLength);
231
- if (isInitial) goToStep2();
232
- renderAll();
233
- }
250
+ cycleLengthInput?.addEventListener('input', updateCalculations);
234
251
 
235
- cycleLengthInput.addEventListener('input', () => {
236
- cycleLength = Number(cycleLengthInput.value);
237
- cycleValueEl.textContent = `${cycleLength} `;
238
- const span = document.createElement('span');
239
- span.textContent = ui['unitDays'] ?? '';
240
- cycleValueEl.appendChild(span);
241
- if (selectedDate) {
242
- result = calculateCycle(selectedDate, cycleLength);
243
- renderAll();
244
- }
245
- });
246
-
247
- root.querySelector('#fde-prev-initial')?.addEventListener('click', () => {
248
- viewDate = new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1);
249
- renderAll();
250
- });
251
- root.querySelector('#fde-next-initial')?.addEventListener('click', () => {
252
- viewDate = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1);
253
- renderAll();
254
- });
255
- root.querySelector('#fde-prev-main')?.addEventListener('click', () => {
256
- viewDate = new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1);
257
- renderAll();
258
- });
259
- root.querySelector('#fde-next-main')?.addEventListener('click', () => {
260
- viewDate = new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1);
261
- renderAll();
262
- });
263
-
264
- renderAll();
252
+ [prevMonthBtn, initialPrevBtn].forEach(btn =>
253
+ btn?.addEventListener('click', () => {
254
+ viewDate.setMonth(viewDate.getMonth() - 1);
255
+ renderCalendars();
256
+ })
257
+ );
258
+
259
+ [nextMonthBtn, initialNextBtn].forEach(btn =>
260
+ btn?.addEventListener('click', () => {
261
+ viewDate.setMonth(viewDate.getMonth() + 1);
262
+ renderCalendars();
263
+ })
264
+ );
265
+
266
+ renderCalendars();
265
267
  </script>