Skip to content

Add multi-recipe cooking timer feature#185

Merged
simonw merged 1 commit intomainfrom
claude/multi-recipe-timer-iw7Ee
Dec 27, 2025
Merged

Add multi-recipe cooking timer feature#185
simonw merged 1 commit intomainfrom
claude/multi-recipe-timer-iw7Ee

Conversation

@simonw
Copy link
Owner

@simonw simonw commented Dec 27, 2025

Modify cooking-timer.html

A major feature of blackened-cauliflower-and-turkish-style-stew.html was that it helped cook two recipes at the same time

Since cooking-timer.html has a feature that can display previous recipes we have a good starting point for adding that feauter

Add checkboxes to the previous recipes and a button for "Cook these at the same time". Make sure that once that option has been selected the URL state updates to reflect the recipes that have been cooked. As before, the start time should be saved in localStorage (and the URL bits too) such that if you come back to the page the state can be resumed automatically - skipping the initial screen unless you hit the "Choose different recipe" reset button

  • Add checkboxes to the Previous Recipes list for selecting multiple recipes
  • Add "Cook these at the same time" button that appears when 2+ recipes exist
  • Merge steps from selected recipes into a combined timeline sorted by time
  • Color-code recipe tags to distinguish steps from different recipes
  • Update URL state to reflect selected recipes (?recipes=id1,id2,...)
  • Persist multi-recipe session state in localStorage for auto-resume
  • Show recipe badges in header during multi-recipe cooking sessions
  • Reset button properly clears multi-recipe state and returns to setup screen

https://gistpreview.github.io/?24075b22aa8f33f5e4c1dfa3a647b2e8

- Add checkboxes to the Previous Recipes list for selecting multiple recipes
- Add "Cook these at the same time" button that appears when 2+ recipes exist
- Merge steps from selected recipes into a combined timeline sorted by time
- Color-code recipe tags to distinguish steps from different recipes
- Update URL state to reflect selected recipes (?recipes=id1,id2,...)
- Persist multi-recipe session state in localStorage for auto-resume
- Show recipe badges in header during multi-recipe cooking sessions
- Reset button properly clears multi-recipe state and returns to setup screen
@claude
Copy link
Contributor

claude bot commented Dec 27, 2025

Claude finished @simonw's task —— View job


Code Review of Multi-Recipe Cooking Timer

I've completed a thorough review of the multi-recipe cooking timer implementation. Here's my detailed feedback:

Todo List

  • Read and analyze the modified cooking-timer.html file
  • Review code quality and best practices
  • Check for potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide comprehensive feedback

✅ Code Quality and Best Practices

Strengths:

  • Clean Architecture: Well-organized separation between single-recipe and multi-recipe modes
  • Good UI/UX: Intuitive checkbox selection, visual feedback with color-coding, and clear multi-recipe indicators
  • Consistent Styling: Good use of CSS custom properties and consistent design patterns
  • Accessibility: Proper use of semantic HTML and ARIA-friendly elements

Areas for Improvement:

  • Function Size: Some functions are quite large (e.g., init(), renderSavedRecipes()) and could be broken down
  • Magic Numbers: Constants like 20 (recipe limit) and 60 seconds (step completion threshold) should be defined as named constants
  • Code Duplication: Timeline rendering logic is duplicated between single and multi-recipe modes

⚠️ Potential Bugs and Issues

Critical Issues:

  1. Race Condition in URL fetching (lines 1080-1095): Multiple async fetch operations aren't properly synchronized, potentially causing state corruption if requests complete out of order
  2. Recipe ID collision (line 865): Using timestamp as ID could cause collisions if recipes are added rapidly
  3. Memory leak risk: Timer intervals aren't cleared in all error paths

Medium Issues:

  1. URL validation bypass (lines 978-983): Basic URL validation can be bypassed with malformed URLs that pass new URL() but fail to fetch
  2. Recipe limit not enforced (line 876): The 20-recipe limit trimming happens after storage, not before adding
  3. Inconsistent error handling: Some errors show in UI, others only log to console

Minor Issues:

  1. Missing null checks in mergeRecipeSteps() (line 1172) for recipe steps array
  2. HTML escaping inconsistency: Not all user input is consistently escaped (recipe details in timeline)

🚀 Performance Considerations

Good Practices:

  • Efficient DOM updates using innerHTML batching
  • Proper use of CSS transforms for animations
  • Minimal re-renders during timer updates

Optimization Opportunities:

  1. Timeline re-rendering (lines 1211, 1477): Full timeline HTML regeneration every second is expensive - could use selective updates
  2. localStorage operations: Multiple reads/writes of the same keys could be batched
  3. Recipe merging (line 1172): Could be optimized to avoid re-sorting on every merge

🔒 Security Concerns

Low-Risk Issues:

  1. XSS Prevention: Good use of escapeHtml() function, but not applied consistently everywhere
  2. CORS Limitations: External recipe URLs are subject to CORS policies - this is actually good for security
  3. localStorage Size: No size limits enforced, could lead to quota exhaustion

Recommendations:

  • Apply HTML escaping to all user-controlled content, especially in timeline details (line 1242)
  • Consider implementing Content Security Policy headers for additional XSS protection
  • Add size validation for recipe JSON to prevent localStorage abuse

🧪 Test Coverage

Missing Test Coverage:

  • No automated tests present
  • Complex multi-recipe merging logic is untested
  • Timer state persistence and recovery scenarios
  • Error handling paths (network failures, malformed JSON)
  • Cross-browser localStorage compatibility

Testing Recommendations:

  • Unit tests for recipe validation, merging, and state management
  • Integration tests for URL loading and multi-recipe workflows
  • End-to-end tests for timer functionality and persistence

🎯 Specific Code Improvements

High Priority:

// Line 865: Fix ID collision risk
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,

// Lines 1080-1095: Add proper error aggregation
const fetchPromises = urlsToFetch.map(async item => { /* ... */ });
const results = await Promise.allSettled(fetchPromises);
// Handle both successes and failures appropriately

Medium Priority:

// Add constants at top of script
const CONSTANTS = {
  MAX_RECIPES: 20,
  STEP_COMPLETION_THRESHOLD: 60,
  TIMER_UPDATE_INTERVAL: 1000,
  RECIPE_COLORS_COUNT: 6
};

// Line 1242: Fix HTML escaping
<div class="timeline-detail">${escapeHtml(step.detail || '')}</div>

📊 Overall Assessment

This is a solid implementation with good functionality and user experience. The multi-recipe feature is well-designed and the code is generally maintainable. The main concerns are around error handling robustness and some performance optimizations.

Recommendation: ✅ Approve with minor fixes

The implementation successfully delivers all requested features. Address the race condition in URL fetching and add consistent HTML escaping before merging.

--- | Branch: claude/multi-recipe-timer-iw7Ee

@simonw
Copy link
Owner Author

simonw commented Dec 27, 2025

Looks like it works!

CleanShot 2025-12-26 at 17 09 20@2x

@simonw simonw merged commit 904763d into main Dec 27, 2025
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants