From ac7c07834122ee7aaec108e7dbc4a8519bab894d Mon Sep 17 00:00:00 2001 From: Paul T Date: Thu, 22 May 2025 14:32:45 -0400 Subject: [PATCH] fix: small misc issues with build (#118) Auto formatted all typst code and fixed CI issue due to using upload artifacts v4 (actions/upload-artifact@v4/docs/MIGRATION.md) --- .github/workflows/tests.yml | 2 +- docs/manual.typ | 8 +- lib.typ | 343 +++++++++++++----------------------- scripts/format | 3 +- scripts/package | 58 +++--- template/coverletter.typ | 7 +- template/coverletter2.typ | 5 +- template/resume.typ | 27 +-- tests/resume/test.typ | 51 ++---- tests/utilities/test.typ | 36 +--- 10 files changed, 192 insertions(+), 348 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18166c7..de4a78e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,7 +65,7 @@ jobs: uses: actions/upload-artifact@v4 if: always() with: - name: diffs + name: diffs-typst-${{ matrix.typst-version }} path: | tests/**/diff/*.png tests/**/out/*.png diff --git a/docs/manual.typ b/docs/manual.typ index 7d0120c..e375596 100644 --- a/docs/manual.typ +++ b/docs/manual.typ @@ -1,9 +1,7 @@ #import "../lib.typ" #import "@preview/tidy:0.4.1" -#let docs = tidy.parse-module( - read("../lib.typ"), - name: "Modern CV", - scope: (resume: lib), -) +#let docs = tidy.parse-module(read("../lib.typ"), name: "Modern CV", scope: ( + resume: lib, +)) #tidy.show-module(docs, style: tidy.styles.minimal) diff --git a/lib.typ b/lib.typ index b0a610a..b5ee686 100644 --- a/lib.typ +++ b/lib.typ @@ -9,27 +9,13 @@ #let default-location-color = rgb("#333333") // const icons -#let linkedin-icon = box( - fa-icon("linkedin", fill: color-darknight), -) -#let github-icon = box( - fa-icon("github", fill: color-darknight), -) -#let gitlab-icon = box( - fa-icon("gitlab", fill: color-darknight), -) -#let bitbucket-icon = box( - fa-icon("bitbucket", fill: color-darknight), -) -#let twitter-icon = box( - fa-icon("twitter", fill: color-darknight), -) -#let google-scholar-icon = box( - fa-icon("google-scholar", fill: color-darknight), -) -#let orcid-icon = box( - fa-icon("orcid", fill: color-darknight), -) +#let linkedin-icon = box(fa-icon("linkedin", fill: color-darknight)) +#let github-icon = box(fa-icon("github", fill: color-darknight)) +#let gitlab-icon = box(fa-icon("gitlab", fill: color-darknight)) +#let bitbucket-icon = box(fa-icon("bitbucket", fill: color-darknight)) +#let twitter-icon = box(fa-icon("twitter", fill: color-darknight)) +#let google-scholar-icon = box(fa-icon("google-scholar", fill: color-darknight)) +#let orcid-icon = box(fa-icon("orcid", fill: color-darknight)) #let phone-icon = box(fa-icon("square-phone", fill: color-darknight)) #let email-icon = box(fa-icon("envelope", fill: color-darknight)) #let birth-icon = box(fa-icon("cake", fill: color-darknight)) @@ -87,11 +73,14 @@ ] } -#let __coverletter_footer(author, language, date, lang_data, use-smallcaps: true) = { - set text( - fill: gray, - size: 8pt, - ) +#let __coverletter_footer( + author, + language, + date, + lang_data, + use-smallcaps: true, +) = { + set text(fill: gray, size: 8pt) __justify_align_3[ #__apply_smallcaps(date, use-smallcaps) ][ @@ -100,7 +89,7 @@ let name = __format_author_name(author, language) name + " · " + linguify("cover-letter", from: lang_data) }, - use-smallcaps + use-smallcaps, ) ][ #context { @@ -110,10 +99,7 @@ } #let __resume_footer(author, language, lang_data, date, use-smallcaps: true) = { - set text( - fill: gray, - size: 8pt, - ) + set text(fill: gray, size: 8pt) __justify_align_3[ #__apply_smallcaps(date, use-smallcaps) ][ @@ -122,7 +108,7 @@ let name = __format_author_name(author, language) name + " · " + linguify("resume", from: lang_data) }, - use-smallcaps + use-smallcaps, ) ][ #context { @@ -138,7 +124,7 @@ /// -> none #let github-link(github-path) = { set box(height: 11pt) - + align(right + horizon)[ #fa-icon("github", fill: color-darkgray) #link( "https://github.com/" + github-path, @@ -150,20 +136,14 @@ /// Right section for the justified headers /// - body (content): The body of the right header #let secondary-right-header(body) = { - set text( - size: 11pt, - weight: "medium", - ) + set text(size: 11pt, weight: "medium") body } /// Right section of a tertiaty headers. /// - body (content): The body of the right header #let tertiary-right-header(body) = { - set text( - weight: "light", - size: 9pt, - ) + set text(weight: "light", size: 9pt) body } @@ -171,10 +151,7 @@ /// - primary (content): The primary section of the header /// - secondary (content): The secondary section of the header #let justified-header(primary, secondary) = { - set block( - above: 0.7em, - below: 0.7em, - ) + set block(above: 0.7em, below: 0.7em) pad[ #__justify_align[ == #primary @@ -220,7 +197,7 @@ show-footer: true, language: "en", font: ("Source Sans Pro", "Source Sans 3"), - header-font: ("Roboto"), + header-font: "Roboto", paper-size: "a4", use-smallcaps: true, body, @@ -228,9 +205,9 @@ if type(accent-color) == str { accent-color = rgb(accent-color) } - + let lang_data = toml("lang.toml") - + show: body => context { set document( author: author.firstname + " " + author.lastname, @@ -238,7 +215,7 @@ ) body } - + set text( font: font, lang: language, @@ -246,7 +223,7 @@ fill: color-darkgray, fallback: true, ) - + set page( paper: paper-size, margin: (left: 15mm, right: 15mm, top: 10mm, bottom: 10mm), @@ -259,23 +236,14 @@ )] else [], footer-descent: 0pt, ) - + // set paragraph spacing - set par( - spacing: 0.75em, - justify: true, - ) - - set heading( - numbering: none, - outlined: false, - ) - + set par(spacing: 0.75em, justify: true) + + set heading(numbering: none, outlined: false) + show heading.where(level: 1): it => [ - #set text( - size: 16pt, - weight: "regular", - ) + #set text(size: 16pt, weight: "regular") #set align(left) #set block(above: 1em) #let color = if colored-headers { @@ -286,39 +254,26 @@ #text[#strong[#text(color)[#it.body]]] #box(width: 1fr, line(length: 100%)) ] - + show heading.where(level: 2): it => { - set text( - color-darkgray, - size: 12pt, - style: "normal", - weight: "bold", - ) + set text(color-darkgray, size: 12pt, style: "normal", weight: "bold") it.body } - + show heading.where(level: 3): it => { - set text( - size: 10pt, - weight: "regular", - ) + set text(size: 10pt, weight: "regular") __apply_smallcaps(it.body, use-smallcaps) } - + let name = { align(center)[ #pad(bottom: 5pt)[ #block[ - #set text( - size: 32pt, - style: "normal", - font: header-font, - ) + #set text(size: 32pt, style: "normal", font: header-font) #if language == "zh" or language == "ja" [ - #text( - accent-color, - weight: "thin", - )[#author.firstname]#text(weight: "bold")[#author.lastname] + #text(accent-color, weight: "thin")[#author.firstname]#text( + weight: "bold", + )[#author.lastname] ] else [ #text(accent-color, weight: "thin")[#author.firstname] #text(weight: "bold")[#author.lastname] @@ -327,46 +282,33 @@ ] ] } - + let positions = { - set text( - accent-color, - size: 9pt, - weight: "regular", - ) + set text(accent-color, size: 9pt, weight: "regular") align(center)[ #__apply_smallcaps( - author.positions.join( - text[#" "#sym.dot.c#" "], - ), - use-smallcaps + author.positions.join(text[#" "#sym.dot.c#" "]), + use-smallcaps, ) ] } - + let address = { - set text( - size: 9pt, - weight: "regular", - ) + set text(size: 9pt, weight: "regular") align(center)[ #if ("address" in author) [ #author.address ] ] } - + let contacts = { set box(height: 9pt) - + let separator = box(width: 5pt) - + align(center)[ - #set text( - size: 9pt, - weight: "regular", - style: "normal", - ) + #set text(size: 9pt, weight: "regular", style: "normal") #block[ #align(horizon)[ #if ("birth" in author) [ @@ -401,25 +343,33 @@ #if ("bitbucket" in author) [ #separator #bitbucket-icon - #box[#link("https://bitbucket.org/" + author.bitbucket)[#author.bitbucket]] + #box[#link( + "https://bitbucket.org/" + author.bitbucket, + )[#author.bitbucket]] ] #if ("linkedin" in author) [ #separator #linkedin-icon #box[ - #link("https://www.linkedin.com/in/" + author.linkedin)[#author.firstname #author.lastname] + #link( + "https://www.linkedin.com/in/" + author.linkedin, + )[#author.firstname #author.lastname] ] ] #if ("twitter" in author) [ #separator #twitter-icon - #box[#link("https://twitter.com/" + author.twitter)[\@#author.twitter]] + #box[#link( + "https://twitter.com/" + author.twitter, + )[\@#author.twitter]] ] #if ("scholar" in author) [ #let fullname = str(author.firstname + " " + author.lastname) #separator #google-scholar-icon - #box[#link("https://scholar.google.com/citations?user=" + author.scholar)[#fullname]] + #box[#link( + "https://scholar.google.com/citations?user=" + author.scholar, + )[#fullname]] ] #if ("orcid" in author) [ #separator @@ -435,11 +385,11 @@ ] ] } - + if profile-picture != none { grid( columns: (100% - 4cm, 4cm), - rows: (100pt), + rows: 100pt, gutter: 10pt, [ #name @@ -464,7 +414,7 @@ address contacts } - + body } @@ -472,16 +422,8 @@ /// This formats the item for the resume entries. Typically your body would be a bullet list of items. Could be your responsibilities at a company or your academic achievements in an educational background section. /// - body (content): The body of the resume entry #let resume-item(body) = { - set text( - size: 10pt, - style: "normal", - weight: "light", - fill: color-darknight, - ) - set block( - above: 0.75em, - below: 1.25em, - ) + set text(size: 10pt, style: "normal", weight: "light", fill: color-darknight) + set block(above: 0.75em, below: 1.25em) set par(leading: 0.65em) block(above: 0.5em)[ #body @@ -525,11 +467,7 @@ /// *Example:* /// #example(`resume.resume-gpa("3.5", "4.0")`) #let resume-gpa(numerator, denominator) = { - set text( - size: 12pt, - style: "italic", - weight: "light", - ) + set text(size: 12pt, style: "italic", weight: "light") text[Cumulative GPA: #box[#strong[#numerator] / #denominator]] } @@ -548,7 +486,7 @@ #let resume-skill-item(category, items) = { set block(below: 0.65em) set pad(top: 2pt) - + pad[ #grid( columns: (20fr, 80fr), @@ -558,11 +496,7 @@ == #category ], align(left)[ - #set text( - size: 11pt, - style: "normal", - weight: "light", - ) + #set text(size: 11pt, style: "normal", weight: "light") #items.join(", ") ], ) @@ -575,10 +509,11 @@ #let default-closing(lang_data) = { align(bottom)[ - #text(weight: "light", style: "italic")[ #linguify( - "attached", + #text(weight: "light", style: "italic")[ + #linguify("attached", from: lang_data)#sym.colon #linguify( + "curriculum-vitae", from: lang_data, - )#sym.colon #linguify("curriculum-vitae", from: lang_data)] + )] ] } @@ -602,7 +537,7 @@ accent-color: default-accent-color, language: "en", font: ("Source Sans Pro", "Source Sans 3"), - header-font: ("Roboto"), + header-font: "Roboto", show-footer: true, closing: none, paper-size: "a4", @@ -612,26 +547,24 @@ if type(accent-color) == str { accent-color = rgb(accent-color) } - + // language data let lang_data = toml("lang.toml") - + if closing == none { closing = default-closing(lang_data) } - + show: body => context { set document( author: author.firstname + " " + author.lastname, - title: lflib._linguify( - "cover-letter", - lang: language, - from: lang_data, - ).ok, + title: lflib + ._linguify("cover-letter", lang: language, from: lang_data) + .ok, ) body } - + set text( font: font, lang: language, @@ -639,7 +572,7 @@ fill: color-darkgray, fallback: true, ) - + set page( paper: paper-size, margin: (left: 15mm, right: 15mm, top: 10mm, bottom: 10mm), @@ -652,93 +585,66 @@ )] else [], footer-descent: 0pt, ) - + // set paragraph spacing - set par( - spacing: 0.75em, - justify: true, - ) - - set heading( - numbering: none, - outlined: false, - ) - + set par(spacing: 0.75em, justify: true) + + set heading(numbering: none, outlined: false) + show heading: it => [ - #set block( - above: 1em, - below: 1em, - ) - #set text( - size: 16pt, - weight: "regular", - ) - + #set block(above: 1em, below: 1em) + #set text(size: 16pt, weight: "regular") + #align(left)[ #text[#strong[#text(accent-color)[#it.body]]] #box(width: 1fr, line(length: 100%)) ] ] - + let name = { align(right)[ #pad(bottom: 5pt)[ #block[ - #set text( - size: 32pt, - style: "normal", - font: header-font, - ) + #set text(size: 32pt, style: "normal", font: header-font) #if language == "zh" or language == "ja" [ - #text( - accent-color, - weight: "thin", - )[#author.firstname]#text(weight: "bold")[#author.lastname] + #text(accent-color, weight: "thin")[#author.firstname]#text( + weight: "bold", + )[#author.lastname] ] else [ #text(accent-color, weight: "thin")[#author.firstname] #text(weight: "bold")[#author.lastname] ] - + ] ] ] } - + let positions = { - set text( - accent-color, - size: 9pt, - weight: "regular", - ) + set text(accent-color, size: 9pt, weight: "regular") align(right)[ #__apply_smallcaps( - author.positions.join( - text[#" "#sym.dot.c#" "], - ), - use-smallcaps + author.positions.join(text[#" "#sym.dot.c#" "]), + use-smallcaps, ) ] } - + let address = { - set text( - size: 9pt, - weight: "bold", - fill: color-gray, - ) + set text(size: 9pt, weight: "bold", fill: color-gray) align(right)[ #if ("address" in author) [ #author.address ] ] } - + let contacts = { set box(height: 9pt) - + let separator = [ #box(sym.bar.v) ] let author_list = () - + if ("phone" in author) { author_list.push[ #phone-icon @@ -761,7 +667,9 @@ author_list.push[ #linkedin-icon #box[ - #link("https://www.linkedin.com/in/" + author.linkedin)[#author.firstname #author.lastname] + #link( + "https://www.linkedin.com/in/" + author.linkedin, + )[#author.firstname #author.lastname] ] ] } @@ -777,22 +685,18 @@ #box[#link(author.website)[#author.website]] ] } - - + + align(right)[ - #set text( - size: 8pt, - weight: "light", - style: "normal", - ) + #set text(size: 8pt, weight: "light", style: "normal") #author_list.join(separator) ] } - + let letter-heading = { grid( columns: (1fr, 2fr), - rows: (100pt), + rows: 100pt, align(left + horizon)[ #block( clip: true, @@ -811,19 +715,18 @@ ], ) } - + let signature = { align(bottom)[ #pad(bottom: 2em)[ - #text(weight: "light")[#linguify( - "sincerely", - from: lang_data, - )#if language != "de" [#sym.comma]] \ + #text(weight: "light")[#linguify("sincerely", from: lang_data)#if ( + language != "de" + ) [#sym.comma]] \ #text(weight: "bold")[#author.firstname #author.lastname] \ \ ] ] } - + // actual content letter-heading body @@ -847,7 +750,7 @@ ][ #text(weight: "light", style: "italic", size: 9pt)[#date] ] - + #pad(top: 0.65em, bottom: 0.65em)[ #text(weight: "regular", fill: color-gray, size: 9pt)[ #__apply_smallcaps(entity-info.name, use-smallcaps) \ @@ -864,7 +767,7 @@ /// - dear (string): optional field for redefining the "dear" variable #let letter-heading(job-position: "", addressee: "", dear: "") = { let lang_data = toml("lang.toml") - + // TODO: Make this adaptable to content underline(evade: false, stroke: 0.5pt, offset: 0.3em)[ #text(weight: "bold", size: 12pt)[#linguify( diff --git a/scripts/format b/scripts/format index b7b47a4..ea71371 100755 --- a/scripts/format +++ b/scripts/format @@ -1,4 +1,3 @@ #!/usr/bin/env bash set -eu - -find . -iname "*.typ" | xargs typstyle -i \ No newline at end of file +find . -iname "*.typ" | xargs typstyle -i diff --git a/scripts/package b/scripts/package index 57013fb..24a1a39 100755 --- a/scripts/package +++ b/scripts/package @@ -27,40 +27,40 @@ readarray -t ignores < <(grep -v '^#' .typstignore | grep '[^[:blank:]]') # recursively print all files that are not excluded via .typstignore function enumerate { - local root="$1" - if [[ -f "$root" ]]; then - echo "$root" - else - local files - readarray -t files < <(find "$root" \ + local root="$1" + if [[ -f "$root" ]]; then + echo "$root" + else + local files + readarray -t files < <(find "$root" \ -mindepth 1 -maxdepth 1 \ -not -name .git \ -not -name .typstignore) - # declare -p files >&2 + # declare -p files >&2 - local f - for f in "${files[@]}"; do - local include - include=1 + local f + for f in "${files[@]}"; do + local include + include=1 - local ignore - for ignore in "${ignores[@]}"; do - if [[ "$ignore" =~ ^! ]]; then - ignore="${ignore:1}" - if [[ "$f" == ./$ignore ]]; then - # echo "\"$f\" matched \"!$ignore\"" >&2 - include=1 - fi - elif [[ "$f" == ./$ignore ]]; then - # echo "\"$f\" matched \"$ignore\"" >&2 - include=0 - fi - done - if [[ "$include" == 1 ]]; then - enumerate "$f" - fi - done - fi + local ignore + for ignore in "${ignores[@]}"; do + if [[ "$ignore" =~ ^! ]]; then + ignore="${ignore:1}" + if [[ "$f" == ./$ignore ]]; then + # echo "\"$f\" matched \"!$ignore\"" >&2 + include=1 + fi + elif [[ "$f" == ./$ignore ]]; then + # echo "\"$f\" matched \"$ignore\"" >&2 + include=0 + fi + done + if [[ "$include" == 1 ]]; then + enumerate "$f" + fi + done + fi } # List of all files that get packaged diff --git a/template/coverletter.typ b/template/coverletter.typ index eec8b33..a359700 100644 --- a/template/coverletter.typ +++ b/template/coverletter.typ @@ -26,7 +26,7 @@ // set this to `none` to show the default or remove it completely closing: [], // see typst "page" documentation for more options - paper-size: "us-gov-legal" + paper-size: "us-gov-legal", ) #hiring-entity-info(entity-info: ( @@ -36,10 +36,7 @@ city: "MOUNTAIN VIEW, CA 94043", )) -#letter-heading( - job-position: "Software Engineer", - addressee: "Sir or Madame", -) +#letter-heading(job-position: "Software Engineer", addressee: "Sir or Madame") = About Me #coverletter-content[ diff --git a/template/coverletter2.typ b/template/coverletter2.typ index b6affe8..8378e54 100644 --- a/template/coverletter2.typ +++ b/template/coverletter2.typ @@ -26,10 +26,7 @@ city: "MOUNTAIN VIEW, CA 94043", )) -#letter-heading( - job-position: "Software Engineer", - addressee: "Sir or Madame", -) +#letter-heading(job-position: "Software Engineer", addressee: "Sir or Madame") #coverletter-content[ #lorem(100) diff --git a/template/resume.typ b/template/resume.typ index 523965f..b2ce34f 100644 --- a/template/resume.typ +++ b/template/resume.typ @@ -56,10 +56,7 @@ #lorem(72) ] -#resume-entry( - title: "Intern", - location: "Example City, EX", -) +#resume-entry(title: "Intern", location: "Example City, EX") #resume-item[ - #lorem(20) @@ -95,15 +92,21 @@ = Skills -#resume-skill-item( - "Languages", - (strong("C++"), strong("Python"), "Java", "C#", "JavaScript", "TypeScript"), -) +#resume-skill-item("Languages", ( + strong("C++"), + strong("Python"), + "Java", + "C#", + "JavaScript", + "TypeScript", +)) #resume-skill-item("Spoken Languages", (strong("English"), "Spanish")) -#resume-skill-item( - "Programs", - (strong("Excel"), "Word", "Powerpoint", "Visual Studio"), -) +#resume-skill-item("Programs", ( + strong("Excel"), + "Word", + "Powerpoint", + "Visual Studio", +)) = Education diff --git a/tests/resume/test.typ b/tests/resume/test.typ index a7659fe..5dda9ba 100644 --- a/tests/resume/test.typ +++ b/tests/resume/test.typ @@ -1,13 +1,8 @@ #import "@local/modern-cv:0.8.0": * // setup the document like we do for the resume -#let font = ("Source Sans 3") -#set text( - font: font, - size: 11pt, - fill: color-darkgray, - fallback: true, -) +#let font = "Source Sans 3" +#set text(font: font, size: 11pt, fill: color-darkgray, fallback: true) #set page( paper: "a4", @@ -19,21 +14,12 @@ // set paragraph spacing #set par(spacing: 0.75em, justify: true) -#set heading( - numbering: none, - outlined: false, -) +#set heading(numbering: none, outlined: false) #show heading.where(level: 1): it => [ - #set block( - above: 1em, - below: 1em, - ) - #set text( - size: 16pt, - weight: "regular", - ) + #set block(above: 1em, below: 1em) + #set text(size: 16pt, weight: "regular") #align(left)[ #let color = if colored-headers { @@ -48,20 +34,12 @@ ] #show heading.where(level: 2): it => { - set text( - color-darkgray, - size: 12pt, - style: "normal", - weight: "bold", - ) + set text(color-darkgray, size: 12pt, style: "normal", weight: "bold") it.body } #show heading.where(level: 3): it => { - set text( - size: 10pt, - weight: "regular", - ) + set text(size: 10pt, weight: "regular") smallcaps[#it.body] } @@ -77,19 +55,10 @@ ) // resume-entry also support omitting the date and description -#resume-entry( - title: "Title", - location: "Location", -) +#resume-entry(title: "Title", location: "Location") -#resume-certification( - "Certified Scrum Master (CSM)", - "Jan 2022", -) +#resume-certification("Certified Scrum Master (CSM)", "Jan 2022") -#resume-skill-item( - "Programming", - (strong["C++"], "Python", "Java"), -) +#resume-skill-item("Programming", (strong["C++"], "Python", "Java")) #resume-gpa("3.5", "4.0") diff --git a/tests/utilities/test.typ b/tests/utilities/test.typ index 25db408..023b5db 100644 --- a/tests/utilities/test.typ +++ b/tests/utilities/test.typ @@ -1,13 +1,8 @@ #import "@local/modern-cv:0.8.0": * // setup the document like we do for the resume -#let font = ("Source Sans 3") -#set text( - font: font, - size: 11pt, - fill: color-darkgray, - fallback: true, -) +#let font = "Source Sans 3" +#set text(font: font, size: 11pt, fill: color-darkgray, fallback: true) #set page( paper: "a4", @@ -19,21 +14,12 @@ // set paragraph spacing #set par(spacing: 0.75em, justify: true) -#set heading( - numbering: none, - outlined: false, -) +#set heading(numbering: none, outlined: false) #show heading.where(level: 1): it => [ - #set block( - above: 1em, - below: 1em, - ) - #set text( - size: 16pt, - weight: "regular", - ) + #set block(above: 1em, below: 1em) + #set text(size: 16pt, weight: "regular") #align(left)[ #let color = if colored-headers { @@ -48,20 +34,12 @@ ] #show heading.where(level: 2): it => { - set text( - color-darkgray, - size: 12pt, - style: "normal", - weight: "bold", - ) + set text(color-darkgray, size: 12pt, style: "normal", weight: "bold") it.body } #show heading.where(level: 3): it => { - set text( - size: 10pt, - weight: "regular", - ) + set text(size: 10pt, weight: "regular") smallcaps[#it.body] }