@jjlmoya/utils-cooking 1.2.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 (130) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +24 -0
  3. package/src/category/i18n/es.ts +208 -0
  4. package/src/category/i18n/fr.ts +24 -0
  5. package/src/category/index.ts +37 -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 +32 -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/i18n-titles.test.ts +66 -0
  18. package/src/tests/locale_completeness.test.ts +42 -0
  19. package/src/tests/mocks/astro_mock.js +2 -0
  20. package/src/tests/no_h1_in_components.test.ts +48 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/tool_validation.test.ts +17 -0
  23. package/src/tool/american-kitchen-converter/AmericanKitchenEngine.ts +259 -0
  24. package/src/tool/american-kitchen-converter/bibliography.astro +6 -0
  25. package/src/tool/american-kitchen-converter/component.astro +838 -0
  26. package/src/tool/american-kitchen-converter/i18n/en.ts +282 -0
  27. package/src/tool/american-kitchen-converter/i18n/es.ts +281 -0
  28. package/src/tool/american-kitchen-converter/i18n/fr.ts +292 -0
  29. package/src/tool/american-kitchen-converter/index.ts +24 -0
  30. package/src/tool/american-kitchen-converter/seo.astro +8 -0
  31. package/src/tool/banana-ripeness/BananaCare.css +587 -0
  32. package/src/tool/banana-ripeness/BananaEngine.ts +79 -0
  33. package/src/tool/banana-ripeness/bibliography.astro +6 -0
  34. package/src/tool/banana-ripeness/component.astro +285 -0
  35. package/src/tool/banana-ripeness/i18n/en.ts +177 -0
  36. package/src/tool/banana-ripeness/i18n/es.ts +177 -0
  37. package/src/tool/banana-ripeness/i18n/fr.ts +177 -0
  38. package/src/tool/banana-ripeness/index.ts +24 -0
  39. package/src/tool/banana-ripeness/seo.astro +8 -0
  40. package/src/tool/brine/bibliography.astro +6 -0
  41. package/src/tool/brine/component.astro +884 -0
  42. package/src/tool/brine/i18n/en.ts +221 -0
  43. package/src/tool/brine/i18n/es.ts +222 -0
  44. package/src/tool/brine/i18n/fr.ts +221 -0
  45. package/src/tool/brine/index.ts +26 -0
  46. package/src/tool/brine/seo.astro +8 -0
  47. package/src/tool/cookware-guide/CookwareGuide.css +487 -0
  48. package/src/tool/cookware-guide/bibliography.astro +6 -0
  49. package/src/tool/cookware-guide/component.astro +164 -0
  50. package/src/tool/cookware-guide/i18n/en.ts +163 -0
  51. package/src/tool/cookware-guide/i18n/es.ts +163 -0
  52. package/src/tool/cookware-guide/i18n/fr.ts +164 -0
  53. package/src/tool/cookware-guide/index.ts +24 -0
  54. package/src/tool/cookware-guide/init.ts +174 -0
  55. package/src/tool/cookware-guide/seo.astro +8 -0
  56. package/src/tool/egg-timer/EggTimer.css +503 -0
  57. package/src/tool/egg-timer/bibliography.astro +14 -0
  58. package/src/tool/egg-timer/component.astro +281 -0
  59. package/src/tool/egg-timer/i18n/en.ts +230 -0
  60. package/src/tool/egg-timer/i18n/es.ts +222 -0
  61. package/src/tool/egg-timer/i18n/fr.ts +121 -0
  62. package/src/tool/egg-timer/index.ts +27 -0
  63. package/src/tool/egg-timer/seo.astro +39 -0
  64. package/src/tool/ingredient-rescaler/IngredientRescaler.css +308 -0
  65. package/src/tool/ingredient-rescaler/bibliography.astro +6 -0
  66. package/src/tool/ingredient-rescaler/component.astro +107 -0
  67. package/src/tool/ingredient-rescaler/i18n/en.ts +265 -0
  68. package/src/tool/ingredient-rescaler/i18n/es.ts +268 -0
  69. package/src/tool/ingredient-rescaler/i18n/fr.ts +207 -0
  70. package/src/tool/ingredient-rescaler/index.ts +24 -0
  71. package/src/tool/ingredient-rescaler/init.ts +200 -0
  72. package/src/tool/ingredient-rescaler/seo.astro +8 -0
  73. package/src/tool/kitchen-timer/KitchenTimer.css +325 -0
  74. package/src/tool/kitchen-timer/bibliography.astro +6 -0
  75. package/src/tool/kitchen-timer/component.astro +341 -0
  76. package/src/tool/kitchen-timer/i18n/en.ts +154 -0
  77. package/src/tool/kitchen-timer/i18n/es.ts +154 -0
  78. package/src/tool/kitchen-timer/i18n/fr.ts +154 -0
  79. package/src/tool/kitchen-timer/index.ts +26 -0
  80. package/src/tool/kitchen-timer/init.ts +55 -0
  81. package/src/tool/kitchen-timer/lib/AudioHelper.ts +27 -0
  82. package/src/tool/kitchen-timer/lib/DockManager.ts +97 -0
  83. package/src/tool/kitchen-timer/lib/KitchenTimer.ts +264 -0
  84. package/src/tool/kitchen-timer/seo.astro +8 -0
  85. package/src/tool/meringue-peak/MeringueCalculator.css +298 -0
  86. package/src/tool/meringue-peak/bibliography.astro +6 -0
  87. package/src/tool/meringue-peak/component.astro +169 -0
  88. package/src/tool/meringue-peak/i18n/en.ts +257 -0
  89. package/src/tool/meringue-peak/i18n/es.ts +234 -0
  90. package/src/tool/meringue-peak/i18n/fr.ts +234 -0
  91. package/src/tool/meringue-peak/index.ts +24 -0
  92. package/src/tool/meringue-peak/seo.astro +8 -0
  93. package/src/tool/mold-scaler/MoldScaler.css +406 -0
  94. package/src/tool/mold-scaler/bibliography.astro +6 -0
  95. package/src/tool/mold-scaler/component.astro +126 -0
  96. package/src/tool/mold-scaler/i18n/en.ts +268 -0
  97. package/src/tool/mold-scaler/i18n/es.ts +269 -0
  98. package/src/tool/mold-scaler/i18n/fr.ts +276 -0
  99. package/src/tool/mold-scaler/index.ts +26 -0
  100. package/src/tool/mold-scaler/init.ts +264 -0
  101. package/src/tool/mold-scaler/seo.astro +8 -0
  102. package/src/tool/pizza/Pizza.css +569 -0
  103. package/src/tool/pizza/bibliography.astro +6 -0
  104. package/src/tool/pizza/calculator.ts +143 -0
  105. package/src/tool/pizza/component.astro +237 -0
  106. package/src/tool/pizza/i18n/en.ts +288 -0
  107. package/src/tool/pizza/i18n/es.ts +289 -0
  108. package/src/tool/pizza/i18n/fr.ts +288 -0
  109. package/src/tool/pizza/index.ts +27 -0
  110. package/src/tool/pizza/seo.astro +8 -0
  111. package/src/tool/roux-guide/RouxGuide.css +483 -0
  112. package/src/tool/roux-guide/bibliography.astro +6 -0
  113. package/src/tool/roux-guide/component.astro +194 -0
  114. package/src/tool/roux-guide/i18n/en.ts +233 -0
  115. package/src/tool/roux-guide/i18n/es.ts +225 -0
  116. package/src/tool/roux-guide/i18n/fr.ts +225 -0
  117. package/src/tool/roux-guide/index.ts +24 -0
  118. package/src/tool/roux-guide/init.ts +187 -0
  119. package/src/tool/roux-guide/seo.astro +8 -0
  120. package/src/tool/sourdough-calculator/SourdoughCalculator.css +369 -0
  121. package/src/tool/sourdough-calculator/bibliography.astro +6 -0
  122. package/src/tool/sourdough-calculator/component.astro +198 -0
  123. package/src/tool/sourdough-calculator/i18n/en.ts +242 -0
  124. package/src/tool/sourdough-calculator/i18n/es.ts +243 -0
  125. package/src/tool/sourdough-calculator/i18n/fr.ts +248 -0
  126. package/src/tool/sourdough-calculator/index.ts +24 -0
  127. package/src/tool/sourdough-calculator/init.ts +131 -0
  128. package/src/tool/sourdough-calculator/seo.astro +8 -0
  129. package/src/tools.ts +29 -0
  130. package/src/types.ts +73 -0
@@ -0,0 +1,281 @@
1
+ ---
2
+ import { Icon } from "astro-icon/components";
3
+ import type { ToolLocaleContent } from "../../types";
4
+ import "./EggTimer.css";
5
+
6
+ interface Props {
7
+ ui: ToolLocaleContent["ui"];
8
+ }
9
+
10
+ const { ui } = Astro.props;
11
+ ---
12
+
13
+ <div class="egg-timer-wrapper">
14
+ <div class="egg-timer-container">
15
+ <div class="egg-timer-grid">
16
+ <div class="egg-timer-card">
17
+ <h2 class="egg-timer-title">
18
+ <Icon name="mdi:tune" />
19
+ {ui.parameters}
20
+ </h2>
21
+
22
+ <div class="egg-timer-controls-space">
23
+ <div class="egg-timer-control-group">
24
+ <div class="egg-timer-label-row">
25
+ <label class="egg-timer-label">{ui.initial_temperature}</label>
26
+ </div>
27
+ <div class="egg-timer-buttons-group">
28
+ <button class="egg-timer-btn active" data-temp="4">
29
+ <Icon name="mdi:fridge" />
30
+ <span>{ui.fridge}</span> (4°C)
31
+ </button>
32
+ <button class="egg-timer-btn" data-temp="20">
33
+ <Icon name="mdi:thermometer" />
34
+ <span>{ui.ambient}</span> (20°C)
35
+ </button>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="egg-timer-control-group">
40
+ <div class="egg-timer-label-row">
41
+ <label class="egg-timer-label">{ui.egg_size}</label>
42
+ </div>
43
+ <div class="egg-timer-size-buttons">
44
+ <button class="egg-timer-size-btn" data-size="53">S</button>
45
+ <button class="egg-timer-size-btn active" data-size="58">M</button>
46
+ <button class="egg-timer-size-btn" data-size="63">L</button>
47
+ <button class="egg-timer-size-btn" data-size="73">XL</button>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="egg-timer-control-group">
52
+ <div class="egg-timer-label-row">
53
+ <label class="egg-timer-label">{ui.altitude}</label>
54
+ </div>
55
+ <div class="egg-timer-input-wrapper">
56
+ <input
57
+ type="number"
58
+ id="altitude-input"
59
+ class="egg-timer-input"
60
+ value="0"
61
+ placeholder="0"
62
+ />
63
+ <div class="egg-timer-input-buttons">
64
+ <button class="egg-timer-quick-btn" id="btn-sea">
65
+ {ui.sea_level}
66
+ </button>
67
+ <button class="egg-timer-quick-btn" id="btn-madrid">
68
+ Mad
69
+ </button>
70
+ <button
71
+ class="egg-timer-quick-btn"
72
+ id="btn-location"
73
+ title={ui.use_location}
74
+ >
75
+ <Icon name="mdi:crosshairs-gps" />
76
+ </button>
77
+ </div>
78
+ </div>
79
+ <p class="egg-timer-help-text">{ui.altitude_help}</p>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
84
+ <div class="egg-timer-results">
85
+ <div class="egg-timer-result-card soft">
86
+ <div class="egg-timer-result-header">
87
+ <div>
88
+ <h3 class="egg-timer-result-title">{ui.soft_cooked}</h3>
89
+ <p class="egg-timer-result-subtitle">{ui.soft_description}</p>
90
+ </div>
91
+ <Icon name="mdi:egg-easter" class="egg-timer-result-icon" />
92
+ </div>
93
+ <div class="egg-timer-result-time" id="time-soft">00:00</div>
94
+ </div>
95
+
96
+ <div class="egg-timer-result-card mollet">
97
+ <div class="egg-timer-result-header">
98
+ <div>
99
+ <h3 class="egg-timer-result-title">{ui.mollet}</h3>
100
+ <p class="egg-timer-result-subtitle">{ui.mollet_description}</p>
101
+ </div>
102
+ <Icon name="mdi:egg" class="egg-timer-result-icon" />
103
+ </div>
104
+ <div class="egg-timer-result-time" id="time-mollet">00:00</div>
105
+ </div>
106
+
107
+ <div class="egg-timer-result-card hard">
108
+ <div class="egg-timer-result-header">
109
+ <div>
110
+ <h3 class="egg-timer-result-title">{ui.hard_cooked}</h3>
111
+ <p class="egg-timer-result-subtitle">{ui.hard_description}</p>
112
+ </div>
113
+ <Icon name="mdi:egg-off" class="egg-timer-result-icon" />
114
+ </div>
115
+ <div class="egg-timer-result-time" id="time-hard">00:00</div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <script>
123
+ let currentTemp = 4;
124
+ let currentSize = 58;
125
+ let currentAltitude = 0;
126
+
127
+ const tempBtns = document.querySelectorAll(
128
+ ".egg-timer-btn"
129
+ ) as NodeListOf<HTMLElement>;
130
+ const sizeBtns = document.querySelectorAll(
131
+ ".egg-timer-size-btn"
132
+ ) as NodeListOf<HTMLElement>;
133
+ const altitudeInput = document.getElementById(
134
+ "altitude-input"
135
+ ) as HTMLInputElement | null;
136
+ const btnLocation = document.getElementById("btn-location");
137
+ const btnSea = document.getElementById("btn-sea");
138
+ const btnMadrid = document.getElementById("btn-madrid");
139
+
140
+ function calculateTime(
141
+ mass: number,
142
+ tempStart: number,
143
+ tempTarget: number,
144
+ altitude: number
145
+ ): number {
146
+ const waterBoilingPoint = 100 - 0.0034 * altitude;
147
+
148
+ const term1 = 0.451 * Math.pow(mass, 2 / 3);
149
+ const term2 = Math.log(
150
+ (waterBoilingPoint - tempStart) / (waterBoilingPoint - tempTarget)
151
+ );
152
+
153
+ const minutes = term1 * term2;
154
+ return minutes * 60;
155
+ }
156
+
157
+ function formatTime(seconds: number): string {
158
+ const m = Math.floor(seconds / 60);
159
+ const s = Math.floor(seconds % 60);
160
+ return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
161
+ }
162
+
163
+ function updateCalculations(): void {
164
+ if (!altitudeInput) return;
165
+
166
+ currentAltitude = parseInt(altitudeInput.value) || 0;
167
+
168
+ const tSoft = calculateTime(currentSize, currentTemp, 62, currentAltitude);
169
+ const tMollet = calculateTime(currentSize, currentTemp, 67, currentAltitude);
170
+ const tHard = calculateTime(currentSize, currentTemp, 77, currentAltitude);
171
+
172
+ const elSoft = document.getElementById("time-soft");
173
+ const elMollet = document.getElementById("time-mollet");
174
+ const elHard = document.getElementById("time-hard");
175
+
176
+ if (elSoft) elSoft.textContent = formatTime(tSoft);
177
+ if (elMollet) elMollet.textContent = formatTime(tMollet);
178
+ if (elHard) elHard.textContent = formatTime(tHard);
179
+ }
180
+
181
+ tempBtns.forEach((btn) => {
182
+ btn.addEventListener("click", () => {
183
+ tempBtns.forEach((b) => b.classList.remove("active"));
184
+ btn.classList.add("active");
185
+ currentTemp = parseInt(btn.getAttribute("data-temp") || "0");
186
+ updateCalculations();
187
+ });
188
+ });
189
+
190
+ sizeBtns.forEach((btn) => {
191
+ btn.addEventListener("click", () => {
192
+ sizeBtns.forEach((b) => b.classList.remove("active"));
193
+ btn.classList.add("active");
194
+ currentSize = parseInt(btn.getAttribute("data-size") || "0");
195
+ updateCalculations();
196
+ });
197
+ });
198
+
199
+ if (altitudeInput) {
200
+ altitudeInput.addEventListener("input", updateCalculations);
201
+ }
202
+
203
+ btnSea?.addEventListener("click", () => {
204
+ if (altitudeInput) {
205
+ altitudeInput.value = "0";
206
+ updateCalculations();
207
+ }
208
+ });
209
+
210
+ btnMadrid?.addEventListener("click", () => {
211
+ if (altitudeInput) {
212
+ altitudeInput.value = "600";
213
+ updateCalculations();
214
+ }
215
+ });
216
+
217
+ async function fetchElevationData(
218
+ latitude: number,
219
+ longitude: number
220
+ ): Promise<number | null> {
221
+ try {
222
+ const response = await fetch(
223
+ `https://api.open-meteo.com/v1/elevation?latitude=${latitude}&longitude=${longitude}`
224
+ );
225
+ const data = (await response.json()) as { elevation?: number };
226
+ return data.elevation ?? null;
227
+ } catch {
228
+ return null;
229
+ }
230
+ }
231
+
232
+ async function handleGeolocation(position: GeolocationPosition): Promise<void> {
233
+ const icon = btnLocation?.querySelector("svg");
234
+ let altitude: number | null = position.coords.altitude;
235
+
236
+ if (altitude === null) {
237
+ const { latitude, longitude } = position.coords;
238
+ altitude = await fetchElevationData(latitude, longitude);
239
+ }
240
+
241
+ if (altitude !== null && altitudeInput) {
242
+ altitudeInput.value = Math.round(altitude).toString();
243
+ updateCalculations();
244
+ } else {
245
+ alert(
246
+ "No pudimos obtener tu altitud exacta. Intenta introducirla manualmente."
247
+ );
248
+ }
249
+
250
+ if (icon) icon.classList.remove("animate-spin");
251
+ if (btnLocation) btnLocation.classList.remove("active");
252
+ }
253
+
254
+ function handleGeolocationError(): void {
255
+ const icon = btnLocation?.querySelector("svg");
256
+ console.error("Geolocation error");
257
+ alert("Error al obtener la ubicación. Asegúrate de dar permisos.");
258
+ if (icon) icon.classList.remove("animate-spin");
259
+ if (btnLocation) btnLocation.classList.remove("active");
260
+ }
261
+
262
+ if (btnLocation) {
263
+ btnLocation.addEventListener("click", () => {
264
+ if (!navigator.geolocation) {
265
+ alert("Tu navegador no soporta geolocalización");
266
+ return;
267
+ }
268
+
269
+ const icon = btnLocation.querySelector("svg");
270
+ if (icon) icon.classList.add("animate-spin");
271
+ btnLocation.classList.add("active");
272
+
273
+ navigator.geolocation.getCurrentPosition(
274
+ handleGeolocation,
275
+ handleGeolocationError
276
+ );
277
+ });
278
+ }
279
+
280
+ updateCalculations();
281
+ </script>
@@ -0,0 +1,230 @@
1
+ import type { ToolLocaleContent } from "../../../types";
2
+
3
+ export const content: ToolLocaleContent = {
4
+ slug: "perfect-boiled-egg-timer-altitude-calculator",
5
+ title: "Precision Scientific Egg Timer and Altitude Calculator",
6
+ description:
7
+ "Master the thermodynamics of the perfect egg. Calculate exact boiling times based on your altitude, egg size, and initial temperature.",
8
+ ui: {
9
+ parameters: "Cooking Parameters",
10
+ initial_temperature: "Initial Temp",
11
+ fridge: "Fridge (4°C)",
12
+ ambient: "Room (20°C)",
13
+ egg_size: "Egg Size",
14
+ altitude: "Your Altitude",
15
+ use_location: "Detect Location",
16
+ altitude_help:
17
+ "Lower atmospheric pressure at high altitudes reduces the water boiling point.",
18
+ sea_level: "0m",
19
+ soft_cooked: "Soft Boiled",
20
+ soft_description: "Runny yolk, just-set whites.",
21
+ mollet: "Mollet (Jammy)",
22
+ mollet_description: "Custard-like yolk, firm whites.",
23
+ hard_cooked: "Hard Boiled",
24
+ hard_description: "Solid yolk, fully set whites.",
25
+ },
26
+ faqTitle: "Frequently Asked Questions",
27
+ faq: [
28
+ {
29
+ question: "Why does altitude affect how long eggs take to boil?",
30
+ answer:
31
+ "Water boils at lower temperatures as you go higher in altitude because there is less atmospheric pressure. At 2,000 meters, water boils at roughly 93°C instead of 100°C, meaning your egg needs much more time to reach the same internal temperature.",
32
+ },
33
+ {
34
+ question: "Should I use eggs straight from the fridge?",
35
+ answer:
36
+ "Fridge eggs (around 4°C) require roughly 1.5 to 2 minutes more than room-temperature eggs. Our calculator adjusts for this 'thermal starting line' automatically to ensure perfect results.",
37
+ },
38
+ {
39
+ question: "What causes the unappealing green ring on yolks?",
40
+ answer:
41
+ "The green ring is ferrous sulfide. It forms when the sulfur in the egg white reacts with the iron in the yolk due to overcooking or high heat. To prevent it, use our timer and immediately submerge the egg in an ice bath.",
42
+ },
43
+ {
44
+ question: "Why are some eggs so difficult to peel?",
45
+ answer:
46
+ "Very fresh eggs have a lower pH, making the membrane stick tightly to the shell. For easy peeling, use eggs that are 1-2 weeks old, drop them into already boiling water, and use an ice bath after cooking.",
47
+ },
48
+ ],
49
+ howTo: [
50
+ {
51
+ name: "Define starting conditions",
52
+ text: "Select your egg's initial temperature (Fridge vs. Room) and size (S to XL) to establish the thermodynamic base.",
53
+ },
54
+ {
55
+ name: "Adjust for your location",
56
+ text: "Enter your altitude or use our automatic geolocation to calibrate the exact boiling point of water at your current pressure.",
57
+ },
58
+ {
59
+ name: "Start the precision timer",
60
+ text: "Begin the countdown. Our tool calculates the precise seconds needed to denature specific egg proteins.",
61
+ },
62
+ {
63
+ name: "Apply the ice bath",
64
+ text: "When the timer ends, immediately move the egg to ice-cold water. This 'thermal shock' stops residual cooking and ensures easy peeling.",
65
+ },
66
+ ],
67
+ bibliographyTitle: "Scientific Sources & Thermodynamics",
68
+ bibliography: [
69
+ {
70
+ name: "Charles D. H. Williams - The Physics of Boiling an Egg",
71
+ url: "https://newton.ex.ac.uk/teaching/CDHW/Egg/",
72
+ },
73
+ {
74
+ name: "The Food Lab: The Science of Hard Boiled Eggs",
75
+ url: "https://www.seriouseats.com/the-food-lab-hard-boiled-eggs-recipe",
76
+ },
77
+ {
78
+ name: "Exploratorium - Egg Science and Protein Denaturation",
79
+ url: "https://www.exploratorium.edu/explore/cooking/egg-science",
80
+ },
81
+ ],
82
+ seo: [
83
+ {
84
+ type: "title",
85
+ text: "Master Guide for Precision Egg Boiling and Thermodynamics",
86
+ level: 2,
87
+ },
88
+ {
89
+ type: "paragraph",
90
+ html: "Boiling an egg is a classic exercise in <strong>applied thermodynamics</strong>. Achieving a specific texture is about controlling the rate of heat transfer from the boiling water to the core of the egg, which varies based on pressure, mass, and starting energy.",
91
+ },
92
+ {
93
+ type: "stats",
94
+ columns: 4,
95
+ items: [
96
+ {
97
+ value: "62°C",
98
+ label: "White Sets",
99
+ icon: "mdi:egg-outline",
100
+ },
101
+ {
102
+ value: "68°C",
103
+ label: "Yolk Sets",
104
+ icon: "mdi:egg-fried",
105
+ },
106
+ {
107
+ value: "-1°C",
108
+ label: "Boil Drop / 300m",
109
+ icon: "mdi:mountain",
110
+ },
111
+ {
112
+ value: "0s",
113
+ label: "Timing Margin",
114
+ icon: "mdi:timer-check-outline",
115
+ },
116
+ ],
117
+ },
118
+ {
119
+ type: "title",
120
+ text: "Comparison of Egg Boiling Stages",
121
+ level: 3,
122
+ },
123
+ {
124
+ type: "comparative",
125
+ columns: 3,
126
+ items: [
127
+ {
128
+ title: "Soft Boiled (Dippy)",
129
+ icon: "mdi:coffee-outline",
130
+ description: "Partially set whites and completely liquid, golden yolk.",
131
+ points: [
132
+ "Delicate silken texture",
133
+ "Perfect for toast soldiers",
134
+ "Quick 3-5 min cook time",
135
+ "Highest peeling difficulty",
136
+ ],
137
+ },
138
+ {
139
+ title: "Mollet (Jammy)",
140
+ icon: "mdi:water-percent",
141
+ description: "Firm, established whites with a custard-like, thick yolk.",
142
+ highlight: true,
143
+ points: [
144
+ "The culinary gold standard",
145
+ "Honey-thick yolk texture",
146
+ "Elastic, resilient whites",
147
+ "Ideal for bowls and ramen",
148
+ ],
149
+ },
150
+ {
151
+ title: "Hard Boiled",
152
+ icon: "mdi:circle-slice-8",
153
+ description: "Completely set proteins with a solid, tender yolk.",
154
+ points: [
155
+ "Solid and opaque center",
156
+ "Easiest to transport/peel",
157
+ "Mainstay for deviled eggs",
158
+ "Requires instant cooling",
159
+ ],
160
+ },
161
+ ],
162
+ },
163
+ {
164
+ type: "title",
165
+ text: "Water Boiling Points by Altitude",
166
+ level: 3,
167
+ },
168
+ {
169
+ type: "table",
170
+ headers: [
171
+ "City / Altitude",
172
+ "Elevation (m)",
173
+ "Boiling Point (°C)",
174
+ "Added Time",
175
+ ],
176
+ rows: [
177
+ ["Sea Level (Coast)", "0m", "100°C", "0s"],
178
+ ["Denver, USA", "1600m", "94.5°C", "+55s"],
179
+ ["Mexico City", "2240m", "92.6°C", "+75s"],
180
+ ["La Paz, Bolivia", "3640m", "88.1°C", "+140s"],
181
+ ],
182
+ },
183
+ {
184
+ type: "diagnostic",
185
+ variant: "warning",
186
+ title: "Hard to Peel or Green Yolk Syndrome?",
187
+ html: "The green ring is <strong>ferrous sulfide</strong> caused by overcooking (sulfur from whites reacting with iron in yolks). If eggs won't peel, they are too fresh; a low pH causes the membrane to fuse to the shell. Use week-old eggs and a vigorous ice bath.",
188
+ },
189
+ {
190
+ type: "title",
191
+ text: "Egg Science Technical Glossary",
192
+ level: 3,
193
+ },
194
+ {
195
+ type: "glossary",
196
+ items: [
197
+ {
198
+ term: "Ovotransferrin",
199
+ definition:
200
+ "The egg white protein that sets first at 62°C, providing the initial white structure.",
201
+ },
202
+ {
203
+ term: "Ovalbumin",
204
+ definition:
205
+ "The major egg protein requiring higher heat (80°C) to reach full solidification.",
206
+ },
207
+ {
208
+ term: "Atmospheric Pressure",
209
+ definition:
210
+ "The external force affecting boiling temperature; lower pressure equals a lower boil.",
211
+ },
212
+ {
213
+ term: "Thermal Shock",
214
+ definition:
215
+ "The process of rapid cooling to instantly halt residual internal heat transfer.",
216
+ },
217
+ ],
218
+ },
219
+ {
220
+ type: "tip",
221
+ title: "The Vinegar and Salt Hook",
222
+ html: "Add vinegar to your boiling water. If an egg cracks, the acid will cause the leaking white to coagulate instantly, plugging the hole and preventing a 'web' from forming.",
223
+ },
224
+ {
225
+ type: "paragraph",
226
+ html: "Our calculator utilizes the Charles Williams equation to calibrate every second based on your location and fridge temperature.",
227
+ },
228
+ ],
229
+ schemas: [],
230
+ };