feat: add work variant

This commit is contained in:
Felix Schröter 2025-02-24 17:03:30 +01:00
parent e2ff82b759
commit 9afd5f51c5
Signed by: felschr
GPG key ID: 671E39E6744C807D
5 changed files with 486 additions and 31 deletions

View file

@ -34,57 +34,74 @@
'';
};
src = typixLib.cleanTypstSource ./.;
commonArgs = {
typstSource = "src/main.typ";
typstOutput = "out/main.pdf";
mkTypst = entry: rec {
src = typixLib.cleanTypstSource ./.;
commonArgs = {
typstSource = "src/${entry}.typ";
typstOutput = "out/${entry}.pdf";
fontPaths = [ ];
fontPaths = [
"${pkgs.inter}/share/fonts/truetype"
];
virtualPaths = [ ];
virtualPaths = [ ];
};
commonBuildArgs = commonArgs // {
XDG_CACHE_HOME = typstPackagesCache;
};
build-drv = typixLib.buildTypstProject (
commonBuildArgs
// {
inherit src;
}
);
build-script = typixLib.buildTypstProjectLocal (
commonBuildArgs
// {
inherit src;
}
);
watch-script = typixLib.watchTypstProject commonArgs;
};
commonBuildArgs = commonArgs // {
XDG_CACHE_HOME = typstPackagesCache;
};
build-drv = typixLib.buildTypstProject (
commonBuildArgs
// {
inherit src;
}
);
build-script = typixLib.buildTypstProjectLocal (
commonBuildArgs
// {
inherit src;
}
);
watch-script = typixLib.watchTypstProject commonArgs;
typstMain = mkTypst "main";
typstWork = mkTypst "work";
in
{
checks = {
inherit build-drv build-script watch-script;
inherit (typstMain) build-drv build-script watch-script;
# inherit (typstWork) build-drv build-script watch-script;
};
packages.default = build-drv;
packages = {
default = typstMain.build-drv;
work = typstWork.build-drv;
};
apps = rec {
default = watch;
build = inputs.flake-utils.lib.mkApp {
drv = build-script;
drv = typstMain.build-script;
};
watch = inputs.flake-utils.lib.mkApp {
drv = watch-script;
drv = typstMain.watch-script;
};
build-work = inputs.flake-utils.lib.mkApp {
drv = typstWork.build-script;
};
watch-work = inputs.flake-utils.lib.mkApp {
drv = typstWork.watch-script;
};
};
devShells.default = typixLib.devShell {
inherit (commonArgs) fontPaths virtualPaths;
inherit (typstMain.commonArgs) fontPaths virtualPaths;
packages = [
watch-script
typstMain.watch-script
pkgs.typstyle
pkgs.tinymist

247
src/lib/work.typ Normal file
View file

@ -0,0 +1,247 @@
#let dates-helper(
start-date: "",
end-date: "",
) = {
start-date + " - " + end-date
}
#let job_entry(date, company, position, description, experiences) = {
grid(
columns: (22%, 33%, auto),
gutter: 12pt,
// Column 1: Date Range
box(
fill: rgb(242, 242, 242, 255),
width: 100%,
inset: 10pt,
text(date),
),
// Column 2: Company Info
box()[
#text(company) \
#text(weight: "bold", position) \
#text(description)
],
// Column 3: Work Experiences
for exp in experiences {
box(
fill: rgb(242, 242, 242, 255),
width: 100%,
inset: 10pt,
[
#text(exp.role) \
#text(weight: "bold", exp.heading) \
#text(size: 10pt, exp.description)
],
)
}
)
}
#let resume(
name: "",
position: "",
address: none,
birth_date: "",
email: "",
phone: "",
profile-picture: image,
company-logo: image,
font: "Inter",
paper: "a4",
body,
) = {
set document(author: name, title: name)
set text(font: font, lang: "en")
show heading: set text(rgb(0, 194, 255, 255))
grid(
columns: 100%,
align: (right),
[
#company-logo
\ \ \ \
]
)
grid(
columns: (60%, 180pt),
align: (top, right),
[
#text(size: 30pt, weight: "bold", name) \
\
#text(size: 13pt, weight: "bold", position) \
\ \
],
)
set text()
grid(
columns: (50%, auto),
gutter: 100pt,
box(
width: 100%,
[
#heading(level: 2, "Personal Data")
#grid(
columns: (50%, 50%),
gutter: 20pt,
box(
width: 100%,
[
#text(weight: "bold", "Name:") \
#text(name)
],
),
box(
width: 100%,
[
#text(weight: "bold", "Birth date:") \
#text(birth_date)
],
),
box(
width: 100%,
[
#text(weight: "bold", "Address:") \
#text(address.street)
#text(address.city)
],
),
box(
width: 100%,
[
#text(weight: "bold", "Contact:") \
#text(email)
#{
if phone != "" {
text(phone)
}
}
],
),
)
],
),
profile-picture,
)
linebreak()
linebreak()
body
}
#let work_experience(body) = {
set text(fill: black)
set text(fill: rgb(0, 194, 255, 255))
grid(
columns: (60%, auto),
heading(level: 2, "Work Experience"), heading(level: 2, "Case Studies"),
)
set text(fill: black)
body
}
#let education_entry(date, university, degree, subject) = {
box(
width: 100%,
[
#text(weight: "bold", date) \
#text(weight: "bold", university) \
#text(degree + " in " + subject)
\ \
],
)
}
#let certification_entry(date, issuer, certificate) = {
box(
width: 100%,
[
#text(weight: "bold", date) \
#text(weight: "bold", certificate) \
#text(weight: "bold", issuer)
\ \
],
)
}
#let language_levels = (
(0, 25, "Beginner"),
(26, 50, "Intermediate"),
(51, 75, "Advanced"),
(76, 99, "Fluent"),
(100, 100, "Native"),
)
#let lang_level_text = score => {
let result = "Unknown"
for (min, max, label) in language_levels {
if score >= min and score <= max {
result = label
}
}
result
}
#let language_entry(lang, score) = {
grid(
columns: (40%, auto),
box(
width: 100%,
[
#text(weight: "bold")[#lang]
],
),
box(
width: 100%,
[
#lang_level_text(score)
#box(
width: 105pt,
height: 6pt,
fill: rgb(220, 220, 220),
inset: 0pt,
[
#rect(
width: (105pt * score / 100),
height: 6pt,
fill: rgb(0, 194, 255, 255),
)
],
)
],
),
)
}
#let bottom_grid(sections) = {
linebreak()
linebreak()
linebreak()
set text(fill: rgb(0, 194, 255, 255))
grid(
columns: (60%, auto),
gutter: 3pt,
..sections.map(s => {
if s != none {
heading(level: 2, s.title)
set text(fill: black)
s.content
}
}),
)
set text(fill: black)
}

BIN
src/photo.jpg Normal file

Binary file not shown.

After

(image error) Size: 307 KiB

BIN
src/upsquared.png Normal file

Binary file not shown.

After

(image error) Size: 9.8 KiB

191
src/work.typ Normal file
View file

@ -0,0 +1,191 @@
#import "lib/work.typ": *
#let name = "Felix Schröter"
#let position = "Senior Software Engineer & Tech Lead"
#let address = (street: "Salzwedeler Str. 1", city: "21339 Lüneburg")
#let birth_date = "26.09.1995"
#let email = "fs@upsquared.com"
#let profile-picture = image("photo.jpg", width: 115pt, height: 135pt)
#let company-logo = image("upsquared.png", width: 220pt, height: auto)
#show: resume.with(
name: name,
position: position,
address: address,
birth_date: birth_date,
email: email,
profile-picture: profile-picture,
company-logo: company-logo,
)
#show: work_experience.with()
#job_entry(
dates-helper(start-date: "Jun 2024", end-date: "Present"),
"upsquared GmbH",
"Senior Software Engineer & Tech Lead",
"Leading Cloud-native Development, Infrastructure & DevOps solutions",
(
(
role: "Tech Lead",
heading: "Grow engineering team",
description: "Onboard, mentor & lead new team of engineers.",
),
(
role: "Software & Cloud Architect",
heading: "Cloud-native solutions",
description: "Architect solutions built on Rust, Kubernetes, OpenTofu & GCP",
),
),
)
#job_entry(
dates-helper(start-date: "Oct 2019", end-date: "May 2024"),
"upsquared GmbH",
"Senior Software Engineer",
"Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions",
(
(
role: "Software & Cloud Architect",
heading: "Cloud-native solutions",
description: "Architect solutions built on Rust, C#, Kubernetes, Terraform & GCP",
),
(
role: "DevOps Engineer",
heading: "Full-stack Observability",
description: "Enhanced Observability with Sentry, Rust, C#, React & GKE",
),
(
role: "Frontend Engineer",
heading: "Plant Analyzer Web",
description: "Built web-based frontend for digital phenotyping platform",
),
(
role: "DevOps Engineer",
heading: "Reproducible CI/CD",
description: "Established reproducible builds & dev environments using Nix",
),
),
)
#job_entry(
dates-helper(start-date: "Apr 2019", end-date: "Sep 2019"),
"Digital Spring",
"Senior Software Engineer",
"Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions",
(
(
role: "DevOps Engineer",
heading: "GitLab CI/CD",
description: "Set up GitLab CI/CD pipeline for .NET microservices",
),
),
)
#job_entry(
dates-helper(start-date: "Oct 2016", end-date: "Mar 2019"),
"Digital Spring",
"Software Engineer",
"Full-Stack Development, Infrastructure & DevOps for Cloud-native solutions",
(
(
role: "Backend & Cloud Architect",
heading: "Cloud-native solutions",
description: "Built microservices & Kubernetes cluster from scratch",
),
(
role: "Backend & Cloud Engineer",
heading: "Serverless solutions",
description: "Built serverless backends with AWS Lambda",
),
(
role: "Frontend Engineer",
heading: "Modern web apps",
description: "Implemented frontends in React & Angular for different projects",
),
),
)
#job_entry(
dates-helper(start-date: "Jun 2015", end-date: "Sep 2016"),
"Werum IT Solutions GmbH (now Körber Pharma Software GmbH)",
"Software Engineer",
"",
(
(
role: "Software Engineer",
heading: "Interface development",
description: "DCS/PCS and ERP interface development with .NET & PL/SQL",
),
),
)
#job_entry(
dates-helper(start-date: "Aug 2012", end-date: "Jun 2015"),
"Werum IT Solutions GmbH (now Körber Pharma Software GmbH)",
"Trainee",
"",
(
(
role: "Software Engineer",
heading: "Process automation",
description: "Process automation (DCS/PCS) interface development with .NET",
),
),
)
#let education = (
(
dates-helper(start-date: "May 2024", end-date: "Present"),
"University of Colorado Boulder",
"Master of Science",
"Computer Science",
),
(
dates-helper(start-date: "Aug 2012", end-date: "Jun 2015"),
"Berufsbildende Schulen I Lüneburg",
"Computer Science Expert",
"Software Development",
),
);
#let certifications = (
(
"Feb 2024",
"CompTIA",
"CompTIA Cloud+",
),
(
"Feb 2024",
"Cloud Security Alliance",
"Certificate of Cloud Security Knowledge v.4",
),
);
#let languages = (
("English", 90),
("German", 100),
)
#let sections = (
(
title: "Education",
content: education.map(e => education_entry(..e)).join("\n"),
),
(
title: "Languages",
content: languages.map(l => language_entry(..l)).join("\n"),
),
none,
// (
// title: "Certifications",
// content: certifications.map(c => certification_entry(..c)).join("\n"),
// ),
(
title: "Interests",
content: "reading, tea, Nix, NixOS, Linux, homelab, Doctor Who",
),
)
#bottom_grid(sections)