From 7934af3ad88a03b7438857c880347731144b9a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Schr=C3=B6ter?= Date: Wed, 26 Feb 2025 00:50:43 +0100 Subject: [PATCH 1/5] fix: fix sign-on typo --- src/main.typ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.typ b/src/main.typ index 15ad7cc..93ba70c 100644 --- a/src/main.typ +++ b/src/main.typ @@ -110,7 +110,7 @@ url: "codeberg.org/felschr/nixos-config", ) - Maintaining my personal & work computers as well as a homelab via a declarative NixOS configuration -- I self-host various services for single sign-On (SSO), home automation, git forge, build server & more +- I self-host various services for single sign-on (SSO), home automation, git forge, build server & more #project( name: "Pheno-Inspect Plant Analyzer Web", From 8f783151ef68cec65a0375ee53e078f6fad7cd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Schr=C3=B6ter?= Date: Wed, 26 Feb 2025 00:51:56 +0100 Subject: [PATCH 2/5] refactor: create own template based on basic-resume --- src/lib/main.typ | 217 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.typ | 2 +- 2 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 src/lib/main.typ diff --git a/src/lib/main.typ b/src/lib/main.typ new file mode 100644 index 0000000..de6a915 --- /dev/null +++ b/src/lib/main.typ @@ -0,0 +1,217 @@ +#import "@preview/scienceicons:0.0.6": orcid-icon + +// based on https://github.com/stuxf/basic-typst-resume-template + +#let resume( + author: "", + author-position: left, + personal-info-position: left, + pronouns: "", + location: "", + email: "", + github: "", + linkedin: "", + phone: "", + personal-site: "", + orcid: "", + accent-color: "#000000", + font: "New Computer Modern", + paper: "a4", + body, +) = { + // Sets document metadata + set document(author: author, title: author) + + // Document-wide formatting, including font and margins + set text( + // LaTeX style font + font: font, + size: 10pt, + lang: "en", + // Disable ligatures so ATS systems do not get confused when parsing fonts. + ligatures: false, + ) + + set page( + margin: 1.5cm, + paper: paper, + ) + + // Link styles + show link: underline + + + // Small caps for section titles + show heading.where(level: 2): it => [ + #pad(top: 0pt, bottom: -10pt, [#smallcaps(it.body)]) + #line(length: 100%, stroke: 1pt) + ] + + // Accent Color Styling + show heading: set text(fill: rgb(accent-color)) + + show link: set text(fill: rgb(accent-color)) + + // Name will be aligned left, bold and big + show heading.where(level: 1): it => [ + #set align(author-position) + #set text( + weight: 700, + size: 20pt, + ) + #pad(it.body) + ] + + // Level 1 Heading + [= #(author)] + + // Personal Info Helper + let contact-item(value, prefix: "", link-type: "") = { + if value != "" { + if link-type != "" { + link(link-type + value)[#(prefix + value)] + } else { + value + } + } + } + + // Personal Info + pad( + top: 0.25em, + align(personal-info-position)[ + #{ + let items = ( + contact-item(pronouns), + contact-item(phone), + contact-item(location), + contact-item(email, link-type: "mailto:"), + contact-item(github, link-type: "https://"), + contact-item(linkedin, link-type: "https://"), + contact-item(personal-site, link-type: "https://"), + contact-item( + orcid, + prefix: [#orcid-icon(color: rgb("#AECD54"))orcid.org/], + link-type: "https://orcid.org/", + ), + ) + items.filter(x => x != none).join(" | ") + } + ], + ) + + // Main body. + set par(justify: true) + + body +} + +// Generic two by two component for resume +#let generic-two-by-two( + top-left: "", + top-right: "", + bottom-left: "", + bottom-right: "", +) = { + [ + #top-left #h(1fr) #top-right \ + #bottom-left #h(1fr) #bottom-right + ] +} + +// Generic one by two component for resume +#let generic-one-by-two( + left: "", + right: "", +) = { + [ + #left #h(1fr) #right + ] +} + +// Cannot just use normal --- ligature becuase ligatures are disabled for good reasons +#let dates-helper( + start-date: "", + end-date: "", +) = { + start-date + " " + $dash.em$ + " " + end-date +} + +// Section components below +#let edu( + institution: "", + dates: "", + degree: "", + gpa: "", + location: "", +) = { + generic-two-by-two( + top-left: strong(institution), + top-right: location, + bottom-left: emph(degree), + bottom-right: emph(dates), + ) +} + +#let work( + title: "", + dates: "", + company: "", + location: "", +) = { + generic-two-by-two( + top-left: strong(title), + top-right: dates, + bottom-left: company, + bottom-right: emph(location), + ) +} + +#let project( + role: "", + name: "", + url: "", + dates: "", +) = { + generic-one-by-two( + left: { + if role == "" { + [*#name* #if url != "" and dates != "" [ (#link("https://" + url)[#url])]] + } else { + [*#role*, #name #if url != "" and dates != "" [ (#link("https://" + url)[#url])]] + } + }, + right: { + if dates == "" and url != "" { + link("https://" + url)[#url] + } else { + dates + } + }, + ) +} + +#let certificates( + name: "", + issuer: "", + url: "", + date: "", +) = { + [ + *#name*, #issuer + #if url != "" { + [ (#link("https://" + url)[#url])] + } + #h(1fr) #date + ] +} + +#let extracurriculars( + activity: "", + dates: "", +) = { + generic-one-by-two( + left: strong(activity), + right: dates, + ) +} diff --git a/src/main.typ b/src/main.typ index 93ba70c..de53bad 100644 --- a/src/main.typ +++ b/src/main.typ @@ -1,4 +1,4 @@ -#import "@preview/basic-resume:0.2.3": * +#import "lib/main.typ": * #let name = "Felix Schröter" #let location = "Lüneburg, Germany" From 22b73648d5d1edd0c771d833c569fd259529f414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Schr=C3=B6ter?= Date: Fri, 28 Feb 2025 12:06:01 +0100 Subject: [PATCH 3/5] feat: update template design & add cover letter option --- flake.nix | 4 +- src/lib/main.typ | 184 ++++++++++++++++++++++++++++++++++++++--------- src/main.typ | 2 - 3 files changed, 153 insertions(+), 37 deletions(-) diff --git a/flake.nix b/flake.nix index 3ba17f4..cfbacb5 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,9 @@ typstSource = "src/main.typ"; typstOutput = "out/main.pdf"; - fontPaths = [ ]; + fontPaths = [ + "${pkgs.work-sans}/share/fonts/opentype" + ]; virtualPaths = [ ]; }; diff --git a/src/lib/main.typ b/src/lib/main.typ index de6a915..1743285 100644 --- a/src/lib/main.typ +++ b/src/lib/main.typ @@ -1,22 +1,18 @@ -#import "@preview/scienceicons:0.0.6": orcid-icon +#import "@preview/scienceicons:0.0.6": ( + email-icon, + github-icon, + linkedin-icon, + orcid-icon, + website-icon, +) // based on https://github.com/stuxf/basic-typst-resume-template -#let resume( +#let common-doc( author: "", - author-position: left, - personal-info-position: left, - pronouns: "", - location: "", - email: "", - github: "", - linkedin: "", - phone: "", - personal-site: "", - orcid: "", - accent-color: "#000000", - font: "New Computer Modern", + font: "Work Sans", paper: "a4", + accent-color: "#000000", body, ) = { // Sets document metadata @@ -54,7 +50,7 @@ // Name will be aligned left, bold and big show heading.where(level: 1): it => [ - #set align(author-position) + #set align(left) #set text( weight: 700, size: 20pt, @@ -62,43 +58,114 @@ #pad(it.body) ] - // Level 1 Heading - [= #(author)] + body +} - // Personal Info Helper - let contact-item(value, prefix: "", link-type: "") = { - if value != "" { - if link-type != "" { - link(link-type + value)[#(prefix + value)] - } else { - value - } +// Personal Info Helper +#let contact-item(value, icon: "", prefix: "", link-type: "") = { + if value != "" { + if icon != "" { + icon + " " + } + if link-type != "" { + link(link-type + value)[#(prefix + value)] + } else { + value } } +} - // Personal Info +// Personal Info +#let personal-info( + position: left, + with-icons: false, + separator: " | ", + pronouns: "", + phone: "", + location: "", + email: "", + github: "", + linkedin: "", + personal-site: "", + orcid: "", +) = { pad( top: 0.25em, - align(personal-info-position)[ + align(position)[ #{ let items = ( contact-item(pronouns), contact-item(phone), contact-item(location), - contact-item(email, link-type: "mailto:"), - contact-item(github, link-type: "https://"), - contact-item(linkedin, link-type: "https://"), - contact-item(personal-site, link-type: "https://"), + contact-item( + email, + icon: if with-icons { email-icon() } else { "" }, + link-type: "mailto:", + ), + contact-item( + github, + icon: if with-icons { github-icon() } else { "" }, + link-type: "https://", + ), + contact-item( + linkedin, + icon: if with-icons { linkedin-icon() } else { "" }, + link-type: "https://", + ), + contact-item( + personal-site, + icon: if with-icons { website-icon() } else { "" }, + link-type: "https://", + ), contact-item( orcid, - prefix: [#orcid-icon(color: rgb("#AECD54"))orcid.org/], + icon: orcid-icon(color: rgb("#AECD54")), + prefix: "orcid.org/", link-type: "https://orcid.org/", ), ) - items.filter(x => x != none).join(" | ") + items.filter(x => x != none).join(separator) } ], ) +} + +#let resume( + author: "", + pronouns: "", + location: "", + email: "", + github: "", + linkedin: "", + phone: "", + personal-site: "", + orcid: "", + accent-color: "#000000", + font: "Work Sans", + paper: "a4", + body, +) = { + show: common-doc.with( + author: author, + font: font, + paper: paper, + accent-color: accent-color, + ) + + // Level 1 Heading + [= #(author)] + + personal-info( + position: left, + pronouns: pronouns, + location: location, + email: email, + phone: phone, + github: github, + linkedin: linkedin, + personal-site: personal-site, + orcid: orcid, + ) // Main body. set par(justify: true) @@ -106,6 +173,55 @@ body } +#let cover-letter( + author: "", + title: "", + pronouns: "", + location: "", + email: "", + github: "", + linkedin: "", + phone: "", + personal-site: "", + orcid: "", + accent-color: "#000000", + font: "Work Sans", + paper: "a4", + body, +) = { + show: common-doc.with( + author: author, + font: font, + paper: paper, + accent-color: accent-color, + ) + + grid( + columns: (70%, auto), + [ + #[= #(author)] + #if (title != "") { + [#text(title, fill: rgb(accent-color), size: 12pt)] + } \ + #location + ], + personal-info( + with-icons: true, + position: left, + separator: "\n", + pronouns: pronouns, + email: email, + phone: phone, + github: github, + linkedin: linkedin, + personal-site: personal-site, + orcid: orcid, + ), + ) + + body +} + // Generic two by two component for resume #let generic-two-by-two( top-left: "", @@ -162,7 +278,7 @@ generic-two-by-two( top-left: strong(title), top-right: dates, - bottom-left: company, + bottom-left: emph(company), bottom-right: emph(location), ) } diff --git a/src/main.typ b/src/main.typ index de53bad..0a8dd0a 100644 --- a/src/main.typ +++ b/src/main.typ @@ -17,8 +17,6 @@ accent-color: "#26428b", font: "New Computer Modern", paper: "a4", - author-position: left, - personal-info-position: left, ) == Work Experience From 08348908f5be97759b797fa7a88be22735bb6fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Schr=C3=B6ter?= Date: Fri, 28 Feb 2025 12:07:28 +0100 Subject: [PATCH 4/5] feat: move some data into info.toml --- flake.nix | 9 ++++++++- src/info.toml | 13 +++++++++++++ src/main.typ | 25 ++++++++++--------------- 3 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 src/info.toml diff --git a/flake.nix b/flake.nix index cfbacb5..d0ddda0 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,7 @@ system: let pkgs = import inputs.nixpkgs { inherit system; }; + inherit (pkgs) lib; typixLib = inputs.typix.lib.${system}; @@ -34,7 +35,13 @@ ''; }; - src = typixLib.cleanTypstSource ./.; + src = lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions [ + (lib.fileset.fromSource (typixLib.cleanTypstSource ./.)) + ./src/info.toml + ]; + }; commonArgs = { typstSource = "src/main.typ"; typstOutput = "out/main.pdf"; diff --git a/src/info.toml b/src/info.toml new file mode 100644 index 0000000..a8816e4 --- /dev/null +++ b/src/info.toml @@ -0,0 +1,13 @@ +[personal] +name = "Felix Schröter" +title = "Senior Software Engineer & Tech Lead" +location = "Lüneburg, Germany" +email = "dev@felschr.com" +github = "github.com/felschr" +linkedin = "linkedin.com/in/schroeter" +website = "felschr.com" + +[layout] +font = "Work Sans" +paper = "a4" +accent_color = "#246a48" diff --git a/src/main.typ b/src/main.typ index 0a8dd0a..5ee2fd2 100644 --- a/src/main.typ +++ b/src/main.typ @@ -1,22 +1,17 @@ #import "lib/main.typ": * -#let name = "Felix Schröter" -#let location = "Lüneburg, Germany" -#let email = "dev@felschr.com" -#let github = "github.com/felschr" -#let linkedin = "linkedin.com/in/schroeter" -#let personal-site = "felschr.com" +#let info = toml("info.toml") #show: resume.with( - author: name, - location: location, - email: email, - github: github, - linkedin: linkedin, - personal-site: personal-site, - accent-color: "#26428b", - font: "New Computer Modern", - paper: "a4", + author: info.personal.name, + location: info.personal.location, + email: info.personal.email, + github: info.personal.github, + linkedin: info.personal.linkedin, + personal-site: info.personal.website, + accent-color: info.layout.accent_color, + font: info.layout.font, + paper: info.layout.paper, ) == Work Experience From 3514071ef34608dff801439ba46da351acd073db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Schr=C3=B6ter?= Date: Fri, 28 Feb 2025 12:08:20 +0100 Subject: [PATCH 5/5] feat: adjust content to new layout --- src/main.typ | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main.typ b/src/main.typ index 5ee2fd2..3c53e65 100644 --- a/src/main.typ +++ b/src/main.typ @@ -35,8 +35,8 @@ - Full-Stack Architecture, Development, Infrastructure & DevOps for Cloud-native solutions - Main technologies: C\#, Rust, Nix, Kubernetes, Terraform / OpenTofu, React, MongoDB, GitLab CI, GCP - Adopted Nix for reproducible builds & environments used both locally for development and for CI/CD -- Expanded Observability using Sentry and integrations with Rust, C\#, React & Google Kubernetes Engine (GKE) -- Adopted Rust as core part of our tech stack due to its strong type system, excellent tooling, safety & performance +- Expanded Observability using Sentry and integrations with Rust, C\#, React & Kubernetes +- Adopted Rust into our tech stack due to its strong type system, excellent tooling, safety & performance - Established reference architecture using Rust, Google Cloud Run, MongoDB Atlas, Nix & GitLab CI with scalability and evolution from monolith to microservices in mind #work( @@ -58,7 +58,7 @@ - Main technologies: C\#, ASP.NET Core, TypeScript, Service Fabric, Cosmos DB, Azure, AWS - Created a microservice-based backend with ASP.NET Core & Azure Cosmos DB - Implemented frontends in React & Angular for different projects -- Built serverless backends for various client projects with AWS Lambda, DynamoDB & Serverless framework +- Built serverless backends for various client projects with AWS Lambda & Serverless framework - Migrated Windows containers to Linux containers to improve performance - Migrated from Azure Service Fabric to Kubernetes for container orchestration @@ -86,7 +86,8 @@ dates: dates-helper(start-date: "May 2024", end-date: "Present"), degree: "Master of Science in Computer Science", ) -- Relevant Coursework: Data Structures and Algorithms, Software Architecture for Big Data, Network Systems +- Current GPA: 4.0 / 4.0 (14 credits) +- Relevant Courses: Data Structures and Algorithms, Software Architecture for Big Data, Network Systems #edu( institution: "Berufsbildende Schulen I Lüneburg", @@ -111,7 +112,7 @@ url: "youtu.be/JMkj8vP0eJw", ) - Client project associated with upsquared GmbH -- Developed a web-based frontend for Pheno-Inspect's Digital Phenotyping platform powered by Computer Vision +- Developed web-based frontend for Digital Phenotyping platform powered by Computer Vision - Large drone images can be rendered & annotated efficiently with pixel-perfect accuracy - Main technologies: Next.js, Redux, MUI, fp-ts, OpenLayers, Rust (WASM), WebGL @@ -143,7 +144,7 @@ dates: dates-helper(start-date: "Nov 2018", end-date: "Aug 2019"), // url: "web.archive.org/web/20191021030141/https://www.letzte-werbung.de/melder", ) -- Allows users to report companies that send mail advertising despite a "No advertising please" sticker on the mailbox +- Allows users to report companies that send mail advertising despite "No advertising" sticker on mailbox - Main technologies: TypeScript, Node.js, React, AWS Lambda, Serverless framework, DynamoDB #project( @@ -197,7 +198,7 @@ - *Industry Knowledge*: Software Architecture, Cloud-native Architecture, DevOps, Infrastructure as Code (IaC), Reproducibility, Scalability, Functional Programming, Open Source Development - *Programming Languages*: Rust, Nix, TypeScript, C\#, HCL, Bash, Nushell -- *Backend*: Podman, Docker, gRPC, MongoDB, OpenAPI, GraphQL, buf, tokio, tonic, prost, axum, ASP.NET Core +- *Backend*: Podman, gRPC, MongoDB, OpenAPI, GraphQL, buf, tokio, tonic, prost, axum, ASP.NET Core - *Frontend*: React, Next.js, Redux, emotion, MUI, storybook, webpack, fp-ts - *Infrastructure & DevOps*: Kubernetes, OpenTofu, GitLab CI, Linux, direnv, treefmt, git-hooks.nix - *Cloud Providers*: Google Cloud Platform (GCP), Firebase, Amazon Web Services (AWS), Azure