|
@@ -4,6 +4,8 @@ struct GradientButton: View {
|
|
|
let title: String
|
|
let title: String
|
|
|
let action: () -> Void
|
|
let action: () -> Void
|
|
|
|
|
|
|
|
|
|
+ @State private var isHovered = false
|
|
|
|
|
+
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
Button(action: action) {
|
|
Button(action: action) {
|
|
|
HStack(spacing: 10) {
|
|
HStack(spacing: 10) {
|
|
@@ -21,11 +23,18 @@ struct GradientButton: View {
|
|
|
.padding(.horizontal, 28)
|
|
.padding(.horizontal, 28)
|
|
|
.padding(.vertical, 15)
|
|
.padding(.vertical, 15)
|
|
|
.frame(maxWidth: .infinity)
|
|
.frame(maxWidth: .infinity)
|
|
|
- .background(AppTheme.primaryGradient)
|
|
|
|
|
|
|
+ .background(isHovered ? AppTheme.primaryGradientHover : AppTheme.primaryGradient)
|
|
|
.clipShape(RoundedRectangle(cornerRadius: AppTheme.buttonCornerRadius))
|
|
.clipShape(RoundedRectangle(cornerRadius: AppTheme.buttonCornerRadius))
|
|
|
- .shadow(color: AppTheme.teal.opacity(0.30), radius: 10, y: 4)
|
|
|
|
|
|
|
+ .shadow(
|
|
|
|
|
+ color: isHovered ? AppTheme.primaryShadowHover : AppTheme.primaryShadow,
|
|
|
|
|
+ radius: isHovered ? 14 : 10,
|
|
|
|
|
+ y: isHovered ? 6 : 4
|
|
|
|
|
+ )
|
|
|
|
|
+ .scaleEffect(isHovered ? 1.02 : 1.0)
|
|
|
|
|
+ .animation(.easeOut(duration: 0.15), value: isHovered)
|
|
|
}
|
|
}
|
|
|
.buttonStyle(.plain)
|
|
.buttonStyle(.plain)
|
|
|
|
|
+ .onHover { isHovered = $0 }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -34,6 +43,8 @@ struct ToolbarButton: View {
|
|
|
let iconName: String
|
|
let iconName: String
|
|
|
let action: () -> Void
|
|
let action: () -> Void
|
|
|
|
|
|
|
|
|
|
+ @State private var isHovered = false
|
|
|
|
|
+
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
Button(action: action) {
|
|
Button(action: action) {
|
|
|
HStack(spacing: 6) {
|
|
HStack(spacing: 6) {
|
|
@@ -43,18 +54,25 @@ struct ToolbarButton: View {
|
|
|
Text(title)
|
|
Text(title)
|
|
|
.font(.system(size: 12, weight: .medium))
|
|
.font(.system(size: 12, weight: .medium))
|
|
|
}
|
|
}
|
|
|
- .foregroundStyle(AppTheme.textSecondary)
|
|
|
|
|
|
|
+ .foregroundStyle(isHovered ? AppTheme.toolbarForegroundHover : AppTheme.textSecondary)
|
|
|
.padding(.horizontal, 12)
|
|
.padding(.horizontal, 12)
|
|
|
.padding(.vertical, 7)
|
|
.padding(.vertical, 7)
|
|
|
- .background(Color.white)
|
|
|
|
|
|
|
+ .background(isHovered ? AppTheme.toolbarBackgroundHover : Color.white)
|
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
|
.overlay(
|
|
.overlay(
|
|
|
RoundedRectangle(cornerRadius: 8)
|
|
RoundedRectangle(cornerRadius: 8)
|
|
|
- .stroke(AppTheme.border, lineWidth: 1)
|
|
|
|
|
|
|
+ .stroke(isHovered ? AppTheme.toolbarBorderHover : AppTheme.border, lineWidth: 1)
|
|
|
)
|
|
)
|
|
|
- .shadow(color: Color.black.opacity(0.03), radius: 2, y: 1)
|
|
|
|
|
|
|
+ .shadow(
|
|
|
|
|
+ color: isHovered ? AppTheme.toolbarShadowHover : AppTheme.toolbarShadow,
|
|
|
|
|
+ radius: isHovered ? 4 : 2,
|
|
|
|
|
+ y: isHovered ? 2 : 1
|
|
|
|
|
+ )
|
|
|
|
|
+ .scaleEffect(isHovered ? 1.02 : 1.0)
|
|
|
|
|
+ .animation(.easeOut(duration: 0.15), value: isHovered)
|
|
|
}
|
|
}
|
|
|
.buttonStyle(.plain)
|
|
.buttonStyle(.plain)
|
|
|
|
|
+ .onHover { isHovered = $0 }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -62,21 +80,30 @@ struct IconButton: View {
|
|
|
let iconName: String
|
|
let iconName: String
|
|
|
let action: () -> Void
|
|
let action: () -> Void
|
|
|
|
|
|
|
|
|
|
+ @State private var isHovered = false
|
|
|
|
|
+
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
Button(action: action) {
|
|
Button(action: action) {
|
|
|
Image(systemName: iconName)
|
|
Image(systemName: iconName)
|
|
|
.font(.system(size: 14))
|
|
.font(.system(size: 14))
|
|
|
- .foregroundStyle(AppTheme.textSecondary)
|
|
|
|
|
|
|
+ .foregroundStyle(isHovered ? AppTheme.toolbarForegroundHover : AppTheme.textSecondary)
|
|
|
.frame(width: 36, height: 36)
|
|
.frame(width: 36, height: 36)
|
|
|
- .background(Color.white)
|
|
|
|
|
|
|
+ .background(isHovered ? AppTheme.toolbarBackgroundHover : Color.white)
|
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
|
.overlay(
|
|
.overlay(
|
|
|
RoundedRectangle(cornerRadius: 8)
|
|
RoundedRectangle(cornerRadius: 8)
|
|
|
- .stroke(AppTheme.border, lineWidth: 1)
|
|
|
|
|
|
|
+ .stroke(isHovered ? AppTheme.toolbarBorderHover : AppTheme.border, lineWidth: 1)
|
|
|
)
|
|
)
|
|
|
- .shadow(color: Color.black.opacity(0.04), radius: 3, y: 1)
|
|
|
|
|
|
|
+ .shadow(
|
|
|
|
|
+ color: isHovered ? AppTheme.toolbarShadowHover : AppTheme.toolbarShadow,
|
|
|
|
|
+ radius: isHovered ? 5 : 3,
|
|
|
|
|
+ y: isHovered ? 2 : 1
|
|
|
|
|
+ )
|
|
|
|
|
+ .scaleEffect(isHovered ? 1.02 : 1.0)
|
|
|
|
|
+ .animation(.easeOut(duration: 0.15), value: isHovered)
|
|
|
}
|
|
}
|
|
|
.buttonStyle(.plain)
|
|
.buttonStyle(.plain)
|
|
|
|
|
+ .onHover { isHovered = $0 }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|