Created
February 23, 2025 14:03
-
-
Save Shriram-Vasudevan/3f0e34c0cdb6bd3e4435a5492f5da37e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct CurvedSheed: View { | |
@Binding var isOpen: Bool | |
@State private var sheetOffset: CGFloat = 1000 | |
@State private var backgroundOpacity: Double = 0 | |
var body: some View { | |
ZStack { | |
// Background overlay | |
Color.black | |
.opacity(backgroundOpacity) | |
.ignoresSafeArea() | |
.onTapGesture { dismiss() } | |
// Sheet content | |
VStack(spacing: 0) { | |
Spacer() | |
// Curved top shape | |
CurveShape() | |
.fill(Color(.systemGray6)) | |
.frame(height: 24) | |
// Content | |
VStack(spacing: 16) { | |
// Handle indicator | |
RoundedRectangle(cornerRadius: 2.5) | |
.fill(Color(.systemGray3)) | |
.frame(width: 36, height: 5) | |
.padding(.top, 8) | |
// Top row - 2 cards | |
HStack(spacing: 12) { | |
Spacer() | |
MinimalCard( | |
icon: "", | |
title: "" | |
) { | |
//Action | |
} | |
MinimalCard( | |
icon: "", | |
title: "" | |
) { | |
//Action | |
} | |
Spacer() | |
} | |
.padding(.horizontal, 24) | |
HStack(spacing: 12) { | |
MinimalCard( | |
icon: "", | |
title: "" | |
) { | |
//Action | |
} | |
MinimalCard( | |
icon: "", | |
title: "" | |
) { | |
//Action | |
} | |
MinimalCard( | |
icon: "", | |
title: "" | |
) { | |
//Action | |
} | |
} | |
.padding(.horizontal, 24) | |
// Close button | |
Button(action: dismiss) { | |
Circle() | |
.fill(Color(.systemGray6)) | |
.frame(width: 44, height: 44) | |
.overlay( | |
Image(systemName: "xmark") | |
.font(.system(size: 17, weight: .medium)) | |
.foregroundColor(.primary) | |
) | |
} | |
.padding(.top, 8) | |
.padding(.bottom, 16) | |
} | |
.background(Color(.systemGray6)) | |
} | |
.offset(y: sheetOffset) | |
.edgesIgnoringSafeArea(.bottom) | |
} | |
.onAppear { animateEntry() } | |
} | |
private func animateEntry() { | |
withAnimation(.spring(response: 0.6, dampingFraction: 0.8)) { | |
sheetOffset = 0 | |
backgroundOpacity = 0.5 | |
} | |
} | |
private func dismiss() { | |
withAnimation(.spring(response: 0.6, dampingFraction: 0.8)) { | |
sheetOffset = 1000 | |
backgroundOpacity = 0 | |
} | |
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { | |
isOpen = false | |
} | |
} | |
} | |
struct CurveShape: Shape { | |
func path(in rect: CGRect) -> Path { | |
var path = Path() | |
path.move(to: CGPoint(x: 0, y: 24)) | |
let center = rect.width / 2 | |
path.addCurve( | |
to: CGPoint(x: rect.width, y: 24), | |
control1: CGPoint(x: center - 80, y: 0), | |
control2: CGPoint(x: center + 80, y: 0) | |
) | |
path.addLine(to: CGPoint(x: rect.width, y: rect.height)) | |
path.addLine(to: CGPoint(x: 0, y: rect.height)) | |
path.closeSubpath() | |
return path | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment