import SwiftUI // MARK: - PulsingRecordButton /// A minimalist, line-drawn record button suitable for a business productivity app. /// Completely avoids heavy neon glows, replacing them with thin outlines, a clean scale animation, /// and an outline mic icon. struct PulsingRecordButton: View { /// Closure triggered on tap. let action: () -> Void var body: some View { TimelineView(.animation(minimumInterval: 1.0 / 30.0)) { context in let time = context.date.timeIntervalSinceReferenceDate let breathingPhase = (sin(time * .pi) + 1) / 2 let ripplePhase = time.truncatingRemainder(dividingBy: 2.5) / 2.5 ZStack { // These transforms are derived directly from time instead of // using a repeating implicit animation. That keeps SwiftUI from // accidentally animating parent layout changes after a cover or // app lifecycle transition. Circle() .stroke(Color.primary.opacity(0.1), lineWidth: 1) .frame(width: 120, height: 120) .scaleEffect(0.98 + breathingPhase * 0.10) Circle() .stroke(Color.primary.opacity(0.08), lineWidth: 1) .frame(width: 100, height: 100) .scaleEffect(1.0 + ripplePhase * 0.25) .opacity(0.8 * (1.0 - ripplePhase)) Circle() .fill(Color.primary.opacity(0.03)) .frame(width: 90, height: 90) .overlay( Circle() .stroke(Color.primary.opacity(0.2), lineWidth: 1) ) Image(systemName: "mic") .font(.system(size: 24, weight: .light)) .foregroundColor(.primary) .scaleEffect(0.98 + breathingPhase * 0.04) } } .frame(width: 120, height: 120) .contentShape(Circle()) .onTapGesture { HapticManager.trigger(.recordStart) action() } } } // MARK: - Preview #Preview { ZStack { Color.spaceBlack.ignoresSafeArea() PulsingRecordButton { print("Record tapped") } } }