App layout improvements #10

Merged
javier merged 5 commits from app/app-layout into main 2026-02-12 03:55:17 +00:00
Showing only changes of commit 1e7e498b47 - Show all commits
@@ -0,0 +1,98 @@
import SwiftUI
/// A view modifier that adds a floating action button for creating new tasks.
///
/// This modifier overlays a glass-effect button in the bottom-trailing corner of the view.
/// The button can be conditionally shown or hidden with smooth animations.
struct NewTaskButtonModifier: ViewModifier {
// MARK: Properties
/// Whether the floating button should be displayed.
let showButton: Bool
/// The action to perform when the button is tapped.
let action: () -> Void
// MARK: Functions
/// Applies the floating action button to the content view.
///
/// When `showButton` is true, overlays a blue glass-effect button with a plus icon
/// in the bottom-trailing corner. The button animates in/out with opacity and scale transitions,
/// and includes a spring animation when pressed.
///
/// - Parameter content: The view to which the button will be added.
/// - Returns: The modified view with the floating button overlay.
func body(content: Content) -> some View {
ZStack(alignment: .bottomTrailing) {
content
if showButton {
Button(action: action) {
Image(systemName: "plus")
.frame(width: 48, height: 48)
.foregroundStyle(.white)
}
.glassEffect(.regular.tint(.blue.opacity(0.8)).interactive())
.padding(.trailing, 20)
}
}
.animation(
.spring(response: 0.4, dampingFraction: 0.8),
value: showButton
)
}
}
// MARK: - View Extension
extension View {
/// Adds a floating action button for creating new tasks.
///
/// This convenience method applies the ``NewTaskButtonModifier`` to show a glass-effect
/// button in the bottom-trailing corner of the view.
///
/// - Parameters:
/// - show: Whether the floating button should be displayed.
/// - action: The action to perform when the button is tapped.
/// - Returns: The modified view with the floating button overlay.
func newTaskButton(
show: Bool,
action: @escaping () -> Void
) -> some View {
modifier(
NewTaskButtonModifier(
showButton: show,
action: action
)
)
}
}
// MARK: - Previews
#Preview("New Task Button") {
@Previewable
@State
var showButton = true
VStack {
Spacer()
Toggle(
"Show Button",
isOn: $showButton
)
Spacer()
}
.padding(.horizontal)
.frame(
maxWidth: .infinity,
maxHeight: .infinity
)
.newTaskButton(show: showButton) {
// On action closure.
}
}