summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DESIGN.md24
-rw-r--r--cmd/dashboard/main.go4
-rw-r--r--internal/handlers/handlers.go63
-rw-r--r--web/templates/index.html2
-rw-r--r--web/templates/partials/plantoeat-meals.html2
5 files changed, 89 insertions, 6 deletions
diff --git a/DESIGN.md b/DESIGN.md
index 59f3cb8..32e2d15 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -184,6 +184,15 @@ BuildTimeline(ctx, store, calendarClient, tasksClient, start, end)
- `bg-black/60 backdrop-blur-lg` for modals
- `box-shadow: 0 0 12px black` for depth
+**Z-Index Hierarchy:**
+| Layer | z-index | Element |
+|-------|---------|---------|
+| Content | default | Page content |
+| Sticky headers | z-10 | Timeline section headers |
+| Details dropdown | z-30 | Navigation dropdown menu |
+| FAB button | z-50 | Floating action button |
+| Modals | z-50 | Action modal, edit modal |
+
### Typography
- **Font:** Inter (300, 400, 500, 600 weights)
@@ -247,8 +256,8 @@ Chronological view of all upcoming items grouped by day section.
**Data Sources:** Todoist, Trello, PlanToEat, Google Calendar, Google Tasks
**Organization:**
-- **Today** (expanded) - Items due today
-- **Tomorrow** (collapsed) - Items due tomorrow
+- **Today** (expanded, collapsible) - Items due today
+- **Tomorrow** (expanded, collapsible) - Items due tomorrow
- **Later** (collapsed) - Items 2+ days out
**Item Display:**
@@ -281,8 +290,19 @@ Aggregated shopping lists from Trello + PlanToEat + user items.
- Large touch targets
- Fixed bottom quick-add
+### Meals View (`/tabs/meals`)
+
+PlanToEat meal schedule for the next 7 days.
+
+**Features:**
+- Meals grouped by date + meal type (breakfast/lunch/dinner)
+- Multiple recipes for same slot combined with " + " separator
+- Sorted by date, then meal type order
+
### Conditions Page (`/conditions`)
+**Public route** - no authentication required.
+
Standalone live feeds page with:
- 3 Kilauea volcano webcams (USGS)
- 2 Hawaii weather maps (Windy.com)
diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go
index 920ccf2..ce91e6e 100644
--- a/cmd/dashboard/main.go
+++ b/cmd/dashboard/main.go
@@ -145,13 +145,15 @@ func main() {
fileServer := http.FileServer(http.Dir(cfg.StaticDir))
r.Handle("/static/*", http.StripPrefix("/static/", fileServer))
+ // Conditions page (public - no auth required)
+ r.Get("/conditions", h.HandleConditionsPage)
+
// Protected routes (auth required)
r.Group(func(r chi.Router) {
r.Use(authHandlers.Middleware().RequireAuth)
// Dashboard
r.Get("/", h.HandleDashboard)
- r.Get("/conditions", h.HandleConditionsPage)
r.Post("/api/refresh", h.HandleRefresh)
r.Get("/api/tasks", h.HandleGetTasks)
r.Get("/api/meals", h.HandleGetMeals)
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 1c2eb18..9fe1b2c 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -1139,6 +1139,14 @@ func (h *Handler) HandleTabPlanning(w http.ResponseWriter, r *http.Request) {
HTMLResponse(w, h.templates, "planning-tab", data)
}
+// CombinedMeal represents multiple meals combined for same date+mealType
+type CombinedMeal struct {
+ RecipeNames []string
+ Date time.Time
+ MealType string
+ RecipeURL string // URL of first meal
+}
+
// HandleTabMeals renders the Meals tab (PlanToEat)
func (h *Handler) HandleTabMeals(w http.ResponseWriter, r *http.Request) {
startDate := config.Now()
@@ -1150,7 +1158,60 @@ func (h *Handler) HandleTabMeals(w http.ResponseWriter, r *http.Request) {
return
}
- HTMLResponse(w, h.templates, "meals-tab", struct{ Meals []models.Meal }{meals})
+ // Group meals by date+mealType
+ type mealKey struct {
+ date string
+ mealType string
+ }
+ mealGroups := make(map[mealKey][]models.Meal)
+ for _, meal := range meals {
+ key := mealKey{
+ date: meal.Date.Format("2006-01-02"),
+ mealType: meal.MealType,
+ }
+ mealGroups[key] = append(mealGroups[key], meal)
+ }
+
+ // Convert to combined meals
+ var combined []CombinedMeal
+ for _, group := range mealGroups {
+ if len(group) == 0 {
+ continue
+ }
+ cm := CombinedMeal{
+ Date: group[0].Date,
+ MealType: group[0].MealType,
+ RecipeURL: group[0].RecipeURL,
+ }
+ for _, m := range group {
+ cm.RecipeNames = append(cm.RecipeNames, m.RecipeName)
+ }
+ combined = append(combined, cm)
+ }
+
+ // Sort by date then meal type order
+ sort.Slice(combined, func(i, j int) bool {
+ if !combined[i].Date.Equal(combined[j].Date) {
+ return combined[i].Date.Before(combined[j].Date)
+ }
+ return mealTypeOrder(combined[i].MealType) < mealTypeOrder(combined[j].MealType)
+ })
+
+ HTMLResponse(w, h.templates, "meals-tab", struct{ Meals []CombinedMeal }{combined})
+}
+
+// mealTypeOrder returns sort order for meal types
+func mealTypeOrder(mealType string) int {
+ switch mealType {
+ case "breakfast":
+ return 0
+ case "lunch":
+ return 1
+ case "dinner":
+ return 2
+ default:
+ return 3
+ }
}
// HandleTabShopping renders the Shopping tab (Trello Shopping board + PlanToEat + User items)
diff --git a/web/templates/index.html b/web/templates/index.html
index c6743ba..3451623 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -118,7 +118,7 @@
<!-- Unified Action Button (FAB) -->
<button onclick="openActionModal()"
- class="fixed bottom-4 right-4 z-40 bg-black/60 hover:bg-black/80 backdrop-blur-sm text-white p-4 rounded-full no-print"
+ class="fixed bottom-4 right-4 z-50 bg-black/60 hover:bg-black/80 backdrop-blur-sm text-white p-4 rounded-full no-print"
style="box-shadow: 0 0 12px black;"
title="Quick Actions (Ctrl+K)">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
diff --git a/web/templates/partials/plantoeat-meals.html b/web/templates/partials/plantoeat-meals.html
index 1f016ef..f05c98c 100644
--- a/web/templates/partials/plantoeat-meals.html
+++ b/web/templates/partials/plantoeat-meals.html
@@ -10,7 +10,7 @@
<div class="space-y-3">
{{range .Meals}}
<div class="border-l-4 border-plantoeat bg-black/30 pl-4 py-3 rounded-r-lg hover:bg-black/40 transition-colors">
- <p class="font-medium text-white">{{.RecipeName}}</p>
+ <p class="font-medium text-white">{{range $i, $name := .RecipeNames}}{{if $i}} + {{end}}{{$name}}{{end}}</p>
<div class="flex justify-between items-center mt-2">
<span class="text-sm text-white/60">{{.Date.Format "Mon, Jan 2"}}</span>
<span class="badge bg-green-900/50 text-green-300 capitalize">