401 lines
11 KiB
Plaintext
401 lines
11 KiB
Plaintext
#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 {
|
|
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(lang, 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(lang, 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.at("url", default: none) != 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(lang, info, uservars) = {
|
|
align(center)[
|
|
= #info.personal.name
|
|
#addresstext(lang, info, uservars)
|
|
#contacttext(lang, info, uservars)
|
|
]
|
|
}
|
|
|
|
#let cvsummary(info, isbreakable: true) = {
|
|
if info != none {
|
|
block(width: 100%, inset: ("left": 3%, "right": 3%))[#h(1em) #text(weight: "regular")[#info.summary]]
|
|
}
|
|
}
|
|
|
|
#let cvwork(lang, info, isbreakable: true) = {
|
|
if info.experience != none {
|
|
block[
|
|
== #info.experience.title
|
|
#for w in info.experience.content {
|
|
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(lang, p.startDate)
|
|
#let end = utils.strpdate(lang, p.endDate)
|
|
// line 2: position and date range
|
|
#text(weight: "semibold", size: 9.0pt, fill: luma(30.6%))[#p.what #h(1fr)
|
|
#start #sym.dash.en #end] \
|
|
// highlights or description
|
|
#if "technologies" in p and p.technologies != none [
|
|
#text(weight: "light", style: "italic")[
|
|
Technologies: #eval(p.technologies.join(" #sym.circle.filled.small "), mode: "markup")
|
|
]
|
|
]
|
|
#for hi in p.why [
|
|
- #text(weight: "light")[#eval(hi, mode: "markup")]
|
|
]
|
|
]
|
|
index = index + 1
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
#let cveducation(lang, info, isbreakable: true) = {
|
|
let education = info.education
|
|
if education != none {
|
|
block[
|
|
== #education.title
|
|
#for edu in education.content {
|
|
let start = utils.strpdate(lang, edu.startDate)
|
|
let end = utils.strpdate(lang, edu.endDate)
|
|
let eduurl = edu.at("url", default: none)
|
|
|
|
// create a block layout for each education entry
|
|
block(
|
|
width: 100%,
|
|
breakable: isbreakable,
|
|
)[
|
|
// line 1: institution and location
|
|
#if eduurl != none {
|
|
text(weight: "extrabold")[
|
|
#link(eduurl)[#edu.with] #h(1fr) #edu.where \
|
|
]
|
|
} else {
|
|
text(weight: "extrabold")[
|
|
#edu.with #h(1fr) #edu.where \
|
|
]
|
|
}
|
|
// line 2: degree and date
|
|
#text(weight: "semibold", size: 9.0pt, fill: luma(30.6%))[#edu.what #h(1fr)
|
|
#start #sym.dash.en #end] \
|
|
#if edu.why != none and edu.why.len() > 0 {
|
|
for hi in edu.why [
|
|
- #text(weight: "light")[#eval(hi, mode: "markup")]
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
#let cvprojects(lang, info, isbreakable: true) = {
|
|
let projects = info.projects
|
|
if projects != none {
|
|
block[
|
|
== #projects.title
|
|
#for project in projects.content {
|
|
// parse ISO date strings into datetime objects
|
|
let start = utils.strpdate(lang, project.startDate)
|
|
let end = utils.strpdate(lang, 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.what]* \
|
|
] else [
|
|
*#project.what* \
|
|
]
|
|
// line 2: organization and date
|
|
#if "with" in project and project.with != none [
|
|
#text(style: "italic")[#project.with] #h(1fr) #start #sym.dash.en #end \
|
|
]
|
|
// summary or description
|
|
#if "why" in project and project.why != none [
|
|
#for hi in project.why [
|
|
- #text(weight: "light")[#eval(hi, mode: "markup")]
|
|
]
|
|
]
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
#let cvaffiliations(lang, 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(lang, org.startDate)
|
|
let end = utils.strpdate(lang, 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 cvawards(lang, 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(lang, 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(lang, 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(lang, 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(lang, 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(lang, 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 cvlanguages(lang, info, isbreakable: true) = {
|
|
block(breakable: isbreakable)[
|
|
== #info.languages.title
|
|
|
|
#for lang in info.languages.content {
|
|
[- *#lang.title*#text(weight: "light")[: #lang.content]]
|
|
}
|
|
]
|
|
}
|
|
|
|
#let cvskills(lang, info, isbreakable: true, sortLexically: true) = {
|
|
block(
|
|
breakable: isbreakable,
|
|
)[
|
|
== #info.skills.title
|
|
|
|
#for skill in info.skills.content {
|
|
let baseContent = if sortLexically {
|
|
skill.content.sorted(key: x => {
|
|
if type(x) == dictionary {
|
|
x.keys().first()
|
|
} else { x }
|
|
})
|
|
} else {
|
|
skill.content
|
|
}
|
|
|
|
let skillContent = baseContent
|
|
.map(
|
|
x => {
|
|
if type(x) == dictionary {
|
|
[#x.keys().first() (#text(style: "italic")[#x.values().first().sorted().join[ #sym.circle.filled.tiny ]])]
|
|
} else {
|
|
[#x]
|
|
}
|
|
},
|
|
)
|
|
.join[ #sym.circle.filled.small ]
|
|
|
|
[- *#skill.title*#text(weight: "light")[: #skillContent]]
|
|
}
|
|
]
|
|
}
|
|
|
|
#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]")
|
|
])
|
|
}
|