fix: dashboard calorie widget horizontal layout + bold meal section headers
All checks were successful
Security Checks / dependency-audit (push) Successful in 13s
Security Checks / secret-scanning (push) Successful in 4s
Security Checks / dockerfile-lint (push) Successful in 3s

Dashboard:
- Removed LazyVGrid, calorie widget is full-width HStack
- Ring (90px) + text info side by side
- No more vertical text issue

Meal sections:
- Title3 bold font for meal name
- Meal icon in tinted circle background
- Item count subtitle
- Calorie total in meal color (bold)
- Subtle tinted background on header
- Clear visual separation from food entries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-04-03 08:44:53 -05:00
parent db6324f161
commit 3040e55475
2 changed files with 61 additions and 34 deletions

View File

@@ -19,41 +19,51 @@ struct MealSectionView: View {
isExpanded.toggle()
}
} label: {
HStack(spacing: 12) {
// Accent bar
HStack(spacing: 0) {
// Colored accent bar
RoundedRectangle(cornerRadius: 2)
.fill(Color.mealColor(for: mealType.rawValue))
.frame(width: 4, height: 32)
.frame(width: 4, height: 40)
.padding(.trailing, 12)
// Meal icon in tinted circle
Image(systemName: mealType.icon)
.font(.body.weight(.medium))
.font(.title3.weight(.semibold))
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
.frame(width: 32, height: 32)
.background(Color.mealColor(for: mealType.rawValue).opacity(0.12))
.clipShape(Circle())
.padding(.trailing, 10)
Text(mealType.displayName)
.font(.headline)
.foregroundStyle(Color.textPrimary)
VStack(alignment: .leading, spacing: 2) {
Text(mealType.displayName)
.font(.title3.weight(.bold))
.foregroundStyle(Color.textPrimary)
Text("\(entries.count)")
.font(.caption.weight(.medium))
.foregroundStyle(Color.textSecondary)
.padding(.horizontal, 6)
.padding(.vertical, 2)
.background(Color.textSecondary.opacity(0.1))
.clipShape(Capsule())
Text("\(entries.count) item\(entries.count == 1 ? "" : "s")")
.font(.caption)
.foregroundStyle(Color.textTertiary)
}
Spacer()
Text("\(Int(totalCalories)) kcal")
.font(.subheadline.weight(.semibold))
Text("\(Int(totalCalories))")
.font(.title3.weight(.bold))
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
+ Text(" kcal")
.font(.caption.weight(.medium))
.foregroundStyle(Color.textSecondary)
Image(systemName: "chevron.right")
.font(.caption.weight(.medium))
.foregroundStyle(Color.textTertiary)
.rotationEffect(.degrees(isExpanded ? 90 : 0))
.padding(.leading, 8)
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
.padding(.vertical, 14)
.background(Color.mealColor(for: mealType.rawValue).opacity(0.04))
.clipShape(RoundedRectangle(cornerRadius: 14))
}
if isExpanded {

View File

@@ -4,10 +4,10 @@ import PhotosUI
struct HomeView: View {
@Environment(AuthManager.self) private var auth
@State private var vm = HomeViewModel()
@State private var showProfileMenu = false
@State private var showAssistant = false
var body: some View {
ZStack {
ZStack(alignment: .bottomTrailing) {
// Background
if let bg = vm.backgroundImage {
Image(uiImage: bg)
@@ -23,7 +23,7 @@ struct HomeView: View {
// Top bar
HStack {
Text("Home")
.font(.largeTitle.weight(.bold))
.font(.title.weight(.bold))
.foregroundStyle(vm.hasBackground ? .white : Color.textPrimary)
Spacer()
Menu {
@@ -55,22 +55,36 @@ struct HomeView: View {
.padding(.horizontal)
.padding(.top, 60)
// Widget grid
LazyVGrid(columns: [
GridItem(.flexible(), spacing: 12),
GridItem(.flexible(), spacing: 12),
], spacing: 12) {
// Calorie widget
calorieWidget
.gridCellColumns(2)
}
.padding(.horizontal)
// Calorie widget full width card
calorieWidget
.padding(.horizontal)
Spacer(minLength: 100)
}
}
// Floating + button
Button {
showAssistant = true
} label: {
Image(systemName: "plus")
.font(.title2.weight(.semibold))
.foregroundStyle(.white)
.frame(width: 56, height: 56)
.background(Color.accentWarm)
.clipShape(Circle())
.shadow(color: Color.accentWarm.opacity(0.3), radius: 8, y: 4)
}
.padding(.trailing, 20)
.padding(.bottom, 100)
}
.navigationBarHidden(true)
.sheet(isPresented: $showAssistant) {
FoodSearchView(
date: Date().apiDateString,
onFoodAdded: { Task { await vm.loadTodayData() } }
)
}
.task {
await vm.loadTodayData()
}
@@ -81,22 +95,25 @@ struct HomeView: View {
private var calorieWidget: some View {
HStack(spacing: 20) {
// Ring
MacroRingWithLabel(
consumed: vm.totalCalories,
goal: vm.calorieGoal,
label: "kcal",
color: .emerald,
size: 100,
lineWidth: 10
size: 90,
lineWidth: 9
)
.frame(width: 90, height: 90)
VStack(alignment: .leading, spacing: 8) {
// Text info
VStack(alignment: .leading, spacing: 6) {
Text("Calories")
.font(.headline)
.foregroundStyle(vm.hasBackground ? .white : Color.textPrimary)
Text("\(Int(vm.totalCalories)) / \(Int(vm.calorieGoal))")
.font(.subheadline)
.font(.subheadline.weight(.medium))
.foregroundStyle(vm.hasBackground ? .white.opacity(0.8) : Color.textSecondary)
let remaining = max(vm.calorieGoal - vm.totalCalories, 0)