refactor: redesign planning mode picker as 2x2 card grid
Replace crowded segmented control with clean card-based grid. Each card shows icon and label with selected state highlight. Fixes text truncation issue with "Follow Team" option. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -212,17 +212,25 @@ struct TripCreationView: View {
|
||||
|
||||
private var planningModeSection: some View {
|
||||
ThemedSection(title: "How do you want to plan?") {
|
||||
Picker("Planning Mode", selection: $viewModel.planningMode) {
|
||||
LazyVGrid(
|
||||
columns: [
|
||||
GridItem(.flexible(), spacing: Theme.Spacing.sm),
|
||||
GridItem(.flexible(), spacing: Theme.Spacing.sm)
|
||||
],
|
||||
spacing: Theme.Spacing.sm
|
||||
) {
|
||||
ForEach(PlanningMode.allCases) { mode in
|
||||
Text(mode.displayName).tag(mode)
|
||||
PlanningModeCard(
|
||||
mode: mode,
|
||||
isSelected: viewModel.planningMode == mode,
|
||||
colorScheme: colorScheme
|
||||
) {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
viewModel.planningMode = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
|
||||
Text(viewModel.planningMode.description)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(Theme.textSecondary(colorScheme))
|
||||
.padding(.top, Theme.Spacing.xs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2384,6 +2392,55 @@ struct TeamPickerSheet: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Planning Mode Card
|
||||
|
||||
struct PlanningModeCard: View {
|
||||
let mode: PlanningMode
|
||||
let isSelected: Bool
|
||||
let colorScheme: ColorScheme
|
||||
let onTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
VStack(spacing: Theme.Spacing.sm) {
|
||||
// Icon
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(isSelected ? Theme.warmOrange : Theme.warmOrange.opacity(0.15))
|
||||
.frame(width: 44, height: 44)
|
||||
|
||||
Image(systemName: mode.iconName)
|
||||
.font(.system(size: 20, weight: .semibold))
|
||||
.foregroundStyle(isSelected ? .white : Theme.warmOrange)
|
||||
}
|
||||
|
||||
// Title
|
||||
Text(mode.displayName)
|
||||
.font(.subheadline.weight(.medium))
|
||||
.foregroundStyle(Theme.textPrimary(colorScheme))
|
||||
.lineLimit(1)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, Theme.Spacing.md)
|
||||
.padding(.horizontal, Theme.Spacing.sm)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
|
||||
.fill(Theme.cardBackgroundElevated(colorScheme))
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)
|
||||
.strokeBorder(
|
||||
isSelected ? Theme.warmOrange : Color.clear,
|
||||
lineWidth: 2
|
||||
)
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("\(mode.displayName): \(mode.description)")
|
||||
.accessibilityAddTraits(isSelected ? .isSelected : [])
|
||||
}
|
||||
}
|
||||
|
||||
struct TeamRow: View {
|
||||
let team: Team
|
||||
let isSelected: Bool
|
||||
|
||||
Reference in New Issue
Block a user