admin f740f40103 feat(ui): global keyboard shortcuts + shortcut help banner (Sprint 5 F2)
F2 — Vim-style keyboard shortcuts (the audit's F2 / H7 finding).

New files:
- frontend/src/hooks/useKeyboardShortcuts.ts: lightweight global
  handler. Supports both single keys ('/', '?', 'Escape') and
  vim-style 2-key sequences ('g d', 'g r', 'g p', 'g s' for nav).
  Sequence timeout is 1500ms; pending prefix is cleared on any
  unrecognised key so typing 'g' alone is safe. Suppressed when
  the user is typing in an input/textarea/select/contenteditable,
  or when any modifier key (Ctrl/Cmd/Alt) is held — those chords
  belong to the browser or other handlers. Uses a ref so the
  listener is registered once and always sees the latest callbacks.

- frontend/src/hooks/useFocusSearch.ts: tiny CustomEvent bus.
  requestFocusSearch() dispatches a 'mealplanner:focus-search'
  event; useFocusSearchOnShortcut(ref) subscribes and focuses the
  supplied input. The decoupling lets any page opt in without the
  global handler needing to know the page's DOM.

- frontend/src/components/ShortcutHelpBanner.tsx: dismissible help
  dialog that slides down under the nav when '?' is pressed.
  Auto-dismisses after 6s; Escape also dismisses. role=dialog +
  aria-label for screen readers; the kbd elements use the
  <kbd> semantic for assistive tech.

Wired in App.tsx:
- New <GlobalShortcuts /> child of <BrowserRouter> calls
  useKeyboardShortcuts with the 4 nav sequences, '/' →
  requestFocusSearch(), and '?' → dispatch SHOW_SHORTCUT_HELP_EVENT.
- <ShortcutHelpBanner /> mounted inside the page wrapper (after
  <main>).

Pantry and Recipes now call useFocusSearchOnShortcut with a
forwardRef attached to their top search inputs. Recipes's search
already debounced via handleSearch so focusing just selects the
existing text for the user to replace. Pantry's search is a plain
controlled input, same treatment.

Behaviour summary:
- g d / g r / g p / g s → navigate to the 4 main pages
- / → focus the search input on the current page (Pantry + Recipes
  only — other pages have no search)
- ? → show the help banner
- All shortcuts are no-ops inside text-entry controls, so a user
  typing 'p' into the pantry search box will not trigger navigation.

Build: tsc 0 errors, vite 0 errors. 5 files, +185/-3.
2026-06-04 12:36:32 -07:00

Meal Planner

Self-hosted meal planning system that integrates with Lucky California grocery store, sends weekly meal proposals via email to family members, generates shopping lists, and learns from feedback.

Background

This project was born out of frustration with meal kit services (Blue Apron → EveryPlate → HungryRoot → Sunbasket) that:

  • Escalate costs to 3x ingredient markup
  • Fall into repetitive meal rhythms
  • Force users to log into apps to manage selections
  • Don't integrate with home pantry items

Features

  • Grocery Integration: Scrapes Lucky California weekly ads and sales
  • Family Approval Workflow: Email proposals with approve/deny; one denial swaps the meal
  • Shopping List Generation: Weekly list grouped by store aisles, highlighting sales, with interactive checkboxes to track purchased items
  • Pantry Integration: Specify home items to incorporate into suggestions
  • Web UI: Modern interface for the whole family
  • Learning: Feedback-based meal recommendations, with weekly auto-discovery of new recipes from external APIs when family preferences are signaled
  • Recipe Images: Scraped from public recipe sites, AI fallback available
  • Unit Conversion: Converts recipe quantities (cups, tbsp, lb) to grocery units for accurate cost estimates

Architecture

  • Backend: Python/FastAPI
  • Database: PostgreSQL
  • Frontend: React + Tailwind CSS
  • Email: SendGrid
  • Hosting: Docker Compose with nginx reverse proxy

Documentation

Quick Start

# Clone and start
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

Family Profile

Household: 2 adults, 2 children

  • One adult likes mushrooms, one child OK with them
  • Three family members do NOT like mushrooms
  • No allergies
  • Calorie, budget, and health conscious eating

Approval Workflow

  1. System generates 7-day meal plan based on sales, dietary constraints, budget, variety
  2. Email sent to both adults with meal previews
  3. One denial = meal swapped; no denials = auto-approved
  4. Shopping list generated after approval

Tech Stack

Component Technology
Backend Python 3.11, FastAPI
Database PostgreSQL 15
Frontend React 18, TypeScript, Tailwind
Scraping Playwright, BeautifulSoup
Email SendGrid
Hosting Docker Compose, nginx
S
Description
No description provided
Readme
46 MiB
Languages
Python 72.5%
TypeScript 25.9%
JavaScript 0.5%
PLpgSQL 0.4%
CSS 0.3%
Other 0.2%