vibetunnel/ios/VibeTunnel/Views/Terminal/ScrollToBottomButton.swift
2025-06-23 14:58:11 +02:00

77 lines
2.7 KiB
Swift

import SwiftUI
private let logger = Logger(category: "ScrollToBottomButton")
/// Floating action button to scroll terminal to bottom
struct ScrollToBottomButton: View {
let isVisible: Bool
let action: () -> Void
@State private var isHovered = false
@State private var isPressed = false
var body: some View {
Button(action: {
HapticFeedback.impact(.light)
action()
}, label: {
Text("")
.font(.system(size: 24, weight: .bold))
.foregroundColor(isHovered ? Theme.Colors.primaryAccent : Theme.Colors.terminalForeground)
.frame(width: 48, height: 48)
.background(
Circle()
.fill(isHovered ? Theme.Colors.cardBackground : Theme.Colors.cardBackground.opacity(0.8))
.overlay(
Circle()
.stroke(
isHovered ? Theme.Colors.primaryAccent : Theme.Colors.cardBorder,
lineWidth: isHovered ? 2 : 1
)
)
)
.shadow(
color: isHovered ? Theme.Colors.primaryAccent.opacity(0.3) : .black.opacity(0.3),
radius: isHovered ? 12 : 8,
x: 0,
y: isHovered ? 3 : 4
)
.scaleEffect(isPressed ? 0.95 : 1.0)
.offset(y: isHovered && !isPressed ? -1 : 0)
})
.buttonStyle(PlainButtonStyle())
.opacity(isVisible ? 1 : 0)
.scaleEffect(isVisible ? 1 : 0.8)
.animation(Theme.Animation.quick, value: isHovered)
.animation(Theme.Animation.quick, value: isPressed)
.animation(Theme.Animation.smooth, value: isVisible)
.allowsHitTesting(isVisible)
.onLongPressGesture(minimumDuration: 0, maximumDistance: .infinity) { pressing in
isPressed = pressing
} perform: {
// Action handled by button
}
.onHover { hovering in
isHovered = hovering
}
}
}
// Note: Use ScrollToBottomButton directly with overlay instead of this extension
// Example:
// .overlay(
// ScrollToBottomButton(isVisible: showButton, action: { })
// .padding(.bottom, Theme.Spacing.large)
// .padding(.leading, Theme.Spacing.large),
// alignment: .bottomLeading
// )
#Preview {
ZStack {
Theme.Colors.terminalBackground
.ignoresSafeArea()
ScrollToBottomButton(isVisible: true) {
logger.debug("Scroll to bottom")
}
}
}