diff --git a/Makefile b/Makefile index 365449f..de980ec 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,8 @@ resume: resume.typ typst compile --input lang=en resume.typ build/resume_en.pdf typst compile --input lang=de resume.typ build/resume_de.pdf -letter: letter.typ - typst compile --input lang=en letter.typ build/letter_en.pdf - typst compile --input lang=de letter.typ build/letter_de.pdf +letter: letter.qmd templates/letter.latex + poetry run quarto render letter.qmd clean: rm -f *CV.aux *CV.bcf *CV.log *CV.out *CV.run.xml *CV.pdf short_CV.tex long_CV.tex *CV.bbl *CV.blg *yaml_CV.md diff --git a/README.md b/README.md deleted file mode 100644 index ae62ba2..0000000 --- a/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Data-driven CV & resume - -My personal CV and resume files, automatically generated from a multi-lingual -yaml data file. - -The CV contains a full run-down of my educational and job experience to date, -while the resume is more compact, reduced to a single page -and can be tailored for a specific job area or expertise. - -Is called like the following: - -```typst -#resume( - yaml("content.yml"), - main: ("experience", "education", "volunteering", "skills", "languages"), - sidebar: ("volunteering", "skills") -) -``` - -This is the default invocation, though sidebar and main body sections can be exchanged at will. - -TODO: - -- [x] move double-resume sources (per langauge) to a variable or similar -- [x] separate volunteering from skills section -- [_] one function per skill section -- [_] resume prep: - - [ ] make experience groupable by client / short version - - [ ] enable display/hiding of sections/entries by tags? - -- [x] migrate to typst template? -- [x] ! Fix german summary to be like English summary -- [_] generalized entry? - Would have 'title', 'place', 'date', 'type'/'tags' + potential - 'publication', 'bullets' - -## Typst-driven branch - -- [x] Fix publication '\&'s -- [x] Fix en-dash/em-dash (e.g. in years) -- [x] Producable from yaml content -- [x] Can be switched between Ger/En -- [x] Try sidebar version - - [ ] Generalize sidebar version through abstraction/extractions -- [ ] unify items: experience/education/(thesis?) diff --git a/content.yml b/content.yml index 93b6526..c862e1a 100644 --- a/content.yml +++ b/content.yml @@ -26,24 +26,12 @@ summary: en: | Since completing the EU-funded European Master of Global Studies Erasmus Mundus programme in 2021, I have acted as a research consultant focused on processes of inequality and poverty reduction, spatialization and collective organization, primarily through the lens of labour market policies. - Through producing the development research literature I have developed a broad range of skills in data acquisition, organization and visualization, as well as manuscript editing and reference management. Additionally, I have gained insights into event management, teaching assistance, content creation, system and web administration. Beyond professional work I strive to foster the development of free and open software and open science without barriers. + Through producing the development research literature I have developed a broad range of skills in data acquisition, organization and visualization, as well as manuscript editing and reference management. Additionally, I have gained insights into event management, teaching assistance, content creation, system administration and website management. Beyond professional work I foster the development of free and open software and open science without barriers. I welcome opportunities to deepen my expertise in these topics, in addition to those expanding my range of applicable skills. -experience_types: - 1: - de: Selbstständiger Schriftsteller Forschung - en: Independent research consultant - 2: - de: Honorararbeit - en: Salaried work - 3: - de: Gewerbeschein - en: Trade license - experience: - - typeid: 1 - date: + - date: de: 2024 en: 2024 title: @@ -65,10 +53,9 @@ experience: - date: de: 2023--2024 en: 2023--2024 - typeid: 1 title: de: Externer Forscher, Ungleichheiten auf dem Arbeitsmarkt - en: External researcher, Inequalities on the labour market + en: External researcher, Inequalities on the Labour market place: de: ILO en: ILO @@ -85,7 +72,6 @@ experience: - date: de: 2023 en: 2023 - typeid: 1 title: de: Consultant, Forschungsarbeit für nachhaltige Beschaffung in internationaler Logistik en: Consultant, Research on sustainable procurement in international logistics @@ -102,7 +88,6 @@ experience: - date: de: 2022 en: 2022 - typeid: 1 title: de: Consultant, Datenbankforschung internationale Hilfsgelder en: Consultant, Database research international aid funds @@ -119,7 +104,6 @@ experience: - date: de: 2022 en: 2022 - typeid: 1 title: de: Redaktionsarbeit, Soziale Absicherung und Widerstandsfähigkeit en: Editorial work, Social Protection and Resilience, Roskilde University @@ -139,7 +123,6 @@ experience: - date: de: 2022 en: 2022 - typeid: 1 title: de: Forschungsassistenz, Entwicklungsprojekte zur Reduzierung Ungleichheitstrends en: Research Assistant, Development projects to reduce inequality trends @@ -160,7 +143,6 @@ experience: - date: de: 2022 en: 2022 - typeid: 1 title: de: Consultant, Review Verknüpfung sozialer Schutz, Produktivität und Formalisierung en: Consultant, Social Protection, Productivity and Formalization Nexus Review @@ -180,7 +162,6 @@ experience: - date: de: 2022 en: 2022 - typeid: 1 title: de: Consultant, Review Arbeitsmarktpolitiken in Asien und dem Pazifik en: Consultant, Labour Market Policies Review in Asia and the Pacific @@ -198,7 +179,6 @@ experience: - date: de: 2021 en: 2021 - typeid: 1 title: de: Forschungsassistenz, Informelle Organisierung und Absicherung en: Research Assistant, Informal Organization and Social Security @@ -218,7 +198,6 @@ experience: - date: de: 2021 en: 2021 - typeid: 1 title: de: Redakteur, Soziale Absicherung informeller Arbeiter (SPIWORK) en: Editorial Assistant, Social Protection of Informal Workers (SPIWORK) @@ -238,7 +217,6 @@ experience: - date: de: 2018--2019 en: 2018--2019 - typeid: 2 title: de: Akademische Hilfskraft, Institut für Amerikastudien en: Academic Assistant, Institute of American Studies @@ -255,7 +233,6 @@ experience: - date: de: 2017--2019 en: 2017--2019 - typeid: 2 title: de: Studentische Hilfskraft, Professor Crister S. Garrett en: Student Assistant, Professor Crister S. Garrett @@ -272,7 +249,6 @@ experience: - date: de: 2018 en: 2018 - typeid: 2 title: de: Lehrassistenz, Transatlantische Sommerschule Cultures of Security en: Teaching Assistant, Trans Atlantic Summer School Cultures of Security @@ -289,7 +265,6 @@ experience: - date: de: 2017--2018 en: 2017--2018 - typeid: 2 title: de: Content-Management, Bachelor Plus/Alumni-System en: Content Management, Bachelor Plus/Alumni System @@ -306,8 +281,6 @@ experience: - date: de: 2014--2018 en: 2014--2018 - typeid: 2 - hidden: true # TODO: Allow hiding entries like this? title: de: Verkaufsassistent und Eventhelfer für historische Märkte en: Sales Assistant and Event Support for Historical Markets @@ -352,10 +325,10 @@ education: en: 2018 - place: de: HTWK Leipzig, Deutschland - en: HTWK Leipzig, Germany + en: HTWK Leipzig, Deutschland title: - de: Medieninformatik, BSc (nicht abg.) - en: Media Computer Science, BSc (not compl.) + de: Medieninformatik, BSc (nicht abgeschlossen) + en: Media Computer Science, BSc (not completed) date: de: 2015 en: 2015 diff --git a/cv.typ b/cv.typ index 518cd71..89bb34c 100644 --- a/cv.typ +++ b/cv.typ @@ -11,290 +11,266 @@ // $ typst compile --input lang=de cv.typ // #let lang = { - if "lang" in sys.inputs and sys.inputs.lang == "de" { - "de" - } else { - "en" - } + if "lang" in sys.inputs and sys.inputs.lang == "de" { + "de" + } else { + "en" + } } -#let sel_word_lang(de: "", en: "") = { - if lang == "de" { - de - } else { - en - } +#let sel_word_lang(de: "", en:"") = { + if lang == "de" { + de + } else { + en + } } #let _columns_3(left_body, center_body, right_body) = { - block[ - #box(width: 1fr)[ - #align(left)[#left_body] + block[ + #box(width: 1fr)[ + #align(left)[#left_body] + ] + #box(width: 1fr)[ + #align(center)[#center_body] + ] + #box(width: 1fr)[ + #align(right)[#right_body] + ] ] - #box(width: 1fr)[ - #align(center)[#center_body] - ] - #box(width: 1fr)[ - #align(right)[#right_body] - ] - ] } #let header(about, columns: (1.5fr, 1fr, 1fr)) = { - [= #about.fullname] - let contact_fields = ( - for c in about.contact { - if "link" in c { - ([#c.icon ~ #link(c.link)[#c.text]],) - } else { - ([#c.icon ~ #c.text],) - } - } - ) - grid( - columns: columns, - gutter: 5pt, - ..contact_fields - ) + [= #about.fullname]; + let contact_fields = (for c in about.contact { + if "link" in c { + ([#c.icon ~ #link(c.link)[#c.text]],) + } else { + ([#c.icon ~ #c.text],) + } + }) + grid( + columns: columns, + gutter: 5pt, + ..contact_fields + ); } #let subdued(body) = { - block(inset: 5%, width: 85%, text(fill: luma(150), body)) + block(inset: 5%, width: 85%, text(fill:luma(150), body)) } #let entry(item: ()) = { - if "title" in item { - [*#item.title.at(lang)*] - } - if "place" in item { if "title" in item { - [, ] + [*#item.title.at(lang)*] } - [_#item.place.at(lang)_] - } - [#h(1fr)] - if "date" in item { - [ _#item.date.at(lang)_ \ ] - } - if "bullets" in item { - for bullet in item.bullets { - [- #bullet.at(lang)] + if "place" in item { + if "title" in item { + [, ] + } + [_#item.place.at(lang)_] + } + [#h(1fr)] + if "date" in item { + [ _#item.date.at(lang)_ \ ] + } + if "bullets" in item { + for bullet in item.bullets { + [- #bullet.at(lang)] + } + } + if "publication" in item { + subdued[#item.publication.at(lang) \ ] + }; + if "abstract" in item { + subdued[#item.abstract.at(lang) \ ] } - } - if "publication" in item { - subdued[#item.publication.at(lang) \ ] - } - if "abstract" in item { - subdued[#item.abstract.at(lang) \ ] - } } -#let horizon_line() = { - v(-3pt) - line(length: 100%) - v(-5pt) -} +#let horizon_line() = {v(-3pt); line(length: 100%); v(-5pt)} -#let section_header(title) = { - [== #title] - horizon_line() -}; +#let section_header(title) = {[== #title]; horizon_line()}; #let section(title: "Section", entries: (), body) = { - section_header(title) - if body == none or body == [] { - for e in entries { - entry(item: e) + section_header(title); + if body == none or body == [] { + for e in entries { + entry(item:e) + } + } else { + body } - } else { - body - } }; // Slightly re-styled entry with PLACE first and TITLE second #let education_entry(item: ()) = { - assert( - "place" in item and "title" in item and "date" in item, - message: "Education items require place, program and date.", - ) - [*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)] - [ _#item.date.at(lang)_ \ ] + assert("place" in item and "title" in item and "date" in item, message: "Education items require place, program and date."); + [*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)]; + [ _#item.date.at(lang)_ \ ]; } // Restyled entry with PLACE not emphasized like usual, and no date but an abstract #let thesis_entry(item: ()) = { - assert("title" in item and "place" in item, message: "Thesis items require type and title.") - [*#item.title.at(lang)* #item.place.at(lang) #h(1fr)] - [#par(item.abstract.at(lang))] + assert("title" in item and "place" in item, message: "Thesis items require type and title."); + [*#item.title.at(lang)* #item.place.at(lang) #h(1fr)]; + [#par(item.abstract.at(lang))] } // skill-specific entry, changing its style for sidebar #let skill_item(item: (), is_sidebar: false) = { - let side_list(body) = if is_sidebar { list(body) } else { par(body) } - for skill in item { - side_list({ - [*#skill.name.at(lang)*] - if is_sidebar [\ ] else [ (] - for (i, v) in skill.items.enumerate() { - [#v.at(lang)] - if i < skill.items.len() - 1 { - [, ] - } - } - if not is_sidebar [)] - }) - } + let side_list(body) = if is_sidebar {list(body)} else {par(body)} + for skill in item { + side_list({ + [*#skill.name.at(lang)*] + if is_sidebar [\ ] else [ (] + for (i,v) in skill.items.enumerate() { + [#v.at(lang)] + if i < skill.items.len() - 1 { + [, ] + } + } + if not is_sidebar [)] + }) + } } #let cv(contents, use_sidebar: false) = { - set text(lang: lang) + set text(lang: lang) - let date_formatting = { - if lang == "de" { - "[day]. [month repr:long] [year]" - } else { - "[month repr:long] [day], [year]" + let date_formatting = { + if lang == "de" { + "[day]. [month repr:long] [year]" + } else { + "[month repr:long] [day], [year]" + } } - } - set page( - paper: "a4", - margin: (x: 0.9cm, y: 1.3cm), - footer: [ - #set text( - fill: luma(200), - size: 8pt, - ) - #_columns_3[ - #smallcaps[#datetime.today().display(date_formatting)] - ][ - #smallcaps[#contents.about.fullname] - ][ - #context counter(page).display() - ] - ], - ) + set page( + paper: "a4", + margin: (x: 0.9cm, y: 1.3cm), + footer: [ + #set text( + fill: luma(200), + size: 8pt, + ) + #_columns_3[ + #smallcaps[#datetime.today().display(date_formatting)] + ][ + #smallcaps[#contents.about.fullname] + ][ + #counter(page).display() + ] + ], + ) - set par(justify: true) + set par(justify: true) - header(contents.about) + header(contents.about) - let body = { - if "summary" in contents { - section( - title: "", - { - contents.summary.at(lang) - }, - ) + let body = { + if "summary" in contents { + section(title:"", { + contents.summary.at(lang) + }) + }; + + if "experience" in contents { + let title = sel_word_lang(en:"Professional Experience", de:"Berufserfahrung") + section(title: title, entries:contents.experience)[] + } + + if "education" in contents { + let title = sel_word_lang(en:"Education", de:"Ausbildung") + section(title: title, entries:contents.thesis + contents.education)[] + } + + if not use_sidebar { + if "volunteering" in contents { + let title = sel_word_lang(en:"Volunteer Work", de:"Ehrenamt") + section(title: title, entries:contents.volunteering)[] + } + + if "skills" in contents { + let title = sel_word_lang(en:"Qualifications", de:"Qualifikationen") + section(title: title, { + skill_item(item:contents.skills) + }) + } + + if "languages" in contents { + let title = sel_word_lang(en:"Languages", de:"Sprachen") + section(title: title, { + skill_item(item:contents.languages) + }) + } + } } - if "experience" in contents { - let title = sel_word_lang(en: "Professional Experience", de: "Berufserfahrung") - section(title: title, entries: contents.experience)[] - } + let sidebar = { + if "volunteering" in contents { + let title = sel_word_lang(en:"Volunteer Work", de:"Ehrenamt") + [== #title] + for e in contents.volunteering { + [ + - *#e.title.at(lang)* (#e.date.at(lang)) + #par(e.bullets.at(0).at(lang)) \ + ] + } + } - if "education" in contents { - let title = sel_word_lang(en: "Education", de: "Ausbildung") - section(title: title, entries: contents.thesis + contents.education)[] + if "languages" in contents { + let title = sel_word_lang(en:"Languages", de:"Sprachen") + [== #title] + skill_item(item:contents.languages, is_sidebar: true) + [\ ] + } + + if "skills" in contents { + let title = sel_word_lang(en:"Qualifications", de:"Kenntnisse") + [== #title] + skill_item(item:contents.skills, is_sidebar: true) + } } if not use_sidebar { - if "volunteering" in contents { - let title = sel_word_lang(en: "Volunteer Work", de: "Ehrenamt") - section(title: title, entries: contents.volunteering)[] - } - - if "skills" in contents { - let title = sel_word_lang(en: "Qualifications", de: "Qualifikationen") - section( - title: title, - { - skill_item(item: contents.skills) - }, - ) - } - - if "languages" in contents { - let title = sel_word_lang(en: "Languages", de: "Sprachen") - section( - title: title, - { - skill_item(item: contents.languages) - }, - ) - } - } - } - - let sidebar = { - if "volunteering" in contents { - let title = sel_word_lang(en: "Volunteer Work", de: "Ehrenamt") - [== #title] - for e in contents.volunteering { - [ - - *#e.title.at(lang)* (#e.date.at(lang)) - #par(e.bullets.at(0).at(lang)) \ - ] - } - } - - if "languages" in contents { - let title = sel_word_lang(en: "Languages", de: "Sprachen") - [== #title] - skill_item(item: contents.languages, is_sidebar: true) - [\ ] - } - - if "skills" in contents { - let title = sel_word_lang(en: "Qualifications", de: "Kenntnisse") - [== #title] - skill_item(item: contents.skills, is_sidebar: true) - } - } - - if not use_sidebar { - body - return - } - let margin = 1pt - grid( - columns: (2fr, 1fr), - block( - outset: 0pt, - inset: (top: 0.4 * margin, right: 0pt, rest: margin), - stroke: none, - width: 100%, - { - set block(above: 10pt) - show heading.where(level: 1): it => style(s => { - let h = text(size: 18pt, upper(it)) - let dim = measure(h, s) - stack( - dir: ltr, - h, - place( - dy: 7pt, - dx: 10pt, - horizon + left, - line(stroke: accent-color, length: 100% - dim.width - 10pt), - ), - ) - }) body - }, - ), - { - v(20pt) - set block(inset: (left: 20 * margin, right: 20 * margin)) - show heading: it => align(right, upper(it)) - set list(marker: "") - show list: it => { - set par(justify: false) - align(right, block(it)) - } - sidebar - }, - ) + return + } + let margin = 1pt + grid( + columns: (2fr, 1fr), + block(outset: 0pt, inset: (top: 0.4 * margin, right: 0pt, rest: margin), stroke: none, width: 100%, { + set block(above: 10pt) + show heading.where(level: 1): it => style(s => { + let h = text(size: 18pt, upper(it)) + let dim = measure(h, s) + stack( + dir: ltr, + h, + place( + dy: 7pt, + dx: 10pt, + horizon + left, + line(stroke: accent-color, length: 100% - dim.width - 10pt) + ), + ) + }) + body + }), + { + v(20pt) + set block(inset: (left: 20 * margin, right: 20 * margin)) + show heading: it => align(right, upper(it)) + set list(marker: "") + show list: it => { + set par(justify: false) + align(right, block(it)) + } + sidebar + } + ) + } -#cv.with(use_sidebar: false)(yaml("content.yml")) +#cv.with(use_sidebar: false)( + yaml("content.yml") +) diff --git a/resume.typ b/resume.typ index 6176dc6..6babff7 100644 --- a/resume.typ +++ b/resume.typ @@ -11,302 +11,265 @@ // $ typst compile --input lang=de cv.typ // #let lang = { - if "lang" in sys.inputs and sys.inputs.lang == "de" { - "de" - } else { - "en" - } + if "lang" in sys.inputs and sys.inputs.lang == "de" { + "de" + } else { + "en" + } +} +#let sel_word_lang(de: "", en:"") = { + if lang == "de" { + de + } else { + en + } } #let _columns_3(left_body, center_body, right_body) = { - block[ - #box(width: 1fr)[ - #align(left)[#left_body] + block[ + #box(width: 1fr)[ + #align(left)[#left_body] + ] + #box(width: 1fr)[ + #align(center)[#center_body] + ] + #box(width: 1fr)[ + #align(right)[#right_body] + ] ] - #box(width: 1fr)[ - #align(center)[#center_body] - ] - #box(width: 1fr)[ - #align(right)[#right_body] - ] - ] } #let header(about, columns: (1.5fr, 1fr, 1fr)) = { - [= #about.fullname] - let contact_fields = ( - for c in about.contact { - if "link" in c { - ([#c.icon ~ #link(c.link)[#c.text]],) - } else { - ([#c.icon ~ #c.text],) - } - } - ) - grid( - columns: columns, - gutter: 5pt, - ..contact_fields - ) + [= #about.fullname]; + let contact_fields = (for c in about.contact { + if "link" in c { + ([#c.icon ~ #link(c.link)[#c.text]],) + } else { + ([#c.icon ~ #c.text],) + } + }) + grid( + columns: columns, + gutter: 5pt, + ..contact_fields + ); } #let subdued(body) = { - block(inset: 5%, width: 85%, text(fill: luma(150), body)) + block(inset: 5%, width: 85%, text(fill:luma(150), body)) } -#let by_client(experience: ()) = { - let by_client = (:) - - for item in experience { - let client = item.place.at(lang) - if client not in by_client { - by_client.insert(client, ()) - } - by_client.at(client).push((item.title.at(lang), item.date.at(lang))) - } - - for (client, jobs) in by_client { - [*#client*:] - for j in jobs { - [- #j.at(0) #h(1fr) #j.at(1)] - } - } -} - -#let by_experience_type(type: (), experience: ()) = { - let by_ty = (:) - for (id, desc) in type { - let matching_exp_items = experience.filter(item => int(item.typeid) == int(id)) - if matching_exp_items.len() == 0 { - return +#let freelance_by_client(experience:()) = { + let by_client = (:) + for item in experience { + let client = item.place.at(lang) + if client not in by_client { + by_client.insert(client, ()) + } + by_client.at(client).push((item.title.at(lang), item.date.at(lang) )) } - [=== _#desc.at(lang)_] - by_client(experience: matching_exp_items) - } + for (client, jobs) in by_client { + [*#client*:] + for j in jobs { + [- #j.at(0) #h(1fr) #j.at(1)] + } + } } #let entry(item: ()) = { - if "title" in item { - [*#item.title.at(lang)*] - } - if "place" in item { if "title" in item { - [, ] + [*#item.title.at(lang)*] } - [_#item.place.at(lang)_] - } - [#h(1fr)] - if "date" in item { - [ _#item.date.at(lang)_ \ ] - } - if "bullets" in item { - for bullet in item.bullets { - [- #bullet.at(lang)] + if "place" in item { + if "title" in item { + [, ] + } + [_#item.place.at(lang)_] + } + [#h(1fr)] + if "date" in item { + [ _#item.date.at(lang)_ \ ] + } + if "bullets" in item { + for bullet in item.bullets { + [- #bullet.at(lang)] + } + } + if "publication" in item { + subdued[#item.publication.at(lang) \ ] + }; + if "abstract" in item { + subdued[#item.abstract.at(lang) \ ] } - } - if "publication" in item { - subdued[#item.publication.at(lang) \ ] - } - if "abstract" in item { - subdued[#item.abstract.at(lang) \ ] - } } -#let horizon_line() = { - v(-3pt) - line(length: 100%) - v(-5pt) -} +#let horizon_line() = {v(-3pt); line(length: 100%); v(-5pt)} -#let section_header(title) = { - [== #title] - horizon_line() -}; +#let section_header(title) = {[== #title]; horizon_line()}; #let section(title: "Section", entries: (), body) = { - section_header(title) - if body == none or body == [] { - for e in entries { - entry(item: e) + section_header(title); + if body == none or body == [] { + for e in entries { + entry(item:e) + } + } else { + body } - } else { - body - } }; // Slightly re-styled entry with PLACE first and TITLE second #let education_entry(item: ()) = { - assert( - "place" in item and "title" in item and "date" in item, - message: "Education items require place, program and date.", - ) - [*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)] - [ _#item.date.at(lang)_ \ ] + assert("place" in item and "title" in item and "date" in item, message: "Education items require place, program and date."); + [*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)]; + [ _#item.date.at(lang)_ \ ]; } // Restyled entry with PLACE not emphasized like usual, and no date but an abstract #let thesis_entry(item: ()) = { - assert("title" in item and "place" in item, message: "Thesis items require type and title.") - [*#item.title.at(lang)* #item.place.at(lang) #h(1fr)] - [#par(item.abstract.at(lang))] + assert("title" in item and "place" in item, message: "Thesis items require type and title."); + [*#item.title.at(lang)* #item.place.at(lang) #h(1fr)]; + [#par(item.abstract.at(lang))] } // skill-specific entry, changing its style for sidebar #let skill_item(item: (), is_sidebar: false) = { - let side_list(body) = if is_sidebar { list(body) } else { par(body) } - for skill in item { - side_list({ - [*#skill.name.at(lang)*] - if is_sidebar [\ ] else [ (] - for (i, v) in skill.items.enumerate() { - [#v.at(lang)] - if i < skill.items.len() - 1 { - [, ] - } - } - if not is_sidebar [)] - }) - } + let side_list(body) = if is_sidebar {list(body)} else {par(body)} + for skill in item { + side_list({ + [*#skill.name.at(lang)*] + if is_sidebar [\ ] else [ (] + for (i,v) in skill.items.enumerate() { + [#v.at(lang)] + if i < skill.items.len() - 1 { + [, ] + } + } + if not is_sidebar [)] + }) + } } -#let resume(contents, main: ("experience", "education"), sidebar: ("volunteering", "languages", "skills")) = { - set text(lang: lang) +#let resume(contents) = { + set text(lang: lang) - let date_formatting = { - if lang == "de" { - "[day]. [month repr:long] [year]" - } else { - "[month repr:long] [day], [year]" + let date_formatting = { + if lang == "de" { + "[day]. [month repr:long] [year]" + } else { + "[month repr:long] [day], [year]" + } } - } - set page( - paper: "a4", - margin: (x: 0.9cm, y: 1.3cm), - footer: [ - #set text( - fill: luma(200), - size: 8pt, - ) - #_columns_3[ - #smallcaps[#datetime.today().display(date_formatting)] - ][ - #smallcaps[#contents.about.fullname] - ][ - #context counter(page).display() - ] - ], - ) + set page( + paper: "a4", + margin: (x: 0.9cm, y: 1.3cm), + footer: [ + #set text( + fill: luma(200), + size: 8pt, + ) + #_columns_3[ + #smallcaps[#datetime.today().display(date_formatting)] + ][ + #smallcaps[#contents.about.fullname] + ][ + #counter(page).display() + ] + ], + ) - set par(justify: true) + set par(justify: true) - header(contents.about) + header(contents.about) - let body = { - if "summary" in main and "summary" in contents { - section( - title: "", - { - contents.summary.at(lang) - }, - ) + let body = { +// if "summary" in contents { +// section(title:"", { +// contents.summary.at(lang) +// }) +// }; + + if "experience" in contents { + let title = sel_word_lang(en:"Professional Experience", de:"Berufserfahrung") + section(title: title)[] + freelance_by_client(experience:contents.experience) + + } + + if "education" in contents { + let title = sel_word_lang(en:"Education", de:"Ausbildung") + section(title: title, entries:contents.thesis + contents.education)[] + } + +// if "volunteering" in contents { +// let title = sel_word_lang(en:"Volunteer Work", de:"Ehrenamt") +// section(title: title, entries:contents.volunteering)[] +// } +// +// if "skills" in contents { +// let title = sel_word_lang(en:"Qualifications", de:"Qualifikationen") +// section(title: title, { +// skill_item(item:contents.skills) +// }) +// } +// +// if "languages" in contents { +// let title = sel_word_lang(en:"Languages", de:"Sprachen") +// section(title: title, { +// skill_item(item:contents.languages) +// }) +// } } - if "experience" in main and "experience" in contents { - let title = (en: "Professional Experience", de: "Berufserfahrung").at(lang) - section(title: title)[] - by_experience_type(experience: contents.experience, type: contents.experience_types) + let sidebar = { + if "volunteering" in contents { + let title = sel_word_lang(en:"Volunteer Work", de:"Ehrenamt") + [== #title] + for e in contents.volunteering { + [ + - *#e.title.at(lang)* (#e.date.at(lang)) + #par(e.bullets.at(0).at(lang)) \ + ] + } + } + + if "languages" in contents { + let title = sel_word_lang(en:"Languages", de:"Sprachen") + [== #title] + skill_item(item:contents.languages, is_sidebar: true) + [\ ] + } + + if "skills" in contents { + let title = sel_word_lang(en:"Qualifications", de:"Kenntnisse") + [== #title] + skill_item(item:contents.skills, is_sidebar: true) + } } - if "education" in main and "education" in contents { - let title = (en: "Education", de: "Ausbildung").at(lang) - section(title: title, entries: contents.thesis + contents.education)[] - } - - if "volunteering" in main and "volunteering" in contents { - let title = (en: "Volunteer Work", de: "Ehrenamt").at(lang) - section(title: title, entries: contents.volunteering)[] - } - - if "skills" in main and "skills" in contents { - let title = (en: "Qualifications", de: "Qualifikationen").at(lang) - section( - title: title, - { - skill_item(item: contents.skills) - }, - ) - } - - if "languages" in main and "languages" in contents { - let title = (en: "Languages", de: "Sprachen").at(lang) - section( - title: title, - { - skill_item(item: contents.languages) - }, - ) - } - } - - let sidebar = { - if "volunteering" in sidebar and "volunteering" in contents { - let title = (en: "Volunteer Work", de: "Ehrenamt").at(lang) - [== #title] - for e in contents.at("volunteering") { - [ - - *#e.title.at(lang)* (#e.date.at(lang)) - #par(e.bullets.at(0).at(lang)) \ - ] - } - } - - if "languages" in sidebar and "languages" in contents { - let title = (en: "Languages", de: "Sprachen").at(lang) - [== #title] - skill_item(item: contents.languages, is_sidebar: true) - [\ ] - } - - if "skills" in sidebar and "skills" in contents { - let title = (en: "Qualifications", de: "Kenntnisse").at(lang) - [== #title] - skill_item(item: contents.skills, is_sidebar: true) - } - } - - let margin = 1pt - grid( - columns: (2fr, 1fr), - block( - outset: 0pt, - inset: (top: 0.4 * margin, right: 0pt, rest: margin), - stroke: none, - width: 100%, - { - set block(above: 10pt) - show heading.where(level: 1): it => style(s => { - let h = text(size: 18pt, upper(it)) - let dim = measure(h, s) - stack( - dir: ltr, - h, - place( - dy: 7pt, - dx: 10pt, - horizon + left, - line(stroke: accent-color, length: 100% - dim.width - 10pt), - ), - ) - }) - body - }, - ), - align( - right, - block( - fill: luma(250), - width: 90%, + let margin = 1pt + grid( + columns: (2fr, 1fr), + block(outset: 0pt, inset: (top: 0.4 * margin, right: 0pt, rest: margin), stroke: none, width: 100%, { + set block(above: 10pt) + show heading.where(level: 1): it => style(s => { + let h = text(size: 18pt, upper(it)) + let dim = measure(h, s) + stack( + dir: ltr, + h, + place( + dy: 7pt, + dx: 10pt, + horizon + left, + line(stroke: accent-color, length: 100% - dim.width - 10pt) + ), + ) + }) + body + }), + align(right, block(fill: luma(250), width: 90%, { v(15pt) set block(inset: (left: 20 * margin, right: 20 * margin)) @@ -316,12 +279,14 @@ set par(justify: false) align(right, block(it)) } - sidebar + sidebar v(15pt) - }, - ), - ), - ) + })) + ) + } -#resume(yaml("content.yml")) +#resume( + yaml("content.yml") +) +