Compare commits
9 Commits
f7987bd429
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bad3524cf | ||
|
|
7471f06c52 | ||
|
|
828162ee36 | ||
|
|
f1f770c859 | ||
|
|
abf61463fe | ||
|
|
b0f2bdf430 | ||
|
|
43a1789332 | ||
|
|
d25c8e1207 | ||
|
|
cbc1b51e78 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
.DS_Store
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
880A8C212AFE3B0C000ABBFA /* PhoneNumberKit in Frameworks */ = {isa = PBXBuildFile; productRef = 880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */; };
|
||||
886AD6452AB9CD9100B1A00D /* ColorScheme+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AD6442AB9CD9100B1A00D /* ColorScheme+Extensions.swift */; };
|
||||
E267D1742A8E0DE80069112B /* ResumeBuilderApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1732A8E0DE80069112B /* ResumeBuilderApp.swift */; };
|
||||
E267D1762A8E0DE80069112B /* CV.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1752A8E0DE80069112B /* CV.swift */; };
|
||||
E267D1782A8E0DE90069112B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E267D1772A8E0DE90069112B /* Assets.xcassets */; };
|
||||
@@ -41,6 +43,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
886AD6442AB9CD9100B1A00D /* ColorScheme+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ColorScheme+Extensions.swift"; sourceTree = "<group>"; };
|
||||
E2329BB12A9651E200A1270E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
E267D1702A8E0DE80069112B /* ResumeBuilder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ResumeBuilder.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E267D1732A8E0DE80069112B /* ResumeBuilderApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeBuilderApp.swift; sourceTree = "<group>"; };
|
||||
@@ -82,6 +85,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E267D1882A8E12D60069112B /* SFSafeSymbols in Frameworks */,
|
||||
880A8C212AFE3B0C000ABBFA /* PhoneNumberKit in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -118,6 +122,7 @@
|
||||
E267D17C2A8E0DE90069112B /* ResumeBuilder.entitlements */,
|
||||
E267D1792A8E0DE90069112B /* Preview Content */,
|
||||
E267D1822A8E0F320069112B /* Color+Extension.swift */,
|
||||
886AD6442AB9CD9100B1A00D /* ColorScheme+Extensions.swift */,
|
||||
E267D1932A8E38C60069112B /* Data.swift */,
|
||||
E267D1A52A8EC34B0069112B /* Data */,
|
||||
E267D1BE2A90095D0069112B /* Language */,
|
||||
@@ -217,6 +222,7 @@
|
||||
name = ResumeBuilder;
|
||||
packageProductDependencies = (
|
||||
E267D1872A8E12D60069112B /* SFSafeSymbols */,
|
||||
880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */,
|
||||
);
|
||||
productName = ResumeBuilder;
|
||||
productReference = E267D1702A8E0DE80069112B /* ResumeBuilder.app */;
|
||||
@@ -230,7 +236,7 @@
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1430;
|
||||
LastUpgradeCheck = 1500;
|
||||
TargetAttributes = {
|
||||
E267D16F2A8E0DE80069112B = {
|
||||
CreatedOnToolsVersion = 14.3.1;
|
||||
@@ -248,6 +254,7 @@
|
||||
mainGroup = E267D1672A8E0DE80069112B;
|
||||
packageReferences = (
|
||||
E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */,
|
||||
880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */,
|
||||
);
|
||||
productRefGroup = E267D1712A8E0DE80069112B /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -295,6 +302,7 @@
|
||||
E267D18C2A8E1A890069112B /* TopViewImage.swift in Sources */,
|
||||
E267D19C2A8E45470069112B /* CareerStation.swift in Sources */,
|
||||
E267D1BA2A8F9D9C0069112B /* SkillStyle.swift in Sources */,
|
||||
886AD6452AB9CD9100B1A00D /* ColorScheme+Extensions.swift in Sources */,
|
||||
E267D1AD2A8F694A0069112B /* PublicationView.swift in Sources */,
|
||||
E267D1BC2A8FFF300069112B /* TagView.swift in Sources */,
|
||||
E267D1A02A8E45620069112B /* CVInfo.swift in Sources */,
|
||||
@@ -313,6 +321,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
@@ -342,9 +351,11 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
@@ -373,6 +384,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
@@ -402,9 +414,11 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@@ -431,6 +445,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = H8WR4M6QQ4;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -460,6 +475,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = H8WR4M6QQ4;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -504,6 +520,14 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/marmelroy/PhoneNumberKit";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 3.7.4;
|
||||
};
|
||||
};
|
||||
E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols";
|
||||
@@ -515,6 +539,11 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */;
|
||||
productName = PhoneNumberKit;
|
||||
};
|
||||
E267D1872A8E12D60069112B /* SFSafeSymbols */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */;
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "phonenumberkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/marmelroy/PhoneNumberKit",
|
||||
"state" : {
|
||||
"revision" : "b456f2f9be10c1d183158220b831afd22697dd68",
|
||||
"version" : "3.7.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sfsafesymbols",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
||||
BIN
ResumeBuilder.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
BIN
ResumeBuilder.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>ResumeBuilder.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,6 +1,9 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CV: View {
|
||||
|
||||
@Environment(\.colorScheme)
|
||||
var colorScheme: ColorScheme
|
||||
|
||||
let info: CVInfo
|
||||
|
||||
@@ -61,7 +64,7 @@ struct CV: View {
|
||||
Spacer(minLength: 0)
|
||||
Text(info.footer)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundColor(colorScheme.secondaryColor)
|
||||
}
|
||||
.padding()
|
||||
.aspectRatio(1 / sqrt(2), contentMode: .fit)
|
||||
|
||||
@@ -13,4 +13,20 @@ extension Color {
|
||||
init(_ r: Double, _ g: Double, _ b: Double) {
|
||||
self.init(red: r, green: g, blue: b)
|
||||
}
|
||||
|
||||
static var lightSchemePrimaryColor: Color {
|
||||
.init(r: 1, g: 1, b: 1)
|
||||
}
|
||||
|
||||
static var darkSchemePrimaryColor: Color {
|
||||
.init(r: 224, g: 224, b: 224)
|
||||
}
|
||||
|
||||
static var lightSchemeSecondaryColor: Color {
|
||||
.init(r: 128, g: 128, b: 128)
|
||||
}
|
||||
|
||||
static var darkSchemeSecondaryColor: Color {
|
||||
.init(r: 161, g: 161, b: 161)
|
||||
}
|
||||
}
|
||||
|
||||
13
ResumeBuilder/ColorScheme+Extensions.swift
Normal file
13
ResumeBuilder/ColorScheme+Extensions.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
extension ColorScheme {
|
||||
|
||||
var primaryColor: Color {
|
||||
self == .light ? .lightSchemePrimaryColor : .darkSchemePrimaryColor
|
||||
}
|
||||
|
||||
var secondaryColor: Color {
|
||||
self == .light ? .lightSchemeSecondaryColor : .darkSchemeSecondaryColor
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ struct ContentView: View {
|
||||
}) {
|
||||
Label("Export", systemSymbol: .squareAndArrowDown)
|
||||
.padding(3)
|
||||
.frame(maxHeight: 20)
|
||||
}.confirmationDialog(
|
||||
"Which format would you like?",
|
||||
isPresented: $showExportFormatPicker
|
||||
@@ -65,6 +66,7 @@ struct ContentView: View {
|
||||
Button(action: importData) {
|
||||
Label("Import", systemSymbol: .docBadgePlus)
|
||||
.padding(8)
|
||||
.frame(maxHeight: 20)
|
||||
}
|
||||
Spacer()
|
||||
Toggle("Dark mode", isOn: $darkModeEnabled)
|
||||
@@ -205,7 +207,7 @@ struct ContentView: View {
|
||||
private var renderContent: some View {
|
||||
CV(info: info, style: style)
|
||||
.frame(width: style.pageWidth, height: style.pageHeight)
|
||||
.preferredColorScheme(.dark)
|
||||
.preferredColorScheme(colorStyle)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
||||
@@ -32,13 +32,19 @@ let cvInfoEnglish = CVInfo(
|
||||
imageName: "Cover",
|
||||
name: "Christoph Hagen",
|
||||
tagLine: "Problem solver and creative mind with a favour for interdisciplinary work.",
|
||||
place: "Würzburg, Germany",
|
||||
ageText: "Age 32",
|
||||
place: "Munich, Germany",
|
||||
ageText: "Age 33",
|
||||
web: "christophhagen.de",
|
||||
email: "jobs@christophhagen.de",
|
||||
phone: "Upon Request",
|
||||
github: "github.com/christophhagen"),
|
||||
work: .init(title: "Work experience", items: [
|
||||
CareerStation(
|
||||
time: "May 2024 - Present",
|
||||
location: "Oberpfaffenhofen, Germany",
|
||||
title: "German Aerospace Center",
|
||||
subtitle: "Software Developer",
|
||||
text: "Development of the mission control system of the LUNA moon simulator hall for robotic experiments and astronaut training."),
|
||||
CareerStation(
|
||||
time: "Jul 2020 - Jul 2023",
|
||||
location: "Braunschweig, Germany",
|
||||
@@ -57,12 +63,6 @@ let cvInfoEnglish = CVInfo(
|
||||
title: "National Institute of Informatics",
|
||||
subtitle: "Research Intern (Intelligent Robotics)",
|
||||
text: "Topic: Concept Acquisition through interactions between Humans and Robots"),
|
||||
CareerStation(
|
||||
time: "Sep 2014 - Nov 2016",
|
||||
location: "Würzburg, Germany",
|
||||
title: "Julius-Maximilians-Universität",
|
||||
subtitle: "Research & Teaching Assistant",
|
||||
text: "Teaching exercises and robotics workshops, design of a modular robot arm connector.")
|
||||
]),
|
||||
education: .init(title: "Education", items: [
|
||||
CareerStation(
|
||||
@@ -124,13 +124,19 @@ let cvInfoGerman = CVInfo(
|
||||
imageName: "Cover",
|
||||
name: "Christoph Hagen",
|
||||
tagLine: "Problemlöser und kreativer Kopf mit einer Vorliebe für interdisziplinäre Arbeit.",
|
||||
place: "Würzburg",
|
||||
ageText: "32 Jahre",
|
||||
place: "München",
|
||||
ageText: "33 Jahre",
|
||||
web: "christophhagen.de",
|
||||
email: "jobs@christophhagen.de",
|
||||
phone: "Auf Anfrage",
|
||||
github: "github.com/christophhagen"),
|
||||
work: .init(title: "Berufserfahrung", items: [
|
||||
CareerStation(
|
||||
time: "Mai 2024 - Heute",
|
||||
location: "Oberpfaffenhofen",
|
||||
title: "Deutsches Zentrum für Luft- und Raumfahrt",
|
||||
subtitle: "Softwareentwickler",
|
||||
text: "Entwicklung des Missionskontrollsystems der LUNA Mondsimulationshalle für robotische Experimente und Astronautentraining."),
|
||||
CareerStation(
|
||||
time: "Jul 2020 - Jul 2023",
|
||||
location: "Braunschweig",
|
||||
@@ -147,14 +153,8 @@ let cvInfoGerman = CVInfo(
|
||||
time: "Jul 2017 - Okt 2017",
|
||||
location: "Tokio, Japan",
|
||||
title: "National Institute of Informatics",
|
||||
subtitle: "Research Intern (Intelligent Robotics)",
|
||||
text: "Thema: Concept Acquisition through interactions between Humans and Robots"),
|
||||
CareerStation(
|
||||
time: "Sep 2014 - Nov 2016",
|
||||
location: "Würzburg",
|
||||
title: "Julius-Maximilians-Universität",
|
||||
subtitle: "Research & Teaching Assistant",
|
||||
text: "Leitung von Übungen und Robotikworkshops, Entwurf einer modularen Verbindung für einen Roboterarm.")
|
||||
subtitle: "Praktikant (Intelligente Robotik)",
|
||||
text: "Thema: Concept Acquisition through interactions between Humans and Robots")
|
||||
]),
|
||||
education: .init(title: "Bildung", items: [
|
||||
CareerStation(
|
||||
|
||||
@@ -3,6 +3,9 @@ import SFSafeSymbols
|
||||
|
||||
struct CareerStationView: View {
|
||||
|
||||
@Environment(\.colorScheme)
|
||||
var colorScheme: ColorScheme
|
||||
|
||||
let info: CareerStation
|
||||
|
||||
let borderSpacing: CGFloat
|
||||
@@ -20,7 +23,7 @@ struct CareerStationView: View {
|
||||
RightImageLabel(info.location, systemSymbol: .house)
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundColor(colorScheme.secondaryColor)
|
||||
Text(info.title)
|
||||
.font(.headline)
|
||||
.fontWeight(.regular)
|
||||
@@ -32,7 +35,7 @@ struct CareerStationView: View {
|
||||
if let text = info.text {
|
||||
Text(text)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundColor(colorScheme.secondaryColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PublicationView: View {
|
||||
|
||||
|
||||
@Environment(\.colorScheme)
|
||||
var colorScheme: ColorScheme
|
||||
|
||||
let info: Publication
|
||||
|
||||
let borderSpacing: CGFloat
|
||||
@@ -15,10 +18,11 @@ struct PublicationView: View {
|
||||
VStack(alignment: .leading) {
|
||||
Text(info.venue)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundColor(colorScheme.secondaryColor)
|
||||
Text(info.title)
|
||||
.font(.subheadline)
|
||||
.fontWeight(.regular)
|
||||
.foregroundColor(colorScheme.primaryColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
|
||||
struct LeftImageLabel: View {
|
||||
|
||||
let text: String
|
||||
struct LeftImageLabel<Content>: View where Content: View {
|
||||
|
||||
let systemSymbol: SFSymbol
|
||||
|
||||
let content: Content
|
||||
|
||||
init(_ text: String, systemSymbol: SFSymbol) {
|
||||
self.text = text
|
||||
init(systemSymbol: SFSymbol, @ViewBuilder content: () -> Content) {
|
||||
self.systemSymbol = systemSymbol
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 0) {
|
||||
Text(text)
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
content
|
||||
Image(systemSymbol: systemSymbol)
|
||||
.frame(width: 20)
|
||||
}
|
||||
@@ -23,6 +23,6 @@ struct LeftImageLabel: View {
|
||||
|
||||
struct LeftImageLabel_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
LeftImageLabel("Home address", systemSymbol: .house)
|
||||
LeftImageLabel(systemSymbol: .house) { Text("Home address") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TitledTextSection: View {
|
||||
|
||||
@Environment(\.colorScheme)
|
||||
var colorScheme: ColorScheme
|
||||
|
||||
let content: Titled<String>
|
||||
|
||||
@@ -8,6 +11,10 @@ struct TitledTextSection: View {
|
||||
|
||||
let paragraphSpacing: CGFloat
|
||||
|
||||
private var textColor: Color {
|
||||
colorScheme == .light ? .lightSchemePrimaryColor : .darkSchemePrimaryColor
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TitledSection(title: content.title, spacing: titleSpacing) {
|
||||
ForEach(content.items) { text in
|
||||
@@ -15,6 +22,7 @@ struct TitledTextSection: View {
|
||||
.font(.body)
|
||||
.fontWeight(.light)
|
||||
.padding(.bottom, paragraphSpacing)
|
||||
.foregroundColor(textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import SwiftUI
|
||||
import SFSafeSymbols
|
||||
import PhoneNumberKit
|
||||
|
||||
private let emailPattern = #"^\S+@\S+\.\S+$"#
|
||||
|
||||
struct TopView: View {
|
||||
|
||||
@@ -8,6 +11,21 @@ struct TopView: View {
|
||||
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
|
||||
@@ -34,18 +52,30 @@ struct TopView: View {
|
||||
shadow: style.imageShadowSize,
|
||||
lineWidth: style.imageBorderWidth)
|
||||
VStack(alignment: .trailing) {
|
||||
LeftImageLabel(info.web, systemSymbol: .globe)
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
LeftImageLabel(systemSymbol: .globe) {
|
||||
Text(info.web)
|
||||
//Link(info.web, destination: URL(string: "https://" + info.web)!)
|
||||
}
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
Spacer()
|
||||
LeftImageLabel(info.email, systemSymbol: .envelope)
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
LeftImageLabel(systemSymbol: .envelope) {
|
||||
Text(info.email)
|
||||
//Link(info.email, destination: URL(string: "mailto:" + info.email)!)
|
||||
//.disabled(!isValidEmail)
|
||||
}
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
Spacer()
|
||||
LeftImageLabel(info.phone, systemSymbol: .phone)
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
LeftImageLabel(systemSymbol: .phone) {
|
||||
Text(info.phone)
|
||||
//Link(info.phone, destination: URL(string: "tel:" + info.phone)!)
|
||||
//.disabled(!isValidPhoneNumber)
|
||||
}
|
||||
.frame(maxHeight: style.iconHeight)
|
||||
Spacer()
|
||||
HStack(spacing: 0) {
|
||||
Spacer()
|
||||
Text(info.github)
|
||||
//Link(info.github, destination: URL(string: "https://" + info.github)!)
|
||||
Image("Github")
|
||||
.resizable()
|
||||
.aspectRatio(1.0, contentMode: .fit)
|
||||
@@ -55,6 +85,7 @@ struct TopView: View {
|
||||
}
|
||||
.font(.subheadline)
|
||||
.frame(width: sideWidth)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user