import SwiftUI import SFSafeSymbols import PhoneNumberKit private let emailPattern = #"^\S+@\S+\.\S+$"# struct TopView: View { let info: TopInfo let style: HeaderStyle let accent: Color private let phoneNumberKit = PhoneNumberKit() var isValidEmail: Bool { info.email.range(of: emailPattern, options: .regularExpression) != nil } var isValidPhoneNumber: Bool { do { _ = try phoneNumberKit.parse(info.phone) return true } catch { return false } } var body: some View { GeometryReader { geo in let sideWidth = max(0, (geo.size.width - geo.size.height) / 2) HStack(spacing: 0) { VStack(alignment: .leading, spacing: 0) { Text(info.name) .font(.title) .foregroundColor(accent) Spacer(minLength: 0) Text(info.tagLine) .font(.subheadline) .padding(.trailing, style.imageShadowSize) Spacer(minLength: 0) HStack { RightImageLabel(info.place, systemSymbol: .house) RightImageLabel(info.ageText, systemSymbol: .hourglass) Spacer() }.font(.subheadline) } .frame(width: sideWidth) TopViewImage( image: info.imageName, shadow: style.imageShadowSize, lineWidth: style.imageBorderWidth) VStack(alignment: .trailing) { LeftImageLabel(systemSymbol: .globe) { Link(info.web, destination: URL(string: "https://" + info.web)!) } .frame(maxHeight: style.iconHeight) Spacer() LeftImageLabel(systemSymbol: .envelope) { Link(info.email, destination: URL(string: "mailto:" + info.email)!) .disabled(!isValidEmail) } .frame(maxHeight: style.iconHeight) Spacer() LeftImageLabel(systemSymbol: .phone) { Link(info.phone, destination: URL(string: "tel:" + info.phone)!) .disabled(!isValidPhoneNumber) } .frame(maxHeight: style.iconHeight) Spacer() HStack(spacing: 0) { Spacer() Link(info.github, destination: URL(string: "https://" + info.github)!) Image("Github") .resizable() .aspectRatio(1.0, contentMode: .fit) .padding(2) .frame(width: style.iconHeight) }.frame(maxHeight: style.iconHeight) } .font(.subheadline) .frame(width: sideWidth) .foregroundStyle(.primary) } } } } struct TopView_Previews: PreviewProvider { static var previews: some View { TopView(info: .init( imageName: "Cover", name: "Christoph Hagen", tagLine: "Problem solver with a favour for interdisciplinary work.", place: "Würzburg, Germany", ageText: "Age 32", web: "christophhagen.de", email: "jobs@christophhagen.de", phone: "Upon Request", github: "github.com/christophhagen"), style: HeaderStyle(), accent: .orange) .previewLayout(.fixed(width: 540, height: 120)) } }