Skip to content

Commit 0f0b42b

Browse files
authored
Add serving time input to cooking timer (#186)
> Modify cooking-timer.html to add a new feature: set desired serving time. This feature is available when the Start Cooking visible is shown. Clicking it brings up a input type=time that lets the user set the desired serving time for the meal. Once a serving time has been selected treat it as if the start cooking button has been clicked, update all times on the page to the time they need to be done in order to meet that serving time, then run the timer as normal. Allows users to set a desired serving time instead of starting immediately. The timer calculates when to start each step to meet the target time, showing a countdown until cooking begins and displaying correct clock times in the timeline. https://gistpreview.github.io/?fc5236c585ebfc7dd7748e9173ed6ac2/index.html
1 parent 2c6bad5 commit 0f0b42b

File tree

1 file changed

+167
-3
lines changed

1 file changed

+167
-3
lines changed

cooking-timer.html

Lines changed: 167 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,91 @@
393393
flex-wrap: wrap;
394394
}
395395

396+
.serving-time-container {
397+
margin-top: 16px;
398+
}
399+
400+
.serving-time-btn {
401+
background: transparent;
402+
border: 2px solid rgba(255,255,255,0.5);
403+
color: #fff;
404+
padding: 10px 24px;
405+
border-radius: 25px;
406+
cursor: pointer;
407+
font-size: 0.9rem;
408+
transition: border-color 0.2s, background 0.2s;
409+
}
410+
411+
.serving-time-btn:hover {
412+
border-color: #fff;
413+
background: rgba(255,255,255,0.1);
414+
}
415+
416+
.serving-time-input-wrapper {
417+
display: flex;
418+
align-items: center;
419+
justify-content: center;
420+
gap: 12px;
421+
background: rgba(0,0,0,0.2);
422+
padding: 12px 16px;
423+
border-radius: 12px;
424+
}
425+
426+
.serving-time-input-wrapper label {
427+
font-size: 0.9rem;
428+
opacity: 0.9;
429+
}
430+
431+
.serving-time-input-wrapper input[type="time"] {
432+
padding: 8px 12px;
433+
border: 2px solid rgba(255,255,255,0.3);
434+
border-radius: 8px;
435+
background: rgba(255,255,255,0.1);
436+
color: #fff;
437+
font-size: 1.1rem;
438+
font-weight: 600;
439+
}
440+
441+
.serving-time-input-wrapper input[type="time"]:focus {
442+
outline: none;
443+
border-color: #fff;
444+
}
445+
446+
.serving-time-set {
447+
background: linear-gradient(135deg, #00b894 0%, #00cec9 100%);
448+
border: none;
449+
color: #fff;
450+
padding: 8px 16px;
451+
border-radius: 6px;
452+
cursor: pointer;
453+
font-size: 0.9rem;
454+
font-weight: 600;
455+
transition: transform 0.2s, box-shadow 0.2s;
456+
}
457+
458+
.serving-time-set:hover {
459+
transform: scale(1.05);
460+
box-shadow: 0 2px 10px rgba(0, 184, 148, 0.3);
461+
}
462+
463+
.serving-time-cancel {
464+
background: transparent;
465+
border: none;
466+
color: #fff;
467+
font-size: 1.4rem;
468+
cursor: pointer;
469+
opacity: 0.6;
470+
padding: 4px 8px;
471+
}
472+
473+
.serving-time-cancel:hover {
474+
opacity: 1;
475+
}
476+
477+
.elapsed-label.countdown {
478+
color: #f39c12;
479+
}
480+
396481
.current-step {
397482
background: linear-gradient(135deg, #00b894 0%, #00cec9 100%);
398483
border-radius: 16px;
@@ -680,9 +765,18 @@ <h1 id="recipeName">Cooking Timer</h1>
680765

681766
<div class="start-section" id="startSection">
682767
<button class="start-btn" id="startBtn" onclick="startCooking()">START COOKING</button>
768+
<div class="serving-time-container" id="servingTimeContainer">
769+
<button class="serving-time-btn" id="servingTimeBtn" onclick="showServingTimeInput()">Set Serving Time</button>
770+
<div class="serving-time-input-wrapper hidden" id="servingTimeInputWrapper">
771+
<label for="servingTimeInput">Serve at:</label>
772+
<input type="time" id="servingTimeInput">
773+
<button class="serving-time-set" onclick="onServingTimeSelected()">Set</button>
774+
<button class="serving-time-cancel" onclick="hideServingTimeInput()">×</button>
775+
</div>
776+
</div>
683777
<div class="hidden" id="timerDisplay">
684778
<div class="elapsed-time" id="elapsedTime">00:00</div>
685-
<div class="elapsed-label">Elapsed Time</div>
779+
<div class="elapsed-label" id="elapsedLabel">Elapsed Time</div>
686780
<div class="timer-controls">
687781
<button class="reset-btn" onclick="resetTimer()">Reset Timer</button>
688782
</div>
@@ -1301,6 +1395,9 @@ <h2>Full Timeline</h2>
13011395

13021396
// Reset timer display
13031397
document.getElementById('startBtn').classList.remove('hidden');
1398+
document.getElementById('servingTimeContainer').classList.remove('hidden');
1399+
document.getElementById('servingTimeBtn').classList.remove('hidden');
1400+
document.getElementById('servingTimeInputWrapper').classList.add('hidden');
13041401
document.getElementById('timerDisplay').classList.add('hidden');
13051402
document.getElementById('startSection').classList.remove('running');
13061403
document.getElementById('currentStepSection').classList.add('hidden');
@@ -1331,8 +1428,58 @@ <h2>Full Timeline</h2>
13311428
startTimer();
13321429
}
13331430

1431+
function showServingTimeInput() {
1432+
document.getElementById('servingTimeBtn').classList.add('hidden');
1433+
document.getElementById('servingTimeInputWrapper').classList.remove('hidden');
1434+
1435+
// Set default value to a reasonable time (1 hour from now, rounded to nearest 5 min)
1436+
const now = new Date();
1437+
const steps = isMultiRecipeMode ? mergedSteps : currentRecipe.steps;
1438+
const lastStepTime = steps[steps.length - 1].time;
1439+
const suggestedServing = new Date(now.getTime() + lastStepTime * 1000 + 5 * 60 * 1000);
1440+
1441+
// Round to nearest 5 minutes
1442+
suggestedServing.setMinutes(Math.ceil(suggestedServing.getMinutes() / 5) * 5);
1443+
suggestedServing.setSeconds(0);
1444+
1445+
const hours = suggestedServing.getHours().toString().padStart(2, '0');
1446+
const mins = suggestedServing.getMinutes().toString().padStart(2, '0');
1447+
document.getElementById('servingTimeInput').value = `${hours}:${mins}`;
1448+
}
1449+
1450+
function hideServingTimeInput() {
1451+
document.getElementById('servingTimeBtn').classList.remove('hidden');
1452+
document.getElementById('servingTimeInputWrapper').classList.add('hidden');
1453+
}
1454+
1455+
function onServingTimeSelected() {
1456+
const timeInput = document.getElementById('servingTimeInput').value;
1457+
if (!timeInput) return;
1458+
1459+
const [hours, minutes] = timeInput.split(':').map(Number);
1460+
const steps = isMultiRecipeMode ? mergedSteps : currentRecipe.steps;
1461+
const lastStepTime = steps[steps.length - 1].time;
1462+
1463+
// Create the serving time for today
1464+
const now = new Date();
1465+
let servingTime = new Date(now);
1466+
servingTime.setHours(hours, minutes, 0, 0);
1467+
1468+
// If the serving time is in the past, assume it's for tomorrow
1469+
if (servingTime.getTime() < now.getTime()) {
1470+
servingTime.setDate(servingTime.getDate() + 1);
1471+
}
1472+
1473+
// Calculate the start time by subtracting the total cooking time
1474+
startTime = servingTime.getTime() - (lastStepTime * 1000);
1475+
1476+
saveTimerState();
1477+
startTimer();
1478+
}
1479+
13341480
function startTimer() {
13351481
document.getElementById('startBtn').classList.add('hidden');
1482+
document.getElementById('servingTimeContainer').classList.add('hidden');
13361483
document.getElementById('timerDisplay').classList.remove('hidden');
13371484
document.getElementById('startSection').classList.add('running');
13381485
document.getElementById('notStartedMsg').classList.add('hidden');
@@ -1348,6 +1495,9 @@ <h2>Full Timeline</h2>
13481495
saveTimerState();
13491496

13501497
document.getElementById('startBtn').classList.remove('hidden');
1498+
document.getElementById('servingTimeContainer').classList.remove('hidden');
1499+
document.getElementById('servingTimeBtn').classList.remove('hidden');
1500+
document.getElementById('servingTimeInputWrapper').classList.add('hidden');
13511501
document.getElementById('timerDisplay').classList.add('hidden');
13521502
document.getElementById('startSection').classList.remove('running');
13531503
document.getElementById('currentStepSection').classList.add('hidden');
@@ -1382,7 +1532,18 @@ <h2>Full Timeline</h2>
13821532
function updateDisplay() {
13831533
const steps = isMultiRecipeMode ? mergedSteps : currentRecipe.steps;
13841534
const elapsed = Math.floor((Date.now() - startTime) / 1000);
1385-
document.getElementById('elapsedTime').textContent = formatTimeWithHours(elapsed);
1535+
const elapsedLabel = document.getElementById('elapsedLabel');
1536+
1537+
// Handle negative elapsed time (waiting to start based on serving time)
1538+
if (elapsed < 0) {
1539+
document.getElementById('elapsedTime').textContent = formatTimeWithHours(Math.abs(elapsed));
1540+
elapsedLabel.textContent = 'Starts in';
1541+
elapsedLabel.classList.add('countdown');
1542+
} else {
1543+
document.getElementById('elapsedTime').textContent = formatTimeWithHours(elapsed);
1544+
elapsedLabel.textContent = 'Elapsed Time';
1545+
elapsedLabel.classList.remove('countdown');
1546+
}
13861547

13871548
// Find current and upcoming steps
13881549
let currentStep = null;
@@ -1403,7 +1564,7 @@ <h2>Full Timeline</h2>
14031564
}
14041565

14051566
// If no "just started" step, find the most recent active step
1406-
if (!currentStep) {
1567+
if (!currentStep && elapsed >= 0) {
14071568
for (let i = steps.length - 1; i >= 0; i--) {
14081569
if (steps[i].time <= elapsed) {
14091570
currentStep = steps[i];
@@ -1439,6 +1600,9 @@ <h2>Full Timeline</h2>
14391600
categoryEl.style.display = currentStep.category ? 'inline-block' : 'none';
14401601
categoryEl.style.background = 'rgba(0,0,0,0.2)';
14411602
}
1603+
} else {
1604+
// Hide current step section when waiting to start or between steps
1605+
document.getElementById('currentStepSection').classList.add('hidden');
14421606
}
14431607

14441608
// Update upcoming steps

0 commit comments

Comments
 (0)