revert: restore warm Atelier design, remove Liquid Glass changes
Reverts all Liquid Glass styling back to the original warm beige/brown Atelier design system. Deployment target back to iOS 17.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -427,7 +427,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
@@ -484,7 +484,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ struct ContentView: View {
|
|||||||
if auth.isCheckingAuth {
|
if auth.isCheckingAuth {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
.background(Color.canvas)
|
||||||
} else if auth.isLoggedIn {
|
} else if auth.isLoggedIn {
|
||||||
MainTabView()
|
MainTabView()
|
||||||
} else {
|
} else {
|
||||||
@@ -38,26 +39,27 @@ struct MainTabView: View {
|
|||||||
.tag(1)
|
.tag(1)
|
||||||
}
|
}
|
||||||
.tint(Color.accentWarm)
|
.tint(Color.accentWarm)
|
||||||
.tabBarMinimizeBehavior(.onScrollDown)
|
|
||||||
|
|
||||||
// Floating buttons
|
// Floating buttons
|
||||||
VStack {
|
VStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
HStack(alignment: .bottom) {
|
HStack(alignment: .bottom) {
|
||||||
|
// Feedback button (subtle, bottom-left)
|
||||||
FeedbackButton()
|
FeedbackButton()
|
||||||
.padding(.leading, 20)
|
.padding(.leading, 20)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
// Add food button (prominent, bottom-right)
|
||||||
Button { showAssistant = true } label: {
|
Button { showAssistant = true } label: {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
.font(.title2.weight(.semibold))
|
.font(.title2.weight(.semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(width: 56, height: 56)
|
.frame(width: 56, height: 56)
|
||||||
|
.background(Color.accentWarm)
|
||||||
|
.clipShape(Circle())
|
||||||
|
.shadow(color: .black.opacity(0.2), radius: 8, y: 4)
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
|
||||||
.tint(Color.accentWarm)
|
|
||||||
.clipShape(Circle())
|
|
||||||
.padding(.trailing, 20)
|
.padding(.trailing, 20)
|
||||||
}
|
}
|
||||||
.padding(.bottom, 70)
|
.padding(.bottom, 70)
|
||||||
@@ -110,11 +112,12 @@ struct AssistantSheetView: View {
|
|||||||
tabButton("Quick Add", icon: "magnifyingglass", index: 1)
|
tabButton("Quick Add", icon: "magnifyingglass", index: 1)
|
||||||
}
|
}
|
||||||
.padding(4)
|
.padding(4)
|
||||||
.background(.ultraThinMaterial)
|
.background(Color.textTertiary.opacity(0.08))
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
.padding(.horizontal, 40)
|
.padding(.horizontal, 40)
|
||||||
}
|
}
|
||||||
.padding(.bottom, 12)
|
.padding(.bottom, 12)
|
||||||
|
.background(Color.canvas)
|
||||||
|
|
||||||
if selectedMode == 0 {
|
if selectedMode == 0 {
|
||||||
AssistantChatView(onFoodAdded: onFoodAdded)
|
AssistantChatView(onFoodAdded: onFoodAdded)
|
||||||
@@ -122,6 +125,7 @@ struct AssistantSheetView: View {
|
|||||||
FoodSearchView(isSheet: true, onFoodAdded: onFoodAdded)
|
FoodSearchView(isSheet: true, onFoodAdded: onFoodAdded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.presentationDetents([.large])
|
.presentationDetents([.large])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +140,7 @@ struct AssistantSheetView: View {
|
|||||||
.foregroundStyle(selectedMode == index ? Color.textPrimary : Color.textTertiary)
|
.foregroundStyle(selectedMode == index ? Color.textPrimary : Color.textTertiary)
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.background {
|
.background(selectedMode == index ? Color.surfaceCard : Color.clear)
|
||||||
if selectedMode == index {
|
|
||||||
Capsule().fill(.thinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ struct AssistantChatView: View {
|
|||||||
ScrollViewReader { proxy in
|
ScrollViewReader { proxy in
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack(spacing: 8) {
|
LazyVStack(spacing: 8) {
|
||||||
|
// Welcome state when no messages
|
||||||
if vm.messages.isEmpty {
|
if vm.messages.isEmpty {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
Spacer(minLength: 60)
|
Spacer(minLength: 60)
|
||||||
@@ -36,10 +37,12 @@ struct AssistantChatView: View {
|
|||||||
.id(message.id)
|
.id(message.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draft card
|
||||||
if let draft = vm.currentDraft, !vm.applied {
|
if let draft = vm.currentDraft, !vm.applied {
|
||||||
draftCard(draft)
|
draftCard(draft)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiple drafts
|
||||||
if vm.currentDrafts.count > 1 && !vm.applied {
|
if vm.currentDrafts.count > 1 && !vm.applied {
|
||||||
multipleDraftsCard
|
multipleDraftsCard
|
||||||
}
|
}
|
||||||
@@ -110,8 +113,9 @@ struct AssistantChatView: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(.bar)
|
.background(Color.surfaceCard)
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.onChange(of: vm.selectedPhoto) {
|
.onChange(of: vm.selectedPhoto) {
|
||||||
Task { await vm.handlePhotoSelection() }
|
Task { await vm.handlePhotoSelection() }
|
||||||
}
|
}
|
||||||
@@ -137,10 +141,10 @@ struct AssistantChatView: View {
|
|||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(
|
.background(
|
||||||
message.role == "user"
|
message.role == "user"
|
||||||
? AnyShapeStyle(Color.accentWarm)
|
? Color.accentWarm
|
||||||
: AnyShapeStyle(.thinMaterial)
|
: Color.surfaceSheet
|
||||||
)
|
)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 18))
|
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||||
|
|
||||||
if message.role == "assistant" { Spacer(minLength: 60) }
|
if message.role == "assistant" { Spacer(minLength: 60) }
|
||||||
}
|
}
|
||||||
@@ -185,12 +189,14 @@ struct AssistantChatView: View {
|
|||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
|
.background(Color.emerald)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
|
||||||
.tint(Color.emerald)
|
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.06), radius: 6, y: 2)
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,12 +235,14 @@ struct AssistantChatView: View {
|
|||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
|
.background(Color.emerald)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
|
||||||
.tint(Color.emerald)
|
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.06), radius: 6, y: 2)
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,9 @@ struct LoginView: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 48)
|
.frame(height: 48)
|
||||||
|
.background(Color.accentWarm)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.background(Color.accentWarm, in: RoundedRectangle(cornerRadius: 14))
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
.disabled(username.isEmpty || password.isEmpty || isLoading)
|
.disabled(username.isEmpty || password.isEmpty || isLoading)
|
||||||
.opacity(username.isEmpty || password.isEmpty ? 0.6 : 1)
|
.opacity(username.isEmpty || password.isEmpty ? 0.6 : 1)
|
||||||
}
|
}
|
||||||
@@ -67,5 +68,6 @@ struct LoginView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ struct FeedbackButton: View {
|
|||||||
.font(.system(size: 14))
|
.font(.system(size: 14))
|
||||||
.foregroundStyle(Color.textTertiary)
|
.foregroundStyle(Color.textTertiary)
|
||||||
.frame(width: 32, height: 32)
|
.frame(width: 32, height: 32)
|
||||||
|
.background(Color.surfaceCard.opacity(0.8))
|
||||||
|
.clipShape(Circle())
|
||||||
|
.shadow(color: .black.opacity(0.08), radius: 4, y: 2)
|
||||||
}
|
}
|
||||||
.buttonStyle(.glass)
|
|
||||||
.clipShape(Circle())
|
|
||||||
.sheet(isPresented: $showSheet) {
|
.sheet(isPresented: $showSheet) {
|
||||||
FeedbackSheet()
|
FeedbackSheet()
|
||||||
.presentationDetents([.large, .medium])
|
.presentationDetents([.large, .medium])
|
||||||
@@ -60,7 +61,12 @@ struct FeedbackSheet: View {
|
|||||||
.font(.body)
|
.font(.body)
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
.padding(12)
|
.padding(12)
|
||||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 14))
|
.background(Color.canvas)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.stroke(Color.textTertiary.opacity(0.2), lineWidth: 1)
|
||||||
|
)
|
||||||
|
|
||||||
// Photo attachment
|
// Photo attachment
|
||||||
HStack {
|
HStack {
|
||||||
@@ -74,7 +80,8 @@ struct FeedbackSheet: View {
|
|||||||
.foregroundStyle(Color.accentWarm)
|
.foregroundStyle(Color.accentWarm)
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.background(Color.accentWarm.opacity(0.1), in: Capsule())
|
.background(Color.accentWarm.opacity(0.1))
|
||||||
|
.clipShape(Capsule())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let preview = photoPreview {
|
if let preview = photoPreview {
|
||||||
@@ -116,15 +123,14 @@ struct FeedbackSheet: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 48)
|
.frame(height: 48)
|
||||||
|
.background(text.trimmingCharacters(in: .whitespaces).isEmpty ? Color.textTertiary : Color.accentWarm)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.background(
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
text.trimmingCharacters(in: .whitespaces).isEmpty ? Color.textTertiary : Color.accentWarm,
|
|
||||||
in: RoundedRectangle(cornerRadius: 14)
|
|
||||||
)
|
|
||||||
.disabled(text.trimmingCharacters(in: .whitespaces).isEmpty || isSending)
|
.disabled(text.trimmingCharacters(in: .whitespaces).isEmpty || isSending)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
.background(Color.surfaceCard)
|
||||||
.onChange(of: selectedPhoto) {
|
.onChange(of: selectedPhoto) {
|
||||||
Task {
|
Task {
|
||||||
if let item = selectedPhoto,
|
if let item = selectedPhoto,
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ struct AddFoodSheet: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
|
|
||||||
|
// Serving picker
|
||||||
if let servings = food.servings, !servings.isEmpty {
|
if let servings = food.servings, !servings.isEmpty {
|
||||||
Picker("Serving", selection: $selectedServingId) {
|
Picker("Serving", selection: $selectedServingId) {
|
||||||
Text("Base (\(food.baseUnit))").tag(nil as String?)
|
Text("Base (\(food.baseUnit))").tag(nil as String?)
|
||||||
@@ -91,7 +92,8 @@ struct AddFoodSheet: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
|
|
||||||
// Meal picker
|
// Meal picker
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
@@ -114,15 +116,15 @@ struct AddFoodSheet: View {
|
|||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(selectedMeal == meal
|
.background(selectedMeal == meal
|
||||||
? Color.mealColor(for: meal.rawValue).opacity(0.15)
|
? Color.mealColor(for: meal.rawValue).opacity(0.15)
|
||||||
: .clear
|
: Color.surfaceCard
|
||||||
)
|
)
|
||||||
.foregroundStyle(selectedMeal == meal
|
.foregroundStyle(selectedMeal == meal
|
||||||
? Color.mealColor(for: meal.rawValue)
|
? Color.mealColor(for: meal.rawValue)
|
||||||
: Color.textSecondary
|
: Color.textSecondary
|
||||||
)
|
)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 12)
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.stroke(selectedMeal == meal
|
.stroke(selectedMeal == meal
|
||||||
? Color.mealColor(for: meal.rawValue).opacity(0.3)
|
? Color.mealColor(for: meal.rawValue).opacity(0.3)
|
||||||
: Color.clear, lineWidth: 1
|
: Color.clear, lineWidth: 1
|
||||||
@@ -133,7 +135,8 @@ struct AddFoodSheet: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
|
|
||||||
// Nutrition preview
|
// Nutrition preview
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
@@ -154,7 +157,8 @@ struct AddFoodSheet: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
|
|
||||||
if let error {
|
if let error {
|
||||||
Text(error)
|
Text(error)
|
||||||
@@ -165,6 +169,7 @@ struct AddFoodSheet: View {
|
|||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.scrollDismissesKeyboard(.immediately)
|
.scrollDismissesKeyboard(.immediately)
|
||||||
|
.background(Color.canvas)
|
||||||
.safeAreaInset(edge: .bottom) {
|
.safeAreaInset(edge: .bottom) {
|
||||||
Button {
|
Button {
|
||||||
addEntry()
|
addEntry()
|
||||||
@@ -179,12 +184,13 @@ struct AddFoodSheet: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
|
.background(Color.accentWarm)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.background(Color.accentWarm, in: RoundedRectangle(cornerRadius: 16))
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
.disabled(isAdding)
|
.disabled(isAdding)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
.background(.bar)
|
.background(Color.canvas)
|
||||||
}
|
}
|
||||||
.navigationTitle("Add Food")
|
.navigationTitle("Add Food")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ struct EntryDetailView: View {
|
|||||||
.foregroundStyle(Color.textPrimary)
|
.foregroundStyle(Color.textPrimary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
|
// Meal type picker
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("Meal")
|
Text("Meal")
|
||||||
.font(.subheadline.weight(.medium))
|
.font(.subheadline.weight(.medium))
|
||||||
@@ -61,6 +62,7 @@ struct EntryDetailView: View {
|
|||||||
.pickerStyle(.segmented)
|
.pickerStyle(.segmented)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quantity field
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("Quantity (\(entry.unit))")
|
Text("Quantity (\(entry.unit))")
|
||||||
.font(.subheadline.weight(.medium))
|
.font(.subheadline.weight(.medium))
|
||||||
@@ -83,7 +85,8 @@ struct EntryDetailView: View {
|
|||||||
.keyboardType(.decimalPad)
|
.keyboardType(.decimalPad)
|
||||||
.frame(width: 80)
|
.frame(width: 80)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 10))
|
.background(Color.canvas)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
if let val = Double(editQuantity) {
|
if let val = Double(editQuantity) {
|
||||||
@@ -130,13 +133,15 @@ struct EntryDetailView: View {
|
|||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
|
.background(Color.emerald)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
|
||||||
.tint(Color.emerald)
|
|
||||||
.disabled(isSaving)
|
.disabled(isSaving)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.04), radius: 6, y: 2)
|
||||||
|
|
||||||
// Nutrition grid
|
// Nutrition grid
|
||||||
LazyVGrid(columns: [
|
LazyVGrid(columns: [
|
||||||
@@ -152,7 +157,8 @@ struct EntryDetailView: View {
|
|||||||
nutritionCell("Fiber", value: entry.fiber, unit: "g", color: .green)
|
nutritionCell("Fiber", value: entry.fiber, unit: "g", color: .green)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
@@ -164,7 +170,8 @@ struct EntryDetailView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
|
||||||
// Delete button
|
// Delete button
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
@@ -175,11 +182,12 @@ struct EntryDetailView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 48)
|
.frame(height: 48)
|
||||||
}
|
}
|
||||||
.buttonStyle(.glass)
|
.buttonStyle(.borderedProminent)
|
||||||
.tint(.red)
|
.tint(.red)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.navigationTitle("Entry Detail")
|
.navigationTitle("Entry Detail")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.alert("Delete Entry?", isPresented: $showDeleteConfirmation) {
|
.alert("Delete Entry?", isPresented: $showDeleteConfirmation) {
|
||||||
|
|||||||
@@ -5,45 +5,46 @@ struct FitnessTabView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
// Sub-tab selector
|
// Sub-tab selector
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
ForEach(Array(fitnessSubTabs.enumerated()), id: \.offset) { index, tab in
|
ForEach(Array(fitnessSubTabs.enumerated()), id: \.offset) { index, tab in
|
||||||
Button {
|
Button {
|
||||||
withAnimation(.easeInOut(duration: 0.2)) {
|
withAnimation(.easeInOut(duration: 0.2)) {
|
||||||
selectedSubTab = index
|
selectedSubTab = index
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Text(tab)
|
|
||||||
.font(.subheadline.weight(selectedSubTab == index ? .semibold : .regular))
|
|
||||||
.foregroundStyle(selectedSubTab == index ? Color.accentWarm : Color.textSecondary)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
.background {
|
|
||||||
if selectedSubTab == index {
|
|
||||||
Capsule()
|
|
||||||
.fill(.ultraThinMaterial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} label: {
|
||||||
|
Text(tab)
|
||||||
|
.font(.subheadline.weight(selectedSubTab == index ? .semibold : .regular))
|
||||||
|
.foregroundStyle(selectedSubTab == index ? Color.accentWarm : Color.textSecondary)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.background {
|
||||||
|
if selectedSubTab == index {
|
||||||
|
Capsule()
|
||||||
|
.fill(Color.accentWarm.opacity(0.12))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
|
||||||
.padding(.top, 8)
|
|
||||||
|
|
||||||
Group {
|
|
||||||
switch selectedSubTab {
|
|
||||||
case 0: TodayView()
|
|
||||||
case 1: TemplatesView()
|
|
||||||
case 2: GoalsView()
|
|
||||||
case 3: FoodLibraryView()
|
|
||||||
default: TodayView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.animation(.easeInOut(duration: 0.2), value: selectedSubTab)
|
|
||||||
}
|
}
|
||||||
.navigationTitle("Fitness")
|
.padding(.horizontal)
|
||||||
.navigationBarTitleDisplayMode(.large)
|
.padding(.top, 8)
|
||||||
|
|
||||||
|
// Content — tap tabs to switch (no page swipe, preserves swipe-to-delete)
|
||||||
|
Group {
|
||||||
|
switch selectedSubTab {
|
||||||
|
case 0: TodayView()
|
||||||
|
case 1: TemplatesView()
|
||||||
|
case 2: GoalsView()
|
||||||
|
case 3: FoodLibraryView()
|
||||||
|
default: TodayView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.animation(.easeInOut(duration: 0.2), value: selectedSubTab)
|
||||||
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
|
.navigationBarHidden(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ struct FoodLibraryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(12)
|
.padding(12)
|
||||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ struct FoodLibraryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.task {
|
.task {
|
||||||
await vm.loadInitial()
|
await vm.loadInitial()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,18 +26,22 @@ struct FoodSearchView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(12)
|
.padding(12)
|
||||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
|
|
||||||
if vm.isLoadingInitial {
|
if vm.isLoadingInitial {
|
||||||
LoadingView()
|
LoadingView()
|
||||||
} else if !vm.searchText.isEmpty {
|
} else if !vm.searchText.isEmpty {
|
||||||
|
// Search results
|
||||||
searchResultsList
|
searchResultsList
|
||||||
} else {
|
} else {
|
||||||
|
// Recent + All
|
||||||
defaultList
|
defaultList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.task {
|
.task {
|
||||||
await vm.loadInitial()
|
await vm.loadInitial()
|
||||||
}
|
}
|
||||||
@@ -128,11 +132,14 @@ struct FoodSearchView: View {
|
|||||||
|
|
||||||
private func recentFoodRow(_ recent: RecentFood) -> some View {
|
private func recentFoodRow(_ recent: RecentFood) -> some View {
|
||||||
Button {
|
Button {
|
||||||
|
// Navigate to add sheet by loading the full food
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
let food = try await FitnessAPI().getFood(id: recent.foodId)
|
let food = try await FitnessAPI().getFood(id: recent.foodId)
|
||||||
selectedFood = food
|
selectedFood = food
|
||||||
} catch {}
|
} catch {
|
||||||
|
// Silently fail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
HStack {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct GoalsView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.task {
|
.task {
|
||||||
await vm.load()
|
await vm.load()
|
||||||
}
|
}
|
||||||
@@ -91,13 +92,15 @@ struct GoalsView: View {
|
|||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
|
.background(Color.emerald)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
|
||||||
.tint(Color.emerald)
|
|
||||||
.disabled(vm.isSaving)
|
.disabled(vm.isSaving)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.04), radius: 6, y: 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func goalField(_ label: String, text: Binding<String>, unit: String, color: Color) -> some View {
|
private func goalField(_ label: String, text: Binding<String>, unit: String, color: Color) -> some View {
|
||||||
@@ -117,6 +120,6 @@ struct GoalsView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
.background(color.opacity(0.06))
|
.background(color.opacity(0.06))
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ struct MealSectionView: View {
|
|||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
|
// Colored accent bar
|
||||||
RoundedRectangle(cornerRadius: 2)
|
RoundedRectangle(cornerRadius: 2)
|
||||||
.fill(Color.mealColor(for: mealType.rawValue))
|
.fill(Color.mealColor(for: mealType.rawValue))
|
||||||
.frame(width: 4, height: 40)
|
.frame(width: 4, height: 40)
|
||||||
.padding(.trailing, 12)
|
.padding(.trailing, 12)
|
||||||
|
|
||||||
|
// Meal icon in tinted circle
|
||||||
Image(systemName: mealType.icon)
|
Image(systemName: mealType.icon)
|
||||||
.font(.title3.weight(.semibold))
|
.font(.title3.weight(.semibold))
|
||||||
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
|
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
|
||||||
@@ -45,14 +47,12 @@ struct MealSectionView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
Text("\(Int(totalCalories))")
|
||||||
Text("\(Int(totalCalories))")
|
.font(.title3.weight(.bold))
|
||||||
.font(.title3.weight(.bold))
|
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
|
||||||
.foregroundStyle(Color.mealColor(for: mealType.rawValue))
|
+ Text(" kcal")
|
||||||
Text("kcal")
|
.font(.caption.weight(.medium))
|
||||||
.font(.caption.weight(.medium))
|
.foregroundStyle(Color.textSecondary)
|
||||||
.foregroundStyle(Color.textSecondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
Image(systemName: "chevron.right")
|
Image(systemName: "chevron.right")
|
||||||
.font(.caption.weight(.medium))
|
.font(.caption.weight(.medium))
|
||||||
@@ -63,14 +63,14 @@ struct MealSectionView: View {
|
|||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 14)
|
.padding(.vertical, 14)
|
||||||
.background(Color.mealColor(for: mealType.rawValue).opacity(0.04))
|
.background(Color.mealColor(for: mealType.rawValue).opacity(0.04))
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
}
|
}
|
||||||
|
|
||||||
if isExpanded {
|
if isExpanded {
|
||||||
ForEach(entries) { entry in
|
ForEach(entries) { entry in
|
||||||
SwipeToDeleteRow(
|
SwipeToDeleteRow(
|
||||||
onDelete: { onDelete(entry) },
|
onDelete: { onDelete(entry) },
|
||||||
onTap: { },
|
onTap: { /* handled by NavigationLink */ },
|
||||||
destination: { EntryDetailView(entry: entry, onDelete: { onDelete(entry) }) }
|
destination: { EntryDetailView(entry: entry, onDelete: { onDelete(entry) }) }
|
||||||
) {
|
) {
|
||||||
entryRow(entry)
|
entryRow(entry)
|
||||||
@@ -78,7 +78,9 @@ struct MealSectionView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.04), radius: 6, y: 2)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +112,7 @@ struct MealSectionView: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(Color(.systemBackground))
|
.background(Color.surfaceCard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +130,7 @@ struct SwipeToDeleteRow<Content: View, Destination: View>: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .trailing) {
|
ZStack(alignment: .trailing) {
|
||||||
|
// Delete button background
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button {
|
Button {
|
||||||
@@ -145,6 +148,7 @@ struct SwipeToDeleteRow<Content: View, Destination: View>: View {
|
|||||||
.background(Color.red)
|
.background(Color.red)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Content row
|
||||||
content()
|
content()
|
||||||
.offset(x: offset)
|
.offset(x: offset)
|
||||||
.navigationDestination(isPresented: $showDetail) {
|
.navigationDestination(isPresented: $showDetail) {
|
||||||
@@ -154,6 +158,7 @@ struct SwipeToDeleteRow<Content: View, Destination: View>: View {
|
|||||||
if !isSwiping {
|
if !isSwiping {
|
||||||
showDetail = true
|
showDetail = true
|
||||||
} else {
|
} else {
|
||||||
|
// Close swipe
|
||||||
withAnimation(.easeOut(duration: 0.2)) {
|
withAnimation(.easeOut(duration: 0.2)) {
|
||||||
offset = 0
|
offset = 0
|
||||||
isSwiping = false
|
isSwiping = false
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ struct TemplatesView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.task {
|
.task {
|
||||||
await vm.load()
|
await vm.load()
|
||||||
}
|
}
|
||||||
@@ -117,6 +118,8 @@ struct TemplatesView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||||
|
.shadow(color: .black.opacity(0.04), radius: 4, y: 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,13 @@ struct TodayView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
|
// Date selector
|
||||||
dateSelector
|
dateSelector
|
||||||
|
|
||||||
|
// Macro summary
|
||||||
macroSummary
|
macroSummary
|
||||||
|
|
||||||
|
// Meal sections
|
||||||
if vm.entries.isEmpty && !vm.isLoading {
|
if vm.entries.isEmpty && !vm.isLoading {
|
||||||
EmptyStateView(
|
EmptyStateView(
|
||||||
icon: "fork.knife",
|
icon: "fork.knife",
|
||||||
@@ -34,6 +38,7 @@ struct TodayView: View {
|
|||||||
.refreshable {
|
.refreshable {
|
||||||
await vm.load()
|
await vm.load()
|
||||||
}
|
}
|
||||||
|
.background(Color.canvas)
|
||||||
.task {
|
.task {
|
||||||
await vm.load()
|
await vm.load()
|
||||||
}
|
}
|
||||||
@@ -123,7 +128,9 @@ struct TodayView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(16)
|
.padding(16)
|
||||||
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
|
.background(Color.surfaceCard)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||||
|
.shadow(color: .black.opacity(0.04), radius: 6, y: 2)
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ struct HomeView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.top, 16)
|
.padding(.top, 16)
|
||||||
|
|
||||||
// Widget grid
|
// Widget grid — half width, tap to go to fitness
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
Button { selectedTab = 1 } label: {
|
Button { selectedTab = 1 } label: {
|
||||||
calorieWidget
|
calorieWidget
|
||||||
@@ -99,6 +99,7 @@ struct HomeView: View {
|
|||||||
.textCase(.uppercase)
|
.textCase(.uppercase)
|
||||||
.tracking(0.5)
|
.tracking(0.5)
|
||||||
|
|
||||||
|
// Animated ring
|
||||||
ZStack {
|
ZStack {
|
||||||
Circle()
|
Circle()
|
||||||
.stroke(Color.emerald.opacity(0.15), lineWidth: 9)
|
.stroke(Color.emerald.opacity(0.15), lineWidth: 9)
|
||||||
@@ -129,8 +130,14 @@ struct HomeView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.aspectRatio(1, contentMode: .fit)
|
.aspectRatio(1, contentMode: .fit)
|
||||||
.background {
|
.background {
|
||||||
RoundedRectangle(cornerRadius: 20)
|
if vm.hasBackground {
|
||||||
.fill(.ultraThinMaterial)
|
RoundedRectangle(cornerRadius: 16)
|
||||||
|
.fill(.ultraThinMaterial)
|
||||||
|
} else {
|
||||||
|
RoundedRectangle(cornerRadius: 16)
|
||||||
|
.fill(Color.surfaceCard)
|
||||||
|
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
extension Color {
|
extension Color {
|
||||||
// MARK: - Canvas / Background (system-adaptive for Liquid Glass)
|
// MARK: - Canvas / Background
|
||||||
static let canvas = Color(.systemBackground)
|
static let canvas = Color(red: 0.96, green: 0.94, blue: 0.90) // #F5EFE6
|
||||||
|
|
||||||
// MARK: - Accent
|
// MARK: - Accent
|
||||||
static let accentWarm = Color(red: 0.545, green: 0.412, blue: 0.078) // #8B6914
|
static let accentWarm = Color(red: 0.545, green: 0.412, blue: 0.078) // #8B6914
|
||||||
static let emerald = Color(red: 0.020, green: 0.588, blue: 0.412) // #059669
|
static let emerald = Color(red: 0.020, green: 0.588, blue: 0.412) // #059669
|
||||||
|
|
||||||
// MARK: - Surfaces (system-adaptive)
|
// MARK: - Surfaces
|
||||||
static let surfaceCard = Color(.secondarySystemGroupedBackground)
|
static let surfaceCard = Color(red: 255/255, green: 252/255, blue: 248/255) // warm white
|
||||||
static let surfaceSheet = Color(.systemGroupedBackground)
|
static let surfaceSheet = Color(red: 0.98, green: 0.97, blue: 0.95)
|
||||||
|
|
||||||
// MARK: - Text (system-adaptive for Liquid Glass + dark mode)
|
// MARK: - Text
|
||||||
static let textPrimary = Color(.label)
|
static let textPrimary = Color(red: 0.12, green: 0.12, blue: 0.12)
|
||||||
static let textSecondary = Color(.secondaryLabel)
|
static let textSecondary = Color(red: 0.45, green: 0.45, blue: 0.45)
|
||||||
static let textTertiary = Color(.tertiaryLabel)
|
static let textTertiary = Color(red: 0.65, green: 0.65, blue: 0.65)
|
||||||
|
|
||||||
// MARK: - Meal Colors
|
// MARK: - Meal Colors
|
||||||
static let mealBreakfast = Color(red: 1.0, green: 0.72, blue: 0.27) // warm orange
|
static let mealBreakfast = Color(red: 1.0, green: 0.72, blue: 0.27) // warm orange
|
||||||
|
|||||||
Reference in New Issue
Block a user