Created
May 8, 2025 18:56
-
-
Save ryanlintott/13b4eafcca6c2e0e7d72af66cf3cb640 to your computer and use it in GitHub Desktop.
A silly scare sheet that looks like a ghost.
This file contains hidden or 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
// | |
// ShareSheetView.swift | |
// ScareSheet | |
// | |
// Created by Ryan Lintott on 2025-05-08. | |
// | |
import ShapeUp | |
import SwiftUI | |
struct Ghost: Shape { | |
func path(in rect: CGRect) -> Path { | |
var ghost = Path() | |
let eyeWidth = rect.width * 0.1 | |
let eyeSize = CGSize(width: eyeWidth, height: eyeWidth) | |
let mouthWidth = rect.width * 0.2 | |
let mouthHeight = rect.width * 0.25 | |
let mouthSize = CGSize(width: mouthWidth, height: mouthHeight) | |
ghost.move(to: rect[-0.5, 1]) | |
ghost.addCurve(to: rect[0.5, 0], control1: rect[0.5, 0.5], control2: rect[0, 0]) | |
ghost.addCurve(to: rect[1.5, 1], control1: rect[1, 0], control2: rect[0.5, 0.5]) | |
ghost.closeSubpath() | |
let mouth = Ellipse().path(in: .init( | |
origin: rect[0.5, 0.2].moved(dx: -mouthWidth * 0.5), | |
size: mouthSize | |
)) | |
let leftEye = Circle().path(in: .init( | |
origin: rect[0.5 - 0.1, 0.1].moved(dx: -eyeWidth * 0.5), | |
size: eyeSize | |
)) | |
let rightEye = Circle().path(in: .init( | |
origin: rect[0.5 + 0.1, 0.1].moved(dx: -eyeWidth * 0.5), | |
size: eyeSize | |
)) | |
return ghost.subtracting(mouth).subtracting(leftEye).subtracting(rightEye) | |
} | |
} | |
struct ShareSheetView: View { | |
@Environment(\.dismiss) var dismiss | |
@State private var showText = false | |
var body: some View { | |
VStack { | |
Spacer() | |
Text(""" | |
\(Text("Boo!").font(.title)) | |
Still here? | |
If I were you | |
I would definitely leave | |
And never ever ever come back... | |
""") | |
.fontDesign(.serif) | |
.multilineTextAlignment(.center) | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.safeAreaInset(edge: .bottom) { | |
HStack(alignment: .firstTextBaseline) { | |
Button { | |
dismiss() | |
} label: { | |
Label { | |
Text("Run away") | |
.frame(maxWidth: .infinity) | |
} icon: { | |
Image(systemName: "") | |
} | |
} | |
.buttonStyle(.borderedProminent) | |
VStack { | |
Button { | |
fatalError() | |
} label: { | |
Text("Continue") | |
.bold() | |
.foregroundStyle(.red) | |
.padding(.horizontal) | |
} | |
Text("if you dare...") | |
.font(.caption) | |
.fontDesign(.serif) | |
.italic() | |
.foregroundStyle(.gray) | |
.padding(.top, 2) | |
} | |
} | |
.padding() | |
} | |
.background { | |
Ghost() | |
.fill(.white) | |
.ignoresSafeArea(.all, edges: .bottom) | |
} | |
} | |
} | |
#Preview { | |
@Previewable @State var isPresented: Bool = true | |
VStack { | |
Button { | |
isPresented = true | |
} label: { | |
Label { | |
Text("Purchase") | |
} icon: { | |
Image(systemName: "basket") | |
} | |
} | |
.buttonStyle(.borderedProminent) | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background(.black) | |
.fullScreenCover(isPresented: $isPresented) { | |
ShareSheetView() | |
.onTapGesture { | |
isPresented = false | |
} | |
.presentationBackground(.clear) | |
} | |
.environment(\.colorScheme, .dark) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The Ghost Shape uses some helpful extensions from my ShapeUp package