@jjlmoya/utils-cooking 1.35.0 → 1.36.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 +1 -1
- package/src/category/index.ts +2 -0
- package/src/entries.ts +3 -1
- package/src/index.ts +1 -0
- package/src/tests/i18n-titles.test.ts +1 -1
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/macaron-drying-predictor/bibliography.astro +6 -0
- package/src/tool/macaron-drying-predictor/bibliography.ts +14 -0
- package/src/tool/macaron-drying-predictor/component.astro +319 -0
- package/src/tool/macaron-drying-predictor/entry.ts +26 -0
- package/src/tool/macaron-drying-predictor/i18n/de.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/en.ts +247 -0
- package/src/tool/macaron-drying-predictor/i18n/es.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/fr.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/id.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/it.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/ja.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/ko.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/nl.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/pl.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/pt.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/ru.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/sv.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/tr.ts +245 -0
- package/src/tool/macaron-drying-predictor/i18n/zh.ts +245 -0
- package/src/tool/macaron-drying-predictor/index.ts +11 -0
- package/src/tool/macaron-drying-predictor/logic.ts +58 -0
- package/src/tool/macaron-drying-predictor/macaron-drying-predictor.css +551 -0
- package/src/tool/macaron-drying-predictor/seo.astro +15 -0
- package/src/tools.ts +2 -0
package/package.json
CHANGED
package/src/category/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { botulismCanningSafety } from '../tool/botulism-canning-safety/entry';
|
|
|
18
18
|
import { meatBinder } from '../tool/meat-binder-transglutaminase-calculator/entry';
|
|
19
19
|
import { carryOverCooking } from '../tool/carry-over-cooking-predictor/entry';
|
|
20
20
|
import { maillardReaction } from '../tool/maillard-reaction-optimizer/entry';
|
|
21
|
+
import { macaronDrying } from '../tool/macaron-drying-predictor/entry';
|
|
21
22
|
|
|
22
23
|
export const cookingCategory: CookingCategoryEntry = {
|
|
23
24
|
icon: 'mdi:chef-hat',
|
|
@@ -41,6 +42,7 @@ export const cookingCategory: CookingCategoryEntry = {
|
|
|
41
42
|
meatBinder,
|
|
42
43
|
carryOverCooking,
|
|
43
44
|
maillardReaction,
|
|
45
|
+
macaronDrying,
|
|
44
46
|
],
|
|
45
47
|
|
|
46
48
|
i18n: {
|
package/src/entries.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { iceCreamPacPod } from './tool/ice-cream-pac-pod/entry';
|
|
|
17
17
|
export { meatBinder } from './tool/meat-binder-transglutaminase-calculator/entry';
|
|
18
18
|
export { carryOverCooking } from './tool/carry-over-cooking-predictor/entry';
|
|
19
19
|
export { maillardReaction } from './tool/maillard-reaction-optimizer/entry';
|
|
20
|
+
export { macaronDrying } from './tool/macaron-drying-predictor/entry';
|
|
20
21
|
export { botulismCanningSafety } from './tool/botulism-canning-safety/entry';
|
|
21
22
|
export { cookingCategory } from './category';
|
|
22
23
|
import { americanKitchenConverter } from './tool/american-kitchen-converter/entry';
|
|
@@ -39,5 +40,6 @@ import { botulismCanningSafety } from './tool/botulism-canning-safety/entry';
|
|
|
39
40
|
import { meatBinder } from './tool/meat-binder-transglutaminase-calculator/entry';
|
|
40
41
|
import { carryOverCooking } from './tool/carry-over-cooking-predictor/entry';
|
|
41
42
|
import { maillardReaction } from './tool/maillard-reaction-optimizer/entry';
|
|
42
|
-
|
|
43
|
+
import { macaronDrying } from './tool/macaron-drying-predictor/entry';
|
|
44
|
+
export const ALL_ENTRIES = [americanKitchenConverter, bananaCare, brine, cookwareGuide, eggTimer, ingredientRescaler, kitchenTimer, meringuePeak, moldScaler, pizza, rouxGuide, sourdoughCalculator, yeastConverter, lactoFermentationSalt, spherificationBath, iceCreamPacPod, botulismCanningSafety, meatBinder, carryOverCooking, maillardReaction, macaronDrying];
|
|
43
45
|
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { BOTULISM_CANNING_SAFETY_TOOL } from './tool/botulism-canning-safety';
|
|
|
21
21
|
export { MEAT_BINDER_TRANSGLUTAMINASE_TOOL } from './tool/meat-binder-transglutaminase-calculator';
|
|
22
22
|
export { CARRY_OVER_COOKING_TOOL } from './tool/carry-over-cooking-predictor';
|
|
23
23
|
export { MAILLARD_REACTION_TOOL } from './tool/maillard-reaction-optimizer';
|
|
24
|
+
export { MACARON_DRYING_TOOL } from './tool/macaron-drying-predictor';
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
export type {
|
|
@@ -36,7 +36,7 @@ describe("i18n titles for FAQ", () => {
|
|
|
36
36
|
|
|
37
37
|
it("should have 17 tools with complete i18n setup", async () => {
|
|
38
38
|
const completeTools = ALL_TOOLS.filter((t) => Object.keys(t.entry.i18n).length > 1);
|
|
39
|
-
expect(completeTools.length).toBe(
|
|
39
|
+
expect(completeTools.length).toBe(21);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it("tool IDs should be correctly registered", () => {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const bibliography = [
|
|
2
|
+
{
|
|
3
|
+
name: 'Les Petits Macarons: Colorful French Confections to Make at Home - Kathryn Gordon, Anne E. McBride',
|
|
4
|
+
url: 'https://www.scribd.com/document/484527225/Les-Petits-Macarons-Colorful-French-Confections-to-Make-at-Home-PDFDrive-pdf',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
name: 'Macarons: The definitive guide to mastering the basics',
|
|
8
|
+
url: 'https://michellesmacarons.com/french-macaron-recipe/',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'The Science Behind Macarons',
|
|
12
|
+
url: 'https://docmacaron.com/492/science-behind-macarons/',
|
|
13
|
+
},
|
|
14
|
+
];
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
ui: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { ui } = Astro.props;
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<div class="md">
|
|
10
|
+
<div class="md-card">
|
|
11
|
+
<div class="md-unit-row">
|
|
12
|
+
<button type="button" id="md-unit-metric" class="md-unit-btn active">Metric</button>
|
|
13
|
+
<button type="button" id="md-unit-imperial" class="md-unit-btn">Imperial</button>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="md-body">
|
|
16
|
+
<div class="md-controls">
|
|
17
|
+
<div class="md-input-row">
|
|
18
|
+
<div class="md-input-group">
|
|
19
|
+
<label class="md-label" for="md-humidity">{ui.humidityLabel}</label>
|
|
20
|
+
<div class="md-slider-wrap">
|
|
21
|
+
<input type="range" id="md-humidity" class="md-slider" min="20" max="90" value="50" />
|
|
22
|
+
<span class="md-value"><span id="md-humidity-val">50</span><span class="md-unit">{ui.humidityUnit}</span></span>
|
|
23
|
+
</div>
|
|
24
|
+
<span id="md-humidity-tag" class="md-tag md-tag-humid-normal">{ui.humidityTagNormal}</span>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="md-input-row">
|
|
28
|
+
<div class="md-input-group">
|
|
29
|
+
<label class="md-label" for="md-temp">{ui.tempLabel}</label>
|
|
30
|
+
<div class="md-slider-wrap">
|
|
31
|
+
<input type="range" id="md-temp" class="md-slider" min="15" max="35" value="22" />
|
|
32
|
+
<span class="md-value"><span id="md-temp-val">22</span><span class="md-unit" id="md-temp-unit">{ui.tempUnit}</span></span>
|
|
33
|
+
</div>
|
|
34
|
+
<span id="md-temp-tag" class="md-tag md-tag-temp-ideal">{ui.tempTagIdeal}</span>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="md-input-row">
|
|
38
|
+
<div class="md-input-group">
|
|
39
|
+
<label class="md-label" for="md-size">{ui.sizeLabel}</label>
|
|
40
|
+
<div class="md-slider-wrap">
|
|
41
|
+
<input type="range" id="md-size" class="md-slider" min="2" max="6" step="0.5" value="3" />
|
|
42
|
+
<span class="md-value"><span id="md-size-val">3</span><span class="md-unit" id="md-size-unit">{ui.sizeUnit}</span></span>
|
|
43
|
+
</div>
|
|
44
|
+
<span id="md-size-tag" class="md-tag md-tag-size-standard">{ui.sizeTagStandard}</span>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="md-result" id="md-result">
|
|
50
|
+
<div class="md-macaron-visual">
|
|
51
|
+
<svg viewBox="0 0 200 160" class="md-macaron-svg">
|
|
52
|
+
<defs>
|
|
53
|
+
<radialGradient id="md-shell-top" cx="50%" cy="40%" r="50%">
|
|
54
|
+
<stop offset="0%" stop-color="#f9a8d4" />
|
|
55
|
+
<stop offset="100%" stop-color="#ec4899" />
|
|
56
|
+
</radialGradient>
|
|
57
|
+
<radialGradient id="md-shell-top-dry" cx="50%" cy="40%" r="50%">
|
|
58
|
+
<stop offset="0%" stop-color="#fce7f3" />
|
|
59
|
+
<stop offset="100%" stop-color="#f9a8d4" />
|
|
60
|
+
</radialGradient>
|
|
61
|
+
<radialGradient id="md-shell-top-overdry" cx="50%" cy="40%" r="50%">
|
|
62
|
+
<stop offset="0%" stop-color="#f1f5f9" />
|
|
63
|
+
<stop offset="100%" stop-color="#e2e8f0" />
|
|
64
|
+
</radialGradient>
|
|
65
|
+
<filter id="md-shell-glow">
|
|
66
|
+
<feGaussianBlur stdDeviation="3" result="blur" />
|
|
67
|
+
<feMerge><feMergeNode in="blur" /><feMergeNode in="SourceGraphic" /></feMerge>
|
|
68
|
+
</filter>
|
|
69
|
+
</defs>
|
|
70
|
+
<ellipse id="md-shell-bottom" cx="100" cy="100" rx="70" ry="22" fill="#be185d" />
|
|
71
|
+
<ellipse id="md-shell-bottom-inner" cx="100" cy="96" rx="60" ry="16" fill="#fce7f3" />
|
|
72
|
+
<rect id="md-shell-feet" x="25" y="88" width="150" height="14" rx="7" fill="#9d174d" opacity="0.3" />
|
|
73
|
+
<ellipse id="md-shell-top" cx="100" cy="68" rx="65" ry="36" fill="url(#md-shell-top)" filter="url(#md-shell-glow)" />
|
|
74
|
+
<text id="md-minutes-display" x="100" y="74" text-anchor="middle" class="md-macaron-minutes">30</text>
|
|
75
|
+
<text x="100" y="92" text-anchor="middle" class="md-macaron-unit">{ui.minutesUnit}</text>
|
|
76
|
+
</svg>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="md-stats-row">
|
|
80
|
+
<div class="md-stat">
|
|
81
|
+
<span class="md-stat-label">{ui.readinessLabel}</span>
|
|
82
|
+
<span id="md-readiness-val" class="md-stat-value">75%</span>
|
|
83
|
+
</div>
|
|
84
|
+
<div id="md-skin-badge" class="md-skin-badge ready">{ui.skinStatusReady}</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div id="md-humidity-desc" class="md-info-card"></div>
|
|
88
|
+
<div id="md-humidity-note" class="md-info-note"></div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div class="md-footer" id="md-footer">
|
|
93
|
+
<div class="md-footer-row">
|
|
94
|
+
<div class="md-footer-chip md-footer-chip-time">
|
|
95
|
+
<svg width="16" height="16" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/><polyline points="12,6 12,12 16,14" fill="none" stroke="currentColor" stroke-width="2"/></svg>
|
|
96
|
+
<span id="md-footer-time">30 min</span>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="md-footer-chip md-footer-chip-humidity">
|
|
99
|
+
<svg width="16" height="16" viewBox="0 0 24 24"><path d="M12 2C12 2 4 12 4 16a8 8 0 0 0 16 0C20 12 12 2 12 2z" fill="currentColor"/></svg>
|
|
100
|
+
<span id="md-footer-humidity">50%</span>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="md-footer-chip md-footer-chip-temp">
|
|
103
|
+
<svg width="16" height="16" viewBox="0 0 24 24"><path d="M12 2v6a4 4 0 1 0 0 8v6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
|
104
|
+
<span id="md-footer-temp">22°C</span>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="md-footer-chip md-footer-chip-size">
|
|
107
|
+
<svg width="16" height="16" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3" fill="currentColor"/><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
|
|
108
|
+
<span id="md-footer-size">3cm</span>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<script is:inline define:vars={{ ui }}>
|
|
116
|
+
const $ = (id) => document.getElementById(id);
|
|
117
|
+
|
|
118
|
+
const humidity = $('md-humidity');
|
|
119
|
+
const temp = $('md-temp');
|
|
120
|
+
const size = $('md-size');
|
|
121
|
+
const hVal = $('md-humidity-val');
|
|
122
|
+
const tVal = $('md-temp-val');
|
|
123
|
+
const sVal = $('md-size-val');
|
|
124
|
+
const hTag = $('md-humidity-tag');
|
|
125
|
+
const tTag = $('md-temp-tag');
|
|
126
|
+
const sTag = $('md-size-tag');
|
|
127
|
+
const result = $('md-result');
|
|
128
|
+
const minutesDisp = $('md-minutes-display');
|
|
129
|
+
const readinessVal = $('md-readiness-val');
|
|
130
|
+
const skinBadge = $('md-skin-badge');
|
|
131
|
+
const humidityDesc = $('md-humidity-desc');
|
|
132
|
+
const humidityNote = $('md-humidity-note');
|
|
133
|
+
const footerTime = $('md-footer-time');
|
|
134
|
+
const footerHumidity = $('md-footer-humidity');
|
|
135
|
+
const footerTemp = $('md-footer-temp');
|
|
136
|
+
const footerSize = $('md-footer-size');
|
|
137
|
+
const footer = $('md-footer');
|
|
138
|
+
const shellTop = $('md-shell-top');
|
|
139
|
+
const unitMetric = $('md-unit-metric');
|
|
140
|
+
const unitImperial = $('md-unit-imperial');
|
|
141
|
+
const tUnit = $('md-temp-unit');
|
|
142
|
+
const sUnit = $('md-size-unit');
|
|
143
|
+
|
|
144
|
+
let unit = 'metric';
|
|
145
|
+
|
|
146
|
+
function cToF(c) { return c * 9/5 + 32; }
|
|
147
|
+
function fToC(f) { return (f - 32) * 5/9; }
|
|
148
|
+
function cmToIn(cm) { return cm / 2.54; }
|
|
149
|
+
function inToCm(inch) { return inch * 2.54; }
|
|
150
|
+
|
|
151
|
+
function getTempUnit() { return unit === 'imperial' ? ui.tempUnitF : ui.tempUnit; }
|
|
152
|
+
function getSizeUnit() { return unit === 'imperial' ? ui.sizeUnitIn : ui.sizeUnit; }
|
|
153
|
+
|
|
154
|
+
function setTempBounds(isImp) {
|
|
155
|
+
temp.setAttribute('min', isImp ? '59' : '15');
|
|
156
|
+
temp.setAttribute('max', isImp ? '95' : '35');
|
|
157
|
+
temp.setAttribute('step', '1');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function setSizeBounds(isImp) {
|
|
161
|
+
size.setAttribute('min', isImp ? '0.8' : '2');
|
|
162
|
+
size.setAttribute('max', isImp ? '2.4' : '6');
|
|
163
|
+
size.setAttribute('step', isImp ? '0.2' : '0.5');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function switchUnit(to) {
|
|
167
|
+
if (unit === to) return;
|
|
168
|
+
const tv = parseInt(temp.value) || 22;
|
|
169
|
+
const sv = parseFloat(size.value) || 3;
|
|
170
|
+
unit = to;
|
|
171
|
+
unitMetric.classList.toggle('active', to === 'metric');
|
|
172
|
+
unitImperial.classList.toggle('active', to === 'imperial');
|
|
173
|
+
|
|
174
|
+
const isImp = to === 'imperial';
|
|
175
|
+
setTempBounds(isImp);
|
|
176
|
+
setSizeBounds(isImp);
|
|
177
|
+
temp.value = isImp ? Math.round(cToF(tv)).toString() : tv.toString();
|
|
178
|
+
size.value = isImp ? cmToIn(sv).toFixed(1) : sv.toString();
|
|
179
|
+
|
|
180
|
+
tUnit.textContent = getTempUnit();
|
|
181
|
+
sUnit.textContent = getSizeUnit();
|
|
182
|
+
refresh();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getTempC() {
|
|
186
|
+
const tv = parseInt(temp.value) || 22;
|
|
187
|
+
return unit === 'imperial' ? fToC(tv) : tv;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getSizeCm() {
|
|
191
|
+
const sv = parseFloat(size.value) || 3;
|
|
192
|
+
return unit === 'imperial' ? inToCm(sv) : sv;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function formatTemp(tc) { return unit === 'imperial' ? Math.round(cToF(tc)).toString() : tc.toString(); }
|
|
196
|
+
function formatSize(sc) { return unit === 'imperial' ? cmToIn(sc).toFixed(1) : sc.toString(); }
|
|
197
|
+
|
|
198
|
+
function updateHumidityTag(hv) {
|
|
199
|
+
if (hv >= 65) {
|
|
200
|
+
hTag.textContent = ui.humidityTagHigh; hTag.className = 'md-tag md-tag-humid-high';
|
|
201
|
+
humidityDesc.className = 'md-info-card md-info-high';
|
|
202
|
+
humidityDesc.innerHTML = '<svg class="md-info-svg" viewBox="0 0 24 24"><path d="M12 2C12 2 4 12 4 16a8 8 0 0 0 16 0C20 12 12 2 12 2z" fill="currentColor"/><path d="M12 6v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg><span>' + ui.humidityDescHigh + '</span>';
|
|
203
|
+
} else if (hv <= 35) {
|
|
204
|
+
hTag.textContent = ui.humidityTagLow; hTag.className = 'md-tag md-tag-humid-low';
|
|
205
|
+
humidityDesc.className = 'md-info-card md-info-low';
|
|
206
|
+
humidityDesc.innerHTML = '<svg class="md-info-svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="5" fill="currentColor"/><g stroke="currentColor" stroke-width="1.5"><line x1="12" y1="1" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="23"/><line x1="1" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="23" y2="12"/><line x1="4.2" y1="4.2" x2="6.3" y2="6.3"/><line x1="17.7" y1="17.7" x2="19.8" y2="19.8"/><line x1="4.2" y1="19.8" x2="6.3" y2="17.7"/><line x1="17.7" y1="6.3" x2="19.8" y2="4.2"/></g></svg><span>' + ui.humidityDescLow + '</span>';
|
|
207
|
+
} else {
|
|
208
|
+
hTag.textContent = ui.humidityTagNormal; hTag.className = 'md-tag md-tag-humid-normal';
|
|
209
|
+
humidityDesc.className = 'md-info-card md-info-ok';
|
|
210
|
+
humidityDesc.innerHTML = '<svg class="md-info-svg" viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg><span>' + ui.humidityDescNormal + '</span>';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function updateTempTag(tv) {
|
|
215
|
+
if (tv >= 28) { tTag.textContent = ui.tempTagHot; tTag.className = 'md-tag md-tag-temp-hot'; }
|
|
216
|
+
else if (tv <= 18) { tTag.textContent = ui.tempTagCool; tTag.className = 'md-tag md-tag-temp-cool'; }
|
|
217
|
+
else { tTag.textContent = ui.tempTagIdeal; tTag.className = 'md-tag md-tag-temp-ideal'; }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function updateSizeTag(sv) {
|
|
221
|
+
if (sv <= 2.5) { sTag.textContent = ui.sizeTagMini; sTag.className = 'md-tag md-tag-size-mini'; }
|
|
222
|
+
else if (sv >= 4.5) { sTag.textContent = ui.sizeTagLarge; sTag.className = 'md-tag md-tag-size-large'; }
|
|
223
|
+
else { sTag.textContent = ui.sizeTagStandard; sTag.className = 'md-tag md-tag-size-standard'; }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function updateTags() {
|
|
227
|
+
const hv = parseInt(humidity.value);
|
|
228
|
+
const tv = parseInt(temp.value);
|
|
229
|
+
const sv = parseFloat(size.value);
|
|
230
|
+
hVal.textContent = hv.toString();
|
|
231
|
+
tVal.textContent = tv.toString();
|
|
232
|
+
sVal.textContent = sv.toString();
|
|
233
|
+
updateHumidityTag(hv);
|
|
234
|
+
updateTempTag(tv);
|
|
235
|
+
updateSizeTag(sv);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function updateSkinBadge(readiness) {
|
|
239
|
+
readinessVal.textContent = readiness + '%';
|
|
240
|
+
if (readiness >= 90) {
|
|
241
|
+
readinessVal.style.color = 'var(--md-green)';
|
|
242
|
+
skinBadge.textContent = ui.skinStatusReady;
|
|
243
|
+
skinBadge.className = 'md-skin-badge ready';
|
|
244
|
+
shellTop.setAttribute('fill', 'url(#md-shell-top)');
|
|
245
|
+
} else if (readiness >= 60) {
|
|
246
|
+
readinessVal.style.color = 'var(--md-amber)';
|
|
247
|
+
skinBadge.textContent = ui.skinStatusForming;
|
|
248
|
+
skinBadge.className = 'md-skin-badge forming';
|
|
249
|
+
shellTop.setAttribute('fill', 'url(#md-shell-top-dry)');
|
|
250
|
+
} else if (readiness >= 20) {
|
|
251
|
+
readinessVal.style.color = 'var(--md-pink)';
|
|
252
|
+
skinBadge.textContent = ui.skinStatusSticky;
|
|
253
|
+
skinBadge.className = 'md-skin-badge sticky';
|
|
254
|
+
shellTop.setAttribute('fill', 'url(#md-shell-top)');
|
|
255
|
+
} else {
|
|
256
|
+
readinessVal.style.color = 'var(--md-gray)';
|
|
257
|
+
skinBadge.textContent = ui.skinStatusOverDry;
|
|
258
|
+
skinBadge.className = 'md-skin-badge over-dry';
|
|
259
|
+
shellTop.setAttribute('fill', 'url(#md-shell-top-overdry)');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function compute() {
|
|
264
|
+
const hv = parseInt(humidity.value);
|
|
265
|
+
const tc = getTempC();
|
|
266
|
+
const sc = getSizeCm();
|
|
267
|
+
const hc = Math.max(20, Math.min(90, hv));
|
|
268
|
+
const tcc = Math.max(15, Math.min(35, tc));
|
|
269
|
+
const dcc = Math.max(2, Math.min(6, sc));
|
|
270
|
+
|
|
271
|
+
const hf = 1 + Math.pow((hc - 30) / 30, 2) * 2;
|
|
272
|
+
const tf = 1 + (25 - tcc) * 0.04;
|
|
273
|
+
const sf = Math.pow(dcc / 3, 1.5);
|
|
274
|
+
const minutes = Math.round(30 * hf * tf * sf);
|
|
275
|
+
const readiness = Math.max(0, Math.min(100, Math.round(100 - (hf - 1) * 50 - (tf - 1) * 30)));
|
|
276
|
+
|
|
277
|
+
minutesDisp.textContent = minutes.toString();
|
|
278
|
+
updateSkinBadge(readiness);
|
|
279
|
+
humidityNote.textContent = Math.round(hf * 100) / 100 !== 1 ? hf.toFixed(1) + 'x factor' : '';
|
|
280
|
+
|
|
281
|
+
footerTime.textContent = minutes + ' ' + ui.minutesUnit;
|
|
282
|
+
footerHumidity.textContent = hv + ui.humidityUnit;
|
|
283
|
+
footerTemp.textContent = formatTemp(tc) + getTempUnit();
|
|
284
|
+
footerSize.textContent = formatSize(sc) + ' ' + getSizeUnit();
|
|
285
|
+
footer.style.display = 'flex';
|
|
286
|
+
result.style.display = 'flex';
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const STORAGE_KEY = 'md-v1';
|
|
290
|
+
|
|
291
|
+
function save() {
|
|
292
|
+
try {
|
|
293
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({ h: humidity.value, t: temp.value, s: size.value, u: unit }));
|
|
294
|
+
} catch {}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function load() {
|
|
298
|
+
try {
|
|
299
|
+
const d = localStorage.getItem(STORAGE_KEY);
|
|
300
|
+
if (!d) return;
|
|
301
|
+
const v = JSON.parse(d);
|
|
302
|
+
if (v.u === 'imperial') switchUnit('imperial');
|
|
303
|
+
if (v.h) humidity.value = v.h;
|
|
304
|
+
if (v.t) temp.value = v.t;
|
|
305
|
+
if (v.s) size.value = v.s;
|
|
306
|
+
} catch {}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function refresh() { updateTags(); compute(); save(); }
|
|
310
|
+
|
|
311
|
+
unitMetric.addEventListener('click', function() { switchUnit('metric'); });
|
|
312
|
+
unitImperial.addEventListener('click', function() { switchUnit('imperial'); });
|
|
313
|
+
humidity.addEventListener('input', refresh);
|
|
314
|
+
temp.addEventListener('input', refresh);
|
|
315
|
+
size.addEventListener('input', refresh);
|
|
316
|
+
|
|
317
|
+
load();
|
|
318
|
+
refresh();
|
|
319
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CookingToolEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const macaronDrying: CookingToolEntry = {
|
|
4
|
+
id: 'macaron-drying-predictor',
|
|
5
|
+
icons: {
|
|
6
|
+
bg: 'mdi:circle-slice-8',
|
|
7
|
+
fg: 'mdi:weather-windy',
|
|
8
|
+
},
|
|
9
|
+
i18n: {
|
|
10
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
11
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
12
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
13
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
14
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
15
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
16
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
17
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
18
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
19
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
20
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
21
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
22
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
23
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
24
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
25
|
+
},
|
|
26
|
+
};
|