Commit Graph

144 Commits

Author SHA1 Message Date
jbrechtel 65b096bc31 Landing page: use recipe images in cards, make cards clickable
Build and Deploy / build-and-deploy (push) Successful in 1m48s
- Card images now show the recipe's actual image when available
  (background-image: url(...) with background-size: contain to preserve
  aspect ratio without distortion), falling back to gradient placeholders
- Cards are now wrapped in <a href="/recipes/{filename}"> so clicking
  anywhere on a card navigates to the recipe page
- Added .contain CSS class for image-fit behavior and .lnd-card a for
  link styling
2026-05-26 07:43:04 -04:00
jbrechtel 162d2f8a1e Formats repo 2026-05-26 07:39:28 -04:00
jbrechtel 0643dda10d Update recipe view page layout to match roux-recipe-mockup.html
Build and Deploy / build-and-deploy (push) Failing after 1m40s
Layout changes:
- Nav matching landing page style (ROUX logo + Recipes + Cook History)
- Large serif title with inline editing preserved
- Subtitle from recipe description
- Meta strip: rounded background with last cook info + source link + Log meal button
- Full-width hero image with upload/replace overlay
- 2-column body grid (1.5fr ingredients+method | 1fr cook history rail)
- Flat ingredient list with quantities (no checkboxes)
- Numbered method paragraphs (no checkboxes, timers preserved)
- Cook history rail on right with + Add button
- Tags displayed below the grid
- Responsive: single column on mobile

Architecture:
- Removed: renderMetaBar, renderCookLog, renderRecentCookEntries,
  renderRecentEntry, renderEntry, renderIngredientGroup, renderIngredientRow,
  collectSectionIngredients, dedupFirst, renderMethodSections, renderMethodStep,
  isEmptyStep, isBlankText, isMethodSection, sectionMethodSteps,
  renderMarginalNote, collectNotes, bodyItemSteps, pairWith
- Added: recipePageStyles, rpHeroImage, rpLastCookInfo, formatFullDate,
  rpIngredientList, rpNamedIngredientSection, collectIngredients,
  rpIngredientItems, rpMethodList, rpRenderMethodStep, rpHistoryList,
  rpRenderHistoryEntry
- Updated cookLogJs to use .roux-record-trigger class for dual trigger buttons
- Removed unused imports (Data.Function, catMaybes)
- All hlint warnings fixed, 51 tests passing
2026-05-26 07:38:15 -04:00
jbrechtel 6a7374c912 Formatting
Build and Deploy / build-and-deploy (push) Successful in 14m49s
2026-05-26 07:25:18 -04:00
jbrechtel d22c8a79d4 Add landing page with cook log integration
Build and Deploy / build-and-deploy (push) Failing after 1m15s
- New landing page (/) based on roux-landing-mockup.html layout
  - Shuffle card that suggests random recipes
  - Recently cooked shelf (driven by cook log DB)
  - Recently added shelf (by file modification time)
- Existing recipe index moved to /recipes
- Updated nav links throughout to point to /recipes
- All hlint warnings fixed
2026-05-26 07:15:38 -04:00
jbrechtel edb682c8bc fix: skip empty/whitespace-only steps so step numbering starts at 1
Build and Deploy / build-and-deploy (push) Failing after 8s
2026-05-26 06:59:07 -04:00
jbrechtel 0be6e299d5 fix: normalize recipe filenames in cook-log (strip .cork ext, lowercase); also fetch with .cork fallback for legacy entries
Build and Deploy / build-and-deploy (push) Failing after 1m25s
2026-05-26 06:48:11 -04:00
jbrechtel 4dd580a042 Formats repo
Build and Deploy / build-and-deploy (push) Successful in 13m25s
2026-05-26 06:45:02 -04:00
jbrechtel ee42bfd981 fix: darken text colors — define --roux-muted, add explicit color to Cancel button, darken recent entry comment/date colors
Build and Deploy / build-and-deploy (push) Failing after 9s
2026-05-26 06:44:23 -04:00
jbrechtel 92ec058114 feat: show most recent 5 cook entries under Record meal button
Build and Deploy / build-and-deploy (push) Failing after 1m17s
2026-05-26 06:40:24 -04:00
jbrechtel 14f43a4ae9 fix: send URL-encoded form data instead of multipart, show errors inline, default empty date to today
Build and Deploy / build-and-deploy (push) Successful in 15m46s
2026-05-25 22:26:53 -04:00
jbrechtel 930fba369c feat: replace inline cook log form with 'Record meal' button + modal
Build and Deploy / build-and-deploy (push) Successful in 17m20s
2026-05-25 22:20:00 -04:00
jbrechtel ac7a979fe9 Formats repo
Build and Deploy / build-and-deploy (push) Successful in 15m3s
2026-05-25 22:11:28 -04:00
jbrechtel 0b6b9c3d17 fix: use Text for created_at, fix show-bug in ToJSON, add /cook-history route
Build and Deploy / build-and-deploy (push) Failing after 21s
2026-05-25 22:10:23 -04:00
jbrechtel 90971568a3 feat: add cook history nav link to index page 2026-05-25 22:01:24 -04:00
jbrechtel c6a9c2dee4 feat: wire up cook log DB at server startup 2026-05-25 22:00:45 -04:00
jbrechtel ceadf50c59 feat: add CookLog module with types and DB operations 2026-05-25 21:55:43 -04:00
jbrechtel 0b5fa61acd chore: add sqlite-simple dependency 2026-05-25 21:54:22 -04:00
jbrechtel edfa9bac76 docs: add implementation plan for cooking log feature 2026-05-25 21:48:51 -04:00
jbrechtel f2bd667b75 docs: add cooking log design spec 2026-05-25 21:45:49 -04:00
jbrechtel ed015d3799 Fix all 20 hlint warnings across 5 source files
Build and Deploy / build-and-deploy (push) Successful in 12m38s
- Use newtype instead of data for single-field types (RouxConfig, ImportError)
- Replace maybe "" id with fromMaybe "" throughout
- Replace not (x `elem` ys) with x `notElem` ys
- Remove redundant brackets, redundant $, and eta-reduce lookupRecipe
- Use numeric underscore for 1_000_000
2026-05-25 21:30:21 -04:00
jbrechtel 67c3b4df6c Merge branch 'feat/inline-title-edit'
Build and Deploy / build-and-deploy (push) Successful in 2m10s
2026-05-21 21:37:20 -04:00
jbrechtel 69f4184f2e feat: add PATCH endpoint for recipe title updates 2026-05-21 21:31:33 -04:00
jbrechtel 7b51c617de feat: add inline title editing JavaScript 2026-05-21 21:29:54 -04:00
jbrechtel e5ed706aa6 Updates prompt 2026-05-21 21:29:34 -04:00
jbrechtel 1f7b55af6f feat: add CSS class and styles for editable recipe title 2026-05-21 21:29:20 -04:00
jbrechtel 8e6e572b35 chore: add .worktrees to gitignore 2026-05-21 21:28:03 -04:00
jbrechtel 59fd96b57d docs: add design and plan for inline title editing 2026-05-21 21:28:00 -04:00
jbrechtel d64129fc9f fix: save recipe images to recipe-images/ subdirectory
Build and Deploy / build-and-deploy (push) Successful in 1m49s
Previously images were saved directly in the recipe directory
alongside .cook files. Now they go into <recipes-dir>/recipe-images/,
keeping the recipe directory clean and making the purpose of the
file clear from its path.
2026-05-21 21:06:07 -04:00
jbrechtel a509f44300 feat: add recipe image upload with in-place metadata update
Build and Deploy / build-and-deploy (push) Successful in 2m4s
Users can now upload an photo for any recipe directly from the
view page. The upload button appears as either a 'Replace' overlay
on existing images or an empty dashed placeholder for recipes
without one.

Upload flow:
1. Click upload button -> file picker opens (accepts image/*)
2. JavaScript reads the file as base64, POSTs to /upload-image
   with form fields: filename, file-b64, file-name
3. Server decodes the base64, saves to <recipe-dir>/<basename>.<ext>
4. Server updates the .cook file's YAML front matter, adding or
   updating the 'image:' key with a /recipe-images/ URL
5. Server returns JSON success, page reloads to show the image

Server routes added:
- POST /upload-image  — accepts base64-encoded image upload
- GET /recipe-images/<filename> — serves saved recipe images
  (extension-whitelisted to .jpg/.jpeg/.png/.gif/.webp)

Image files are stored alongside .cook files in the recipe directory
and served via the /recipe-images/ path. The fsnotify watcher detects
the .cook metadata change and triggers an SSE reload.
2026-05-21 20:43:58 -04:00
jbrechtel 76fab5c716 fix: save uploaded files to recipe-images/ subdir and inject source URL
Build and Deploy / build-and-deploy (push) Successful in 1m49s
2026-05-21 17:04:34 -04:00
jbrechtel 439f5780c9 feat: show recipe image thumbnail on index page
Build and Deploy / build-and-deploy (push) Successful in 1m43s
2026-05-21 15:19:14 -04:00
jbrechtel 2dd8840569 fix: resolve prompts dir in Docker and script, try multiple locations
Build and Deploy / build-and-deploy (push) Successful in 1m34s
2026-05-21 12:58:52 -04:00
jbrechtel f6040f5445 chore: add convert-to-cooklang and Python deps to Dockerfile
Build and Deploy / build-and-deploy (push) Successful in 4m21s
2026-05-21 11:59:31 -04:00
jbrechtel 5117c9d445 fix: remove relative path fallback in findConvertScript, rely on PATH only
Build and Deploy / build-and-deploy (push) Successful in 1m33s
2026-05-21 11:42:06 -04:00
jbrechtel 16074b0060 fix: resolve convert-to-cooklang script path with makeAbsolute
Build and Deploy / build-and-deploy (push) Successful in 1m46s
2026-05-21 11:15:39 -04:00
jbrechtel 76fb927109 Fixes typo in Dockerfile config
Build and Deploy / build-and-deploy (push) Successful in 1m43s
2026-05-21 11:03:10 -04:00
jbrechtel d9a7f6538e feat: add Import link to index page navbar
Build and Deploy / build-and-deploy (push) Successful in 1m32s
2026-05-21 10:56:35 -04:00
jbrechtel c36e632d25 style: style import form inputs to match search box
Build and Deploy / build-and-deploy (push) Successful in 1m32s
2026-05-21 10:52:34 -04:00
jbrechtel 5680cc434c Loads config in Docker
Build and Deploy / build-and-deploy (push) Successful in 1m35s
2026-05-21 10:48:52 -04:00
jbrechtel e5e0f1c0e0 chore: add yaml and base64-bytestring dependencies, re-export Config
Build and Deploy / build-and-deploy (push) Successful in 2m1s
2026-05-21 10:34:03 -04:00
jbrechtel 232373cd5c feat: expand import form with file upload via base64 JS 2026-05-21 10:32:49 -04:00
jbrechtel 578d1ae068 feat: add LLM import pipeline with file upload and text input 2026-05-21 10:29:35 -04:00
jbrechtel b179135136 feat: add --config-file CLI flag for YAML config 2026-05-21 10:25:06 -04:00
jbrechtel c015dce51e fix: strip code fences, add MIME/size validation, add tests 2026-05-21 10:23:25 -04:00
jbrechtel 7a3f63e377 feat: add convert-to-cooklang script for Anthropic API recipe conversion 2026-05-21 10:18:23 -04:00
jbrechtel 5765829004 refactor: return Either from loadConfig, add Config tests 2026-05-21 10:16:41 -04:00
jbrechtel 1d5459ea1e feat: add Config module for YAML config loading 2026-05-21 10:10:59 -04:00
jbrechtel 5abf5490b4 feat: add interactive countdown timers to recipe steps
Build and Deploy / build-and-deploy (push) Successful in 1m45s
Cooklang timer references (~{15%minutes}) now render as clickable
spans. Clicking one starts a live countdown displayed in-place
with MM:SS format. A reset button (↺) restarts the timer from
the original duration. A close button (✕) returns to the static
label. When the timer reaches zero, the display pulses and turns
rust-colored for 3 cycles.

Implementation:
- durationToSeconds helper converts Duration to total seconds
- Timer span uses data-seconds attribute for the total
- Label + controls (display, reset, close) structure pre-rendered
  in HTML, toggled via a .running CSS class
- Timer JS initializes all .roux-timer-tag elements on page load
- Each timer manages its own setInterval, multiple timers can
  run simultaneously across different steps
2026-05-20 22:50:35 -04:00
jbrechtel ddb8577c4b feat: add headless Chromium fallback to recipe scraper
Build and Deploy / build-and-deploy (push) Has been cancelled
Uses Playwright to drive Chromium when the primary requests-based
fetch fails (e.g., Cloudflare, JS-required pages). Hybrid approach:
try fast path first, fall back to Chromium only on failure.

Dockerfile: add playwright==1.52.0 pip package, run playwright
install-deps chromium + playwright install chromium to download
the browser and all system libraries.

scrape-recipe: add fetch_with_chromium() that tries Playwright
first, then chromium --headless --dump-dom as a subprocess fallback.
Modify main() to catch primary fetch errors and call Chromium
fallback before giving up.
2026-05-20 22:44:15 -04:00