(actually) add 0.1.0 of finely-crafted-cv template
This commit is contained in:
20 files changed
+888
No files matched your search
@@ -0,0 +1,228 @@
|
||||
#import "constants.typ": *
|
||||
#import "helpers.typ": *
|
||||
#import "state.typ": __get, __set
|
||||
|
||||
// Main resume function
|
||||
#let resume(
|
||||
name: "YOUR NAME HERE",
|
||||
tagline: none,
|
||||
paper: "us-letter",
|
||||
heading_font: HEADING_FONT,
|
||||
body_font: BODY_FONT,
|
||||
body_size: BODY_SIZE,
|
||||
email: none,
|
||||
phone: none,
|
||||
linkedin_username: none,
|
||||
keywords: "",
|
||||
thumbnail: none, // check out https://qrframe.kylezhe.ng/ for QR code generation
|
||||
body
|
||||
) = {
|
||||
// Save our settings needed in other functions
|
||||
__set("heading_font", heading_font)
|
||||
|
||||
// Document setup, mostly metadata in a PDF
|
||||
set document(
|
||||
title: "Résumé/CV of " + name,
|
||||
author: name,
|
||||
keywords: keywords,
|
||||
)
|
||||
|
||||
// Page setup, including header and footer
|
||||
set page(
|
||||
paper: paper,
|
||||
margin: PAGE_MARGIN,
|
||||
numbering: "1 / 1",
|
||||
header: context {
|
||||
if here().page() == 1 {
|
||||
text(
|
||||
size: HEADER_SIZE,
|
||||
grid(
|
||||
columns: (1fr, auto, auto, auto, auto, auto),
|
||||
gutter: 1em,
|
||||
align: center+horizon,
|
||||
"",
|
||||
icon_and_contact("icons/email.svg", link("mailto:" + email, email)),
|
||||
sym.divides,
|
||||
icon_and_contact("icons/phone.svg", link("tel:" + phone, phone)),
|
||||
sym.divides,
|
||||
icon_and_contact("icons/linkedin.svg", link("https://www.linkedin.com/in/" + linkedin_username, linkedin_username))
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
footer: context {
|
||||
let multi_page = counter(page).final().first() > 1
|
||||
let date = datetime.today().display("[month repr:long] [day], [year]")
|
||||
text(size: FOOTER_SIZE, weight: FOOTER_TEXT_WEIGHT, font: heading_font)[
|
||||
#grid(
|
||||
columns: (1fr, 1fr, 1fr),
|
||||
align: (left, center, right + horizon),
|
||||
// left column
|
||||
[Last updated: #date],
|
||||
// center column
|
||||
if multi_page { counter(page).display(both: true, "1 of 1") },
|
||||
// right column
|
||||
if thumbnail != none {
|
||||
move(dy: -0.25in, box(height: 0.5in, thumbnail))
|
||||
} else {
|
||||
[ ]
|
||||
}
|
||||
)
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
// Global text settings
|
||||
set text(font: body_font, size: body_size, weight: BODY_WEIGHT, fallback: true)
|
||||
set par(justify: true)
|
||||
|
||||
// Heading styles
|
||||
set heading(numbering: "I.A.")
|
||||
show heading.where(level: 1): it => {
|
||||
block(
|
||||
above: SECTION_HEADING_SPACE_ABOVE,
|
||||
below: SECTION_HEADING_SPACE_BELOW,
|
||||
breakable: false,
|
||||
[
|
||||
#text(size: SECTION_HEADING_SIZE, weight: SECTION_HEADING_WEIGHT, font: heading_font)[
|
||||
#context counter(heading).display()
|
||||
#upper(it.body)
|
||||
]
|
||||
#hrule(stroke: SECTION_HEADING_HRULE_STROKE)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
// Table style
|
||||
set table(
|
||||
stroke: none,
|
||||
fill: (x, y) => {
|
||||
if y == 0 {
|
||||
TABLE_HEADER_COLOR
|
||||
} else if calc.rem(y, 2) == 0 {
|
||||
TABLE_ZEBRA_COLOR_0
|
||||
} else {
|
||||
TABLE_ZEBRA_COLOR_1
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Main Headline
|
||||
text(size: HEADLINE_NAME_SIZE, weight: HEADLINE_NAME_WEIGHT, font: heading_font)[#smallcaps(name)]
|
||||
h(1fr)
|
||||
text(size: TAGLINE_SIZE, style: TAGLINE_STYLE, weight: TAGLINE_WEIGHT)[#tagline]
|
||||
hrule(stroke: HEADLINE_HRULE_STROKE)
|
||||
|
||||
// The rest of the content
|
||||
body
|
||||
}
|
||||
|
||||
// Alias resume to cv for non-Americans
|
||||
#let cv = resume
|
||||
|
||||
#let company-heading(name, start: none, end: none, icon: none, body) = {
|
||||
let icon_spacing = if icon != none { COMPANY_ICON_SPACING } else { 0em }
|
||||
block(
|
||||
below: COMPANY_BLOCK_BELOW,
|
||||
breakable: false,
|
||||
|
||||
grid(
|
||||
columns: (auto, auto, 1fr, auto),
|
||||
column-gutter: (icon_spacing, 0.5em),
|
||||
row-gutter: 0.5em,
|
||||
align: (left + horizon, left + horizon, right + horizon),
|
||||
|
||||
// first column, optional icon
|
||||
if icon != none { box(height: COMPANY_ICON_SIZE, icon) },
|
||||
|
||||
// second column, company name
|
||||
context text(
|
||||
weight: COMPANY_NAME_WEIGHT,
|
||||
size: COMPANY_NAME_SIZE,
|
||||
font: __get("heading_font"),
|
||||
name
|
||||
),
|
||||
|
||||
// third column, dots
|
||||
if start != none {
|
||||
repeat(h(0.3em) + "." + h(0.3em))
|
||||
} else {
|
||||
[]
|
||||
},
|
||||
|
||||
// fourth column, optional dates
|
||||
context text(
|
||||
weight: COMPANY_DATE_WEIGHT,
|
||||
size: COMPANY_DATE_SIZE,
|
||||
font: __get("heading_font"),
|
||||
|
||||
if start != none {
|
||||
[#start -- #end]
|
||||
} else {
|
||||
[ ]
|
||||
}
|
||||
),
|
||||
|
||||
// second row, company content
|
||||
grid.cell(colspan: 4, body)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Alias to school heading
|
||||
#let school-heading = company-heading
|
||||
|
||||
#let job-heading(title, location: none, start: none, end: none, comment: none, body) = {
|
||||
block(
|
||||
above: JOB_BLOCK_ABOVE,
|
||||
below: JOB_BLOCK_BELOW,
|
||||
breakable: false,
|
||||
|
||||
// heading
|
||||
grid(
|
||||
columns: (auto, auto, auto, 1fr, auto),
|
||||
gutter: 0.5em,
|
||||
align: (left + horizon, right + horizon),
|
||||
|
||||
// first column, title
|
||||
context text(
|
||||
style: JOB_NAME_STYLE,
|
||||
weight: JOB_NAME_WEIGHT,
|
||||
size: JOB_NAME_SIZE,
|
||||
font: __get("heading_font"),
|
||||
title
|
||||
),
|
||||
|
||||
// second column, job comment ellipsis
|
||||
if comment != none { [ ... ] },
|
||||
|
||||
// third column, job comment ellipsis
|
||||
if comment != none { [ #comment ] },
|
||||
|
||||
// fourth column, hfill
|
||||
h(1fr),
|
||||
|
||||
// fifth column, optional location
|
||||
context text(
|
||||
style: JOB_LOCATION_STYLE,
|
||||
weight: JOB_LOCATION_WEIGHT,
|
||||
size: JOB_LOCATION_SIZE,
|
||||
font: __get("heading_font"),
|
||||
|
||||
if location != none and start != none {
|
||||
[#location#[;] #h(0.25em)#start#if end != none [ -- #end]]
|
||||
} else if location != none {
|
||||
location
|
||||
} else if start != none {
|
||||
[#start#if end != none [ -- #end]]
|
||||
}
|
||||
),
|
||||
|
||||
grid.cell(colspan: 5, body)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Alias to degree heading
|
||||
#let degree-heading = job-heading
|
||||
|
||||
Reference in new issue
Block a user