// // HoverButton.swift // DynamicIsland // // Created by Kraigo on 04.09.2024. // import SwiftUI struct HoverButton: View { var icon: String var iconColor: Color = .white; var scale: Image.Scale = .medium var pressEffect: PressEffect? = nil var action: () -> Void var contentTransition: ContentTransition = .symbolEffect; @State private var isHovering = false @State private var pressOffset: CGFloat = 0 var body: some View { let size = CGFloat(scale == .large ? 40 : 30) Button(action: { triggerPressEffect() action() }) { Rectangle() .fill(.clear) .contentShape(Rectangle()) .frame(width: size, height: size) .overlay { Capsule() .fill(isHovering ? Color.gray.opacity(0.2) : .clear) .frame(width: size, height: size) .overlay { Image(systemName: icon) .foregroundColor(iconColor) .contentTransition(contentTransition) .font(scale == .large ? .largeTitle : .body) } } } .buttonStyle(PlainButtonStyle()) .offset(x: pressOffset) .onHover { hovering in withAnimation(.smooth(duration: 0.3)) { isHovering = hovering } } } private func triggerPressEffect() { guard let pressEffect else { return } switch pressEffect { case .nudge(let amount): withAnimation(.spring(response: 0.2, dampingFraction: 0.55)) { pressOffset = amount } DispatchQueue.main.asyncAfter(deadline: .now() + 0.16) { withAnimation(.spring(response: 0.28, dampingFraction: 0.72)) { pressOffset = 0 } } } } enum PressEffect { case nudge(CGFloat) } }