// ── Quick Timer Sheet ────────────────────────────────────────── // Bottom sheet with one-tap preset timers import SwiftUI struct QuickTimerSheet: View { @EnvironmentObject var store: TimerStore @Environment(\.dismiss) private var dismiss private let presets: [(String, Int, String, UrgencyLevel)] = [ ("1 min", 1, "timer", .gentle), ("3 min", 3, "timer", .gentle), ("5 min", 5, "timer", .gentle), ("10 min", 10, "timer", .standard), ("15 min", 15, "timer", .standard), ("20 min", 20, "timer", .standard), ("25 min", 25, "Pomodoro", .standard), ("30 min", 30, "timer", .standard), ("45 min", 45, "timer", .important), ("1 hour", 60, "timer", .important), ("90 min", 90, "timer", .important), ("2 hours", 120, "timer", .important), ] let columns = [ GridItem(.flexible(), spacing: CMSpacing.md), GridItem(.flexible(), spacing: CMSpacing.md), GridItem(.flexible(), spacing: CMSpacing.md), ] var body: some View { NavigationStack { ZStack { CMColors.bg.ignoresSafeArea() ScrollView { LazyVGrid(columns: columns, spacing: CMSpacing.md) { ForEach(presets, id: \.0) { label, minutes, name, urgency in Button { HapticEngine.tap() let _ = store.addCountdown(CreateCountdownParams( label: "\(label) \(name)", durationSeconds: TimeInterval(minutes * 60), urgency: urgency, cascade: CascadeConfig( preset: minutes >= 30 ? .light : .minimal, intervals: [] ) )) dismiss() } label: { VStack(spacing: CMSpacing.xs) { Text(label) .font(CMFonts.mono(size: 18, weight: .semibold)) .foregroundStyle(CMColors.text) // Time reference if let ref = getTimeReference(minutes: minutes) { Text(ref.replacingOccurrences(of: "About as long as ", with: "")) .font(CMFonts.body(size: 10)) .foregroundStyle(CMColors.textMuted) .lineLimit(1) } } .frame(maxWidth: .infinity) .padding(.vertical, CMSpacing.lg) .background(CMColors.surface) .clipShape(RoundedRectangle(cornerRadius: CMRadius.md)) .overlay( RoundedRectangle(cornerRadius: CMRadius.md) .stroke(CMColors.border, lineWidth: 1) ) } } } .padding(CMSpacing.lg) } } .navigationTitle("Quick Timer") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { dismiss() } .foregroundStyle(CMColors.textSecondary) } } .toolbarBackground(CMColors.surface, for: .navigationBar) .toolbarColorScheme(.dark, for: .navigationBar) } .presentationDetents([.medium, .large]) } }