#import "utils.typ" // set rules #let setrules(uservars, doc) = { set text( font: uservars.bodyfont, size: uservars.fontsize, hyphenate: false, ) set list( spacing: uservars.linespacing ) set par( leading: uservars.linespacing, justify: true, ) doc } // show rules #let showrules(uservars, doc) = { // uppercase section headings show heading.where( level: 2, ): it => block(width: 100%)[ #set align(left) #set text(font: uservars.headingfont, size: 1em, weight: "bold") #if (uservars.at("headingsmallcaps", default:false)) { smallcaps(it.body) } else { // upper(it.body) it.body } #v(-0.75em) #line(length: 100%, stroke: 1pt + black) // draw a line ] // name title show heading.where( level: 1, ): it => block(width: 100%)[ #set text(font: uservars.headingfont, size: 2em, weight: "bold") #if (uservars.at("headingsmallcaps", default:false)) { smallcaps(it.body) } else { // upper(it.body) it.body } #v(2pt) ] doc } // set page layout #let cvinit(doc) = { doc = setrules(doc) doc = showrules(doc) doc } // address #let addresstext(info, uservars) = { if uservars.showAddress { block(width: 100%)[ #info.personal.location.city, #info.personal.location.region, #info.personal.location.country #v(-4pt) ] } else {none} } #let fa(body) = { set text(font:"FontAwesome") [#body] } #let contacttext(info, uservars) = block(width: 100%)[ #let profiles = ( box(link("mailto:" + info.personal.email)[#fa(" ") #info.personal.email]), if uservars.showNumber {box(link("tel:" + info.personal.phone)[#fa("") #info.personal.phone])} else {none}, if info.personal.url != none { box(link(info.personal.url)[#fa(" ") #info.personal.url.split("//").at(1)]) } ).filter(it => it != none) // filter out none elements from the profile array #if info.personal.profiles.len() > 0 { for profile in info.personal.profiles { profiles.push( box(link(profile.url)[#profile.username]) ) } } #set text(font: uservars.bodyfont, weight: "light", size: uservars.fontsize * 1) #pad(x: 0em)[ #profiles.join([#sym.space.en|#sym.space.en]) ] ] #let cvheading(info, uservars) = { align(center)[ = #info.personal.name #addresstext(info, uservars) #contacttext(info, uservars) ] } #let cvwork(info, isbreakable: true) = { if info.experience != none {block[ == Work Experience #for w in info.experience { block(width: 100%, breakable: isbreakable)[ #if w.url != none [ *#link(w.url)[#w.with]* #h(1fr) *#w.where* \ ] else [ *#w.with* #h(1fr) *#w.where* \ ] ] // create a block layout for each work entry let index = 0 for p in w.what { if index != 0 {v(0.6em)} block(width: 100%, breakable: isbreakable, above: 0.6em)[ // parse ISO date strings into datetime objects #let start = utils.strpdate(p.startDate) #let end = utils.strpdate(p.endDate) // line 2: position and date range #text(style: "italic")[#p.what] #h(1fr) #start #sym.dash.en #end \ // highlights or description #for hi in p.why [ - #eval(hi, mode: "markup") ] ] index = index + 1 } } ]} } #let cveducation(info, isbreakable: true) = { if info.education != none {block[ == Education #for edu in info.education { let start = utils.strpdate(edu.startDate) let end = utils.strpdate(edu.endDate) let edu-items = "" if edu.honors != none {edu-items = edu-items + "- *Honors*: " + edu.honors.join(", ") + "\n"} if edu.why != none {edu-items = edu-items + "- *Courses*: " + edu.why.join(", ") + "\n"} if edu.highlights != none { for hi in edu.highlights { edu-items = edu-items + "- " + hi + "\n" } edu-items = edu-items.trim("\n") } // create a block layout for each education entry block(width: 100%, breakable: isbreakable)[ // line 1: institution and location #if edu.url != none [ *#link(edu.url)[#edu.with]* #h(1fr) *#edu.what* \ ] else [ *#edu.with* #h(1fr) *#edu.what* \ ] // line 2: degree and date #text(style: "italic")[#edu.what] #h(1fr) #start #sym.dash.en #end \ #eval(edu-items, mode: "markup") ] } ]} } #let cvaffiliations(info, isbreakable: true) = { if info.affiliations != none {block[ == Leadership & Activities #for org in info.affiliations { // parse ISO date strings into datetime objects let start = utils.strpdate(org.startDate) let end = utils.strpdate(org.endDate) // create a block layout for each affiliation entry block(width: 100%, breakable: isbreakable)[ // line 1: organization and location #if org.url != none [ *#link(org.url)[#org.with]* #h(1fr) *#org.where* \ ] else [ *#org.with* #h(1fr) *#org.where* \ ] // line 2: position and date #text(style: "italic")[#org.position] #h(1fr) #start #sym.dash.en #end \ // highlights or description #if org.highlights != none { for hi in org.highlights [ - #eval(hi, mode: "markup") ] } else {} ] } ]} } #let cvprojects(info, isbreakable: true) = { if info.projects != none {block[ == Projects #for project in info.projects { // parse ISO date strings into datetime objects let start = utils.strpdate(project.startDate) let end = utils.strpdate(project.endDate) // create a block layout for each project entry block(width: 100%, breakable: isbreakable)[ // line 1: project name #if project.url != none [ *#link(project.url)[#project.name]* \ ] else [ *#project.name* \ ] // line 2: organization and date #text(style: "italic")[#project.affiliation] #h(1fr) #start #sym.dash.en #end \ // summary or description #for hi in project.highlights [ - #eval(hi, mode: "markup") ] ] } ]} } #let cvawards(info, isbreakable: true) = { if info.awards != none {block[ == Honors & Awards #for award in info.awards { // parse ISO date strings into datetime objects let date = utils.strpdate(award.date) // create a block layout for each award entry block(width: 100%, breakable: isbreakable)[ // line 1: award title and location #if award.url != none [ *#link(award.url)[#award.title]* #h(1fr) *#award.location* \ ] else [ *#award.title* #h(1fr) *#award.location* \ ] // line 2: issuer and date Issued by #text(style: "italic")[#award.issuer] #h(1fr) #date \ // summary or description #if award.highlights != none { for hi in award.highlights [ - #eval(hi, mode: "markup") ] } else {} ] } ]} } #let cvcertificates(info, isbreakable: true) = { if info.certificates != none {block[ == Licenses & Certifications #for cert in info.certificates { // parse ISO date strings into datetime objects let date = utils.strpdate(cert.date) // create a block layout for each certificate entry block(width: 100%, breakable: isbreakable)[ // line 1: certificate name #if cert.url != none [ *#link(cert.url)[#cert.name]* \ ] else [ *#cert.name* \ ] // line 2: issuer and date Issued by #text(style: "italic")[#cert.issuer] #h(1fr) #date \ ] } ]} } #let cvpublications(info, isbreakable: true) = { if info.publications != none {block[ == Research & Publications #for pub in info.publications { // parse ISO date strings into datetime objects let date = utils.strpdate(pub.releaseDate) // create a block layout for each publication entry block(width: 100%, breakable: isbreakable)[ // line 1: publication title #if pub.url != none [ *#link(pub.url)[#pub.name]* \ ] else [ *#pub.name* \ ] // line 2: publisher and date Published on #text(style: "italic")[#pub.publisher] #h(1fr) #date \ ] } ]} } #let cvskills(info, isbreakable: true) = { if (info.languages != none) or (info.skills != none) or (info.interests != none) {block(breakable: isbreakable)[ == Skills, Languages, Interests #if (info.languages != none) [ #let langs = () #for lang in info.languages { langs.push([#lang.language (#lang.fluency)]) } - *Languages*: #langs.join(", ") ] #if (info.skills != none) [ #for group in info.skills [ - *#group.category*: #group.skills.join(", ") ] ] #if (info.interests != none) [ - *Interests*: #info.interests.join(", ") ] ]} } #let cvreferences(info, isbreakable: true) = { if info.references != none {block[ == References #for ref in info.references { block(width: 100%, breakable: isbreakable)[ #if ref.url != none [ - *#link(ref.url)[#ref.name]*: "#ref.reference" ] else [ - *#ref.name*: "#ref.reference" ] ] } ]} else {} } #let endnote() = { place( bottom + right, block[ #set text(size: 5pt, font: "Consolas", fill: silver) Félix Desmaretz #datetime.today().display("[year]-[month]-[day]") ] ) }