|
@@ -64,6 +64,45 @@ struct AppSecondaryButtonStyle: ButtonStyle {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+struct AppDestructiveButtonStyle: ButtonStyle {
|
|
|
|
|
+ private static let destructiveColor = Color(hex: 0xEF4444)
|
|
|
|
|
+
|
|
|
|
|
+ @State private var isHovered = false
|
|
|
|
|
+
|
|
|
|
|
+ func makeBody(configuration: Configuration) -> some View {
|
|
|
|
|
+ configuration.label
|
|
|
|
|
+ .foregroundStyle(Self.destructiveColor)
|
|
|
|
|
+ .padding(.horizontal, 12)
|
|
|
|
|
+ .padding(.vertical, 8)
|
|
|
|
|
+ .background(destructiveBackground(isPressed: configuration.isPressed))
|
|
|
|
|
+ .clipShape(RoundedRectangle(cornerRadius: 8))
|
|
|
|
|
+ .overlay(
|
|
|
|
|
+ RoundedRectangle(cornerRadius: 8)
|
|
|
|
|
+ .stroke(
|
|
|
|
|
+ isHovered || configuration.isPressed
|
|
|
|
|
+ ? Self.destructiveColor.opacity(0.55)
|
|
|
|
|
+ : Self.destructiveColor.opacity(0.25),
|
|
|
|
|
+ lineWidth: 1
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ .scaleEffect(configuration.isPressed ? AppTheme.hoverPressScale : (isHovered ? AppTheme.hoverLiftScale : 1))
|
|
|
|
|
+ .animation(AppTheme.hoverAnimation, value: isHovered)
|
|
|
|
|
+ .animation(AppTheme.hoverAnimation, value: configuration.isPressed)
|
|
|
|
|
+ .onHover { isHovered = $0 }
|
|
|
|
|
+ .hoverCursor()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func destructiveBackground(isPressed: Bool) -> Color {
|
|
|
|
|
+ if isPressed {
|
|
|
|
|
+ return Self.destructiveColor.opacity(0.18)
|
|
|
|
|
+ }
|
|
|
|
|
+ if isHovered {
|
|
|
|
|
+ return Self.destructiveColor.opacity(0.12)
|
|
|
|
|
+ }
|
|
|
|
|
+ return Self.destructiveColor.opacity(0.08)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
struct AppPrimaryButtonStyle: ButtonStyle {
|
|
struct AppPrimaryButtonStyle: ButtonStyle {
|
|
|
@State private var isHovered = false
|
|
@State private var isHovered = false
|
|
|
|
|
|