From 986968b93d959b6910b2b369a7a2a3c7bf32c4a1 Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Sun, 17 May 2026 21:22:37 -0700 Subject: [PATCH] fix: improve mobile layout on meals page and navigation - Dashboard: stack days vertically on mobile and suppress empty meal slots - Nav: allow wrapping on narrow screens - MealDetail: responsive hero sizing and padding --- frontend/src/App.tsx | 12 +- frontend/src/pages/Dashboard.tsx | 297 +++++++++++++++--------------- frontend/src/pages/MealDetail.tsx | 20 +- 3 files changed, 162 insertions(+), 167 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e6eaa83..07fa5f1 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -21,13 +21,11 @@ function Navigation() { return ( diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index a7c5c2e..d336334 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -119,159 +119,156 @@ function MealCard({ item, dragHandleProps, isDragging, onApprove, onDeny }: { ) } -/* ------------------------------------------------------------------ */ -/* MealSlot — droppable area for one day + meal_type */ -/* ------------------------------------------------------------------ */ -function MealSlot({ - dayIndex, - mealType, - item, - onApprove, - onDeny, - onGenerate, -}: { - dayIndex: number - mealType: string - item?: MealPlanItem - onApprove?: (itemId: string) => void - onDeny?: (itemId: string) => void - onGenerate?: (dayIndex: number, mealType: string) => void -}) { - const droppableId = `slot-${dayIndex}-${mealType}` + /* ------------------------------------------------------------------ */ + /* MealSlot — droppable area for one day + meal_type */ + /* ------------------------------------------------------------------ */ + function MealSlot({ + dayIndex, + mealType, + item, + onApprove, + onDeny, + onGenerate, + }: { + dayIndex: number + mealType: string + item?: MealPlanItem + onApprove?: (itemId: string) => void + onDeny?: (itemId: string) => void + onGenerate?: (dayIndex: number, mealType: string) => void + }) { + const droppableId = `slot-${dayIndex}-${mealType}` - return ( - - {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => ( -
- {item ? ( - - {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => ( -
- -
- )} -
- ) : ( -
- Empty - {onGenerate && ( - - )} -
- )} - {provided.placeholder} -
- )} -
- ) -} - -/* ------------------------------------------------------------------ */ -/* DayColumn */ -/* ------------------------------------------------------------------ */ -function DayColumn({ - dayIndex, - items, - onApprove, - onDeny, - onGenerate, -}: { - dayIndex: number - items: MealPlanItem[] - onApprove?: (itemId: string) => void - onDeny?: (itemId: string) => void - onGenerate?: (dayIndex: number, mealType: string) => void -}) { - const today = new Date().getDay() - const isToday = today === (dayIndex + 1) % 7 - - return ( -
-
-
- - {FULL_DAY_NAMES[dayIndex]} - - {isToday && Today} -
- {DAY_NAMES[dayIndex]} -
-
- {MEAL_TYPES.map(mealType => { - const item = items.find(i => i.meal_type === mealType) - return ( -
- - {mealType} - - -
- ) - })} -
-
- ) -} - -/* ------------------------------------------------------------------ */ -/* Skeleton */ -/* ------------------------------------------------------------------ */ -function DashboardSkeleton() { - return ( -
-
- -
- - -
-
-
- {Array.from({ length: 7 }).map((_, i) => ( -
- - - - + return ( + + {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => ( +
+ {item ? ( + + {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => ( +
+ +
+ )} +
+ ) : ( +
+ Empty + {onGenerate && ( + + )} +
+ )} + {provided.placeholder}
- ))} + )} +
+ ) + } + + /* ------------------------------------------------------------------ */ + /* DayColumn */ + /* ------------------------------------------------------------------ */ + function DayColumn({ + dayIndex, + items, + onApprove, + onDeny, + onGenerate, + }: { + dayIndex: number + items: MealPlanItem[] + onApprove?: (itemId: string) => void + onDeny?: (itemId: string) => void + onGenerate?: (dayIndex: number, mealType: string) => void + }) { + const today = new Date().getDay() + const isToday = today === (dayIndex + 1) % 7 + + return ( +
+
+
+ + {FULL_DAY_NAMES[dayIndex]} + + {isToday && Today} +
+ {DAY_NAMES[dayIndex]} +
+
+ {MEAL_TYPES.map(mealType => { + const item = items.find(i => i.meal_type === mealType) + return ( +
+ + {mealType} + + +
+ ) + })} +
-
- - + ) + } + + function DashboardSkeleton() { + return ( +
+
+ +
+ + +
+
+
+ {Array.from({ length: 7 }).map((_, i) => ( +
+ +
+
+
+
+ ))} +
+
+ + +
-
- ) -} + ) + } /* ------------------------------------------------------------------ */ /* VoteEmailButton */ @@ -431,7 +428,7 @@ export default function Dashboard() { -
+
{itemsByDay.map((items, index) => ( ) : ( -
+
)}
-
-
+
+
-

{recipe.name}

+

{recipe.name}

{recipe.description && ( -

{recipe.description}

+

{recipe.description}

)}
-
-
+
+
${item.estimated_cost?.toFixed(2) || 'N/A'}
-
per serving
+
per serving
{/* Metadata Row */} -
+
{totalTime > 0 && (