Compare commits

...

11 Commits

Author SHA1 Message Date
Christoph Hagen
5bad3524cf Update Data.swift 2025-01-31 22:17:30 +01:00
Christoph Hagen
7471f06c52 Don't use links until bug is fixed 2023-12-05 14:47:52 +01:00
Christoph Hagen
828162ee36 Create .gitignore 2023-12-03 09:23:55 +01:00
Christoph Hagen
f1f770c859 Update city 2023-12-03 09:23:47 +01:00
Christoph Hagen
abf61463fe Fix button heights 2023-11-10 13:46:43 +01:00
Christoph Hagen
b0f2bdf430 Add links for email, phone and domain 2023-11-10 11:22:49 +01:00
Christoph Hagen
43a1789332 Fix wrong colors in PDF export 2023-09-19 14:50:20 +02:00
Christoph Hagen
d25c8e1207 Update data 2023-09-19 13:51:34 +02:00
Christoph Hagen
cbc1b51e78 Update roles 2023-08-24 15:34:46 +02:00
Christoph Hagen
f7987bd429 Add roadmap 2023-08-23 17:27:31 +02:00
Christoph Hagen
f38ca55e4c Update icon 2023-08-23 17:27:24 +02:00
38 changed files with 186 additions and 49 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.DS_Store

BIN
Icon.key

Binary file not shown.

View File

@@ -14,3 +14,6 @@ Problems:
- The `ImageRenderer` sometimes renders text in the wrong color (seems to be a bug). - The `ImageRenderer` sometimes renders text in the wrong color (seems to be a bug).
- PDF exports are fairly large (> 2 MB) due to included fonts, which is a problem for some applications. - PDF exports are fairly large (> 2 MB) due to included fonts, which is a problem for some applications.
Next steps:
- Create HTML export to use for my website

View File

@@ -7,6 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* 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 */; }; E267D1742A8E0DE80069112B /* ResumeBuilderApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1732A8E0DE80069112B /* ResumeBuilderApp.swift */; };
E267D1762A8E0DE80069112B /* CV.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1752A8E0DE80069112B /* CV.swift */; }; E267D1762A8E0DE80069112B /* CV.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1752A8E0DE80069112B /* CV.swift */; };
E267D1782A8E0DE90069112B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E267D1772A8E0DE90069112B /* Assets.xcassets */; }; E267D1782A8E0DE90069112B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E267D1772A8E0DE90069112B /* Assets.xcassets */; };
@@ -41,6 +43,7 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference 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>"; }; 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; }; 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>"; }; E267D1732A8E0DE80069112B /* ResumeBuilderApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumeBuilderApp.swift; sourceTree = "<group>"; };
@@ -82,6 +85,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
E267D1882A8E12D60069112B /* SFSafeSymbols in Frameworks */, E267D1882A8E12D60069112B /* SFSafeSymbols in Frameworks */,
880A8C212AFE3B0C000ABBFA /* PhoneNumberKit in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -118,6 +122,7 @@
E267D17C2A8E0DE90069112B /* ResumeBuilder.entitlements */, E267D17C2A8E0DE90069112B /* ResumeBuilder.entitlements */,
E267D1792A8E0DE90069112B /* Preview Content */, E267D1792A8E0DE90069112B /* Preview Content */,
E267D1822A8E0F320069112B /* Color+Extension.swift */, E267D1822A8E0F320069112B /* Color+Extension.swift */,
886AD6442AB9CD9100B1A00D /* ColorScheme+Extensions.swift */,
E267D1932A8E38C60069112B /* Data.swift */, E267D1932A8E38C60069112B /* Data.swift */,
E267D1A52A8EC34B0069112B /* Data */, E267D1A52A8EC34B0069112B /* Data */,
E267D1BE2A90095D0069112B /* Language */, E267D1BE2A90095D0069112B /* Language */,
@@ -217,6 +222,7 @@
name = ResumeBuilder; name = ResumeBuilder;
packageProductDependencies = ( packageProductDependencies = (
E267D1872A8E12D60069112B /* SFSafeSymbols */, E267D1872A8E12D60069112B /* SFSafeSymbols */,
880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */,
); );
productName = ResumeBuilder; productName = ResumeBuilder;
productReference = E267D1702A8E0DE80069112B /* ResumeBuilder.app */; productReference = E267D1702A8E0DE80069112B /* ResumeBuilder.app */;
@@ -230,7 +236,7 @@
attributes = { attributes = {
BuildIndependentTargetsInParallel = 1; BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1430; LastSwiftUpdateCheck = 1430;
LastUpgradeCheck = 1430; LastUpgradeCheck = 1500;
TargetAttributes = { TargetAttributes = {
E267D16F2A8E0DE80069112B = { E267D16F2A8E0DE80069112B = {
CreatedOnToolsVersion = 14.3.1; CreatedOnToolsVersion = 14.3.1;
@@ -248,6 +254,7 @@
mainGroup = E267D1672A8E0DE80069112B; mainGroup = E267D1672A8E0DE80069112B;
packageReferences = ( packageReferences = (
E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */,
880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */,
); );
productRefGroup = E267D1712A8E0DE80069112B /* Products */; productRefGroup = E267D1712A8E0DE80069112B /* Products */;
projectDirPath = ""; projectDirPath = "";
@@ -295,6 +302,7 @@
E267D18C2A8E1A890069112B /* TopViewImage.swift in Sources */, E267D18C2A8E1A890069112B /* TopViewImage.swift in Sources */,
E267D19C2A8E45470069112B /* CareerStation.swift in Sources */, E267D19C2A8E45470069112B /* CareerStation.swift in Sources */,
E267D1BA2A8F9D9C0069112B /* SkillStyle.swift in Sources */, E267D1BA2A8F9D9C0069112B /* SkillStyle.swift in Sources */,
886AD6452AB9CD9100B1A00D /* ColorScheme+Extensions.swift in Sources */,
E267D1AD2A8F694A0069112B /* PublicationView.swift in Sources */, E267D1AD2A8F694A0069112B /* PublicationView.swift in Sources */,
E267D1BC2A8FFF300069112B /* TagView.swift in Sources */, E267D1BC2A8FFF300069112B /* TagView.swift in Sources */,
E267D1A02A8E45620069112B /* CVInfo.swift in Sources */, E267D1A02A8E45620069112B /* CVInfo.swift in Sources */,
@@ -313,6 +321,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -342,9 +351,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
@@ -373,6 +384,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -402,9 +414,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -431,6 +445,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\"";
DEVELOPMENT_TEAM = H8WR4M6QQ4; DEVELOPMENT_TEAM = H8WR4M6QQ4;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -460,6 +475,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"ResumeBuilder/Preview Content\"";
DEVELOPMENT_TEAM = H8WR4M6QQ4; DEVELOPMENT_TEAM = H8WR4M6QQ4;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -504,6 +520,14 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference 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" */ = { E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols";
@@ -515,6 +539,11 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */ = {
isa = XCSwiftPackageProductDependency;
package = 880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */;
productName = PhoneNumberKit;
};
E267D1872A8E12D60069112B /* SFSafeSymbols */ = { E267D1872A8E12D60069112B /* SFSafeSymbols */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; package = E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */;

View File

@@ -1,5 +1,14 @@
{ {
"pins" : [ "pins" : [
{
"identity" : "phonenumberkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/marmelroy/PhoneNumberKit",
"state" : {
"revision" : "b456f2f9be10c1d183158220b831afd22697dd68",
"version" : "3.7.4"
}
},
{ {
"identity" : "sfsafesymbols", "identity" : "sfsafesymbols",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",

View File

@@ -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>

View File

@@ -1,61 +1,61 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "icon 9.jpg", "filename" : "icon 9.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "16x16" "size" : "16x16"
}, },
{ {
"filename" : "icon 8.jpg", "filename" : "icon 8.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "16x16" "size" : "16x16"
}, },
{ {
"filename" : "icon 7.jpg", "filename" : "icon 7.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "32x32" "size" : "32x32"
}, },
{ {
"filename" : "icon 6.jpg", "filename" : "icon 6.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "32x32" "size" : "32x32"
}, },
{ {
"filename" : "icon 5.jpg", "filename" : "icon 5.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "128x128" "size" : "128x128"
}, },
{ {
"filename" : "icon 4.jpg", "filename" : "icon 4.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "128x128" "size" : "128x128"
}, },
{ {
"filename" : "icon 3.jpg", "filename" : "icon 3.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "icon 2.jpg", "filename" : "icon 2.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "icon 1.jpg", "filename" : "icon 1.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "512x512" "size" : "512x512"
}, },
{ {
"filename" : "icon.jpg", "filename" : "icon.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "512x512" "size" : "512x512"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -1,6 +1,9 @@
import SwiftUI import SwiftUI
struct CV: View { struct CV: View {
@Environment(\.colorScheme)
var colorScheme: ColorScheme
let info: CVInfo let info: CVInfo
@@ -61,7 +64,7 @@ struct CV: View {
Spacer(minLength: 0) Spacer(minLength: 0)
Text(info.footer) Text(info.footer)
.font(.footnote) .font(.footnote)
.foregroundColor(.secondary) .foregroundColor(colorScheme.secondaryColor)
} }
.padding() .padding()
.aspectRatio(1 / sqrt(2), contentMode: .fit) .aspectRatio(1 / sqrt(2), contentMode: .fit)

View File

@@ -13,4 +13,20 @@ extension Color {
init(_ r: Double, _ g: Double, _ b: Double) { init(_ r: Double, _ g: Double, _ b: Double) {
self.init(red: r, green: g, blue: b) 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)
}
} }

View 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
}
}

View File

@@ -51,6 +51,7 @@ struct ContentView: View {
}) { }) {
Label("Export", systemSymbol: .squareAndArrowDown) Label("Export", systemSymbol: .squareAndArrowDown)
.padding(3) .padding(3)
.frame(maxHeight: 20)
}.confirmationDialog( }.confirmationDialog(
"Which format would you like?", "Which format would you like?",
isPresented: $showExportFormatPicker isPresented: $showExportFormatPicker
@@ -65,6 +66,7 @@ struct ContentView: View {
Button(action: importData) { Button(action: importData) {
Label("Import", systemSymbol: .docBadgePlus) Label("Import", systemSymbol: .docBadgePlus)
.padding(8) .padding(8)
.frame(maxHeight: 20)
} }
Spacer() Spacer()
Toggle("Dark mode", isOn: $darkModeEnabled) Toggle("Dark mode", isOn: $darkModeEnabled)
@@ -205,7 +207,7 @@ struct ContentView: View {
private var renderContent: some View { private var renderContent: some View {
CV(info: info, style: style) CV(info: info, style: style)
.frame(width: style.pageWidth, height: style.pageHeight) .frame(width: style.pageWidth, height: style.pageHeight)
.preferredColorScheme(.dark) .preferredColorScheme(colorStyle)
} }
@MainActor @MainActor

View File

@@ -32,13 +32,19 @@ let cvInfoEnglish = CVInfo(
imageName: "Cover", imageName: "Cover",
name: "Christoph Hagen", name: "Christoph Hagen",
tagLine: "Problem solver and creative mind with a favour for interdisciplinary work.", tagLine: "Problem solver and creative mind with a favour for interdisciplinary work.",
place: "Würzburg, Germany", place: "Munich, Germany",
ageText: "Age 32", ageText: "Age 33",
web: "christophhagen.de", web: "christophhagen.de",
email: "jobs@christophhagen.de", email: "jobs@christophhagen.de",
phone: "Upon Request", phone: "Upon Request",
github: "github.com/christophhagen"), github: "github.com/christophhagen"),
work: .init(title: "Work experience", items: [ 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( CareerStation(
time: "Jul 2020 - Jul 2023", time: "Jul 2020 - Jul 2023",
location: "Braunschweig, Germany", location: "Braunschweig, Germany",
@@ -57,12 +63,6 @@ let cvInfoEnglish = CVInfo(
title: "National Institute of Informatics", title: "National Institute of Informatics",
subtitle: "Research Intern (Intelligent Robotics)", subtitle: "Research Intern (Intelligent Robotics)",
text: "Topic: Concept Acquisition through interactions between Humans and Robots"), 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: [ education: .init(title: "Education", items: [
CareerStation( CareerStation(
@@ -124,13 +124,19 @@ let cvInfoGerman = CVInfo(
imageName: "Cover", imageName: "Cover",
name: "Christoph Hagen", name: "Christoph Hagen",
tagLine: "Problemlöser und kreativer Kopf mit einer Vorliebe für interdisziplinäre Arbeit.", tagLine: "Problemlöser und kreativer Kopf mit einer Vorliebe für interdisziplinäre Arbeit.",
place: "Würzburg", place: "München",
ageText: "32 Jahre", ageText: "33 Jahre",
web: "christophhagen.de", web: "christophhagen.de",
email: "jobs@christophhagen.de", email: "jobs@christophhagen.de",
phone: "Auf Anfrage", phone: "Auf Anfrage",
github: "github.com/christophhagen"), github: "github.com/christophhagen"),
work: .init(title: "Berufserfahrung", items: [ 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( CareerStation(
time: "Jul 2020 - Jul 2023", time: "Jul 2020 - Jul 2023",
location: "Braunschweig", location: "Braunschweig",
@@ -147,14 +153,8 @@ let cvInfoGerman = CVInfo(
time: "Jul 2017 - Okt 2017", time: "Jul 2017 - Okt 2017",
location: "Tokio, Japan", location: "Tokio, Japan",
title: "National Institute of Informatics", title: "National Institute of Informatics",
subtitle: "Research Intern (Intelligent Robotics)", subtitle: "Praktikant (Intelligente Robotik)",
text: "Thema: Concept Acquisition through interactions between Humans and Robots"), 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.")
]), ]),
education: .init(title: "Bildung", items: [ education: .init(title: "Bildung", items: [
CareerStation( CareerStation(

View File

@@ -3,6 +3,9 @@ import SFSafeSymbols
struct CareerStationView: View { struct CareerStationView: View {
@Environment(\.colorScheme)
var colorScheme: ColorScheme
let info: CareerStation let info: CareerStation
let borderSpacing: CGFloat let borderSpacing: CGFloat
@@ -20,7 +23,7 @@ struct CareerStationView: View {
RightImageLabel(info.location, systemSymbol: .house) RightImageLabel(info.location, systemSymbol: .house)
} }
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(colorScheme.secondaryColor)
Text(info.title) Text(info.title)
.font(.headline) .font(.headline)
.fontWeight(.regular) .fontWeight(.regular)
@@ -32,7 +35,7 @@ struct CareerStationView: View {
if let text = info.text { if let text = info.text {
Text(text) Text(text)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(colorScheme.secondaryColor)
} }
} }
} }

View File

@@ -1,7 +1,10 @@
import SwiftUI import SwiftUI
struct PublicationView: View { struct PublicationView: View {
@Environment(\.colorScheme)
var colorScheme: ColorScheme
let info: Publication let info: Publication
let borderSpacing: CGFloat let borderSpacing: CGFloat
@@ -15,10 +18,11 @@ struct PublicationView: View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text(info.venue) Text(info.venue)
.font(.caption) .font(.caption)
.foregroundColor(.secondary) .foregroundColor(colorScheme.secondaryColor)
Text(info.title) Text(info.title)
.font(.subheadline) .font(.subheadline)
.fontWeight(.regular) .fontWeight(.regular)
.foregroundColor(colorScheme.primaryColor)
} }
} }
} }

View File

@@ -1,20 +1,20 @@
import SwiftUI import SwiftUI
import SFSafeSymbols import SFSafeSymbols
struct LeftImageLabel: View { struct LeftImageLabel<Content>: View where Content: View {
let text: String
let systemSymbol: SFSymbol let systemSymbol: SFSymbol
let content: Content
init(_ text: String, systemSymbol: SFSymbol) { init(systemSymbol: SFSymbol, @ViewBuilder content: () -> Content) {
self.text = text
self.systemSymbol = systemSymbol self.systemSymbol = systemSymbol
self.content = content()
} }
var body: some View { var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 0) { HStack(alignment: .center, spacing: 0) {
Text(text) content
Image(systemSymbol: systemSymbol) Image(systemSymbol: systemSymbol)
.frame(width: 20) .frame(width: 20)
} }
@@ -23,6 +23,6 @@ struct LeftImageLabel: View {
struct LeftImageLabel_Previews: PreviewProvider { struct LeftImageLabel_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
LeftImageLabel("Home address", systemSymbol: .house) LeftImageLabel(systemSymbol: .house) { Text("Home address") }
} }
} }

View File

@@ -1,6 +1,9 @@
import SwiftUI import SwiftUI
struct TitledTextSection: View { struct TitledTextSection: View {
@Environment(\.colorScheme)
var colorScheme: ColorScheme
let content: Titled<String> let content: Titled<String>
@@ -8,6 +11,10 @@ struct TitledTextSection: View {
let paragraphSpacing: CGFloat let paragraphSpacing: CGFloat
private var textColor: Color {
colorScheme == .light ? .lightSchemePrimaryColor : .darkSchemePrimaryColor
}
var body: some View { var body: some View {
TitledSection(title: content.title, spacing: titleSpacing) { TitledSection(title: content.title, spacing: titleSpacing) {
ForEach(content.items) { text in ForEach(content.items) { text in
@@ -15,6 +22,7 @@ struct TitledTextSection: View {
.font(.body) .font(.body)
.fontWeight(.light) .fontWeight(.light)
.padding(.bottom, paragraphSpacing) .padding(.bottom, paragraphSpacing)
.foregroundColor(textColor)
} }
} }
} }

View File

@@ -1,5 +1,8 @@
import SwiftUI import SwiftUI
import SFSafeSymbols import SFSafeSymbols
import PhoneNumberKit
private let emailPattern = #"^\S+@\S+\.\S+$"#
struct TopView: View { struct TopView: View {
@@ -8,6 +11,21 @@ struct TopView: View {
let style: HeaderStyle let style: HeaderStyle
let accent: Color 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 { var body: some View {
GeometryReader { geo in GeometryReader { geo in
@@ -34,18 +52,30 @@ struct TopView: View {
shadow: style.imageShadowSize, shadow: style.imageShadowSize,
lineWidth: style.imageBorderWidth) lineWidth: style.imageBorderWidth)
VStack(alignment: .trailing) { VStack(alignment: .trailing) {
LeftImageLabel(info.web, systemSymbol: .globe) LeftImageLabel(systemSymbol: .globe) {
.frame(maxHeight: style.iconHeight) Text(info.web)
//Link(info.web, destination: URL(string: "https://" + info.web)!)
}
.frame(maxHeight: style.iconHeight)
Spacer() Spacer()
LeftImageLabel(info.email, systemSymbol: .envelope) LeftImageLabel(systemSymbol: .envelope) {
.frame(maxHeight: style.iconHeight) Text(info.email)
//Link(info.email, destination: URL(string: "mailto:" + info.email)!)
//.disabled(!isValidEmail)
}
.frame(maxHeight: style.iconHeight)
Spacer() Spacer()
LeftImageLabel(info.phone, systemSymbol: .phone) LeftImageLabel(systemSymbol: .phone) {
.frame(maxHeight: style.iconHeight) Text(info.phone)
//Link(info.phone, destination: URL(string: "tel:" + info.phone)!)
//.disabled(!isValidPhoneNumber)
}
.frame(maxHeight: style.iconHeight)
Spacer() Spacer()
HStack(spacing: 0) { HStack(spacing: 0) {
Spacer() Spacer()
Text(info.github) Text(info.github)
//Link(info.github, destination: URL(string: "https://" + info.github)!)
Image("Github") Image("Github")
.resizable() .resizable()
.aspectRatio(1.0, contentMode: .fit) .aspectRatio(1.0, contentMode: .fit)
@@ -55,6 +85,7 @@ struct TopView: View {
} }
.font(.subheadline) .font(.subheadline)
.frame(width: sideWidth) .frame(width: sideWidth)
.foregroundStyle(.primary)
} }
} }
} }