1
0
Fork 0
nix-typst-resume/base/lib.typ
2025-08-09 19:04:01 -05:00

197 lines
4.8 KiB
Typst

// SPDX-FileCopyrightText: 2025 Ethan Reece <contact@ethanreece.com>
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#import "@preview/fontawesome:0.5.0": fa-icon
#import "@preview/linguify:0.4.2": linguify
#let reset(body) = text(font: "Inter", size: 10pt, weight: "regular", body)
#let lang-data = toml("lang.toml")
#let l(content) = linguify(content, from: lang-data)
#let name(below: 0em, size: 0em, body) = reset(block(
width: 100%,
below: below,
text(size: size, weight: "extrabold", align(center, body)),
))
#let section-heading(above: 0em, below: 0em, body) = reset(block(
width: 100%,
above: above,
below: below,
text(size: 1.3em, weight: "bold", body),
))
#let left_pad(body) = pad(left: 1em, body)
#let base(
lang: "en",
region: "US",
self: (:),
name-below: 0em,
name-size: 0em,
body,
) = text(
lang: lang,
region: region,
reset(
page(
paper: "us-letter",
margin: (x: 0.5in, y: 0.4in),
{
set document(
title: lang-data.lang.at(text.lang).Resume,
author: self.package.authors,
description: self.package.description,
keywords: self.package.keywords,
)
set list(
marker: text(weight: "extralight", size: 0.95em, sym.dash.en),
indent: 0.25em,
body-indent: 1.5em,
tight: false,
spacing: 0.85em,
)
set text(size: 0.95em)
set par(spacing: 0em, justify: true)
show list: it => left_pad(it)
show par: it => block(width: 100%, it)
show raw: it => text(font: "JetBrains Mono", it)
show heading.where(level: 1): it => name(
below: name-below,
size: name-size,
it.body,
)
show heading.where(level: 2): it => section-heading(
above: 1.1em,
below: 0.8em,
it.body,
)
body
},
),
),
)
#let contact(gutter: 0em, below: 0em, ..methods) = reset(block(
width: 100%,
below: below,
text(
size: 1.05em,
weight: "medium",
align(
center + horizon,
grid(columns: methods.pos().len(), rows: 1, gutter: gutter, ..methods),
),
),
))
#let contact-method(title: "", icon: "") = grid(
rows: 1,
columns: 2,
gutter: .9em,
fa-icon(icon, solid: true), title,
)
#let Skills = l("Skills")
#let Education = l("Education")
#let Experience = l("Experience")
#let Organizations = l("Organizations")
#let Projects = l("Projects")
#let Volunteering = l("Volunteering")
#let skills-grid(..skills) = reset(left_pad(grid(
columns: 2,
gutter: 1em,
..for skill in skills.pos() {
(
heading(level: 3, text(weight: "semibold", size: 0.95em, skill.title)),
text(size: 0.95em, skill.items.join(", ")),
)
}
)))
#let item-heading(
title: "",
subtitle: "",
long-subtitle: false,
timeframe: "",
location: "",
type: "",
skills: (),
condensed: false,
below: 0em,
above: 0em,
) = {
let gutter = 0.6em
let subtitle_text = text(weight: "light", size: 0.9em, subtitle)
let location_text = text(size: 0.85em, weight: "extralight", location)
let skills_text = text(weight: "light", size: 0.9em, skills.join(", "))
let type_text = text(weight: "light", size: 0.85em, type)
reset(block(
below: below,
above: above,
left_pad(
grid(
columns: 1,
rows: 2,
gutter: gutter,
grid(
columns: (auto, 1fr),
rows: 1,
gutter: gutter,
align: (left + bottom, right + bottom),
grid(
columns: 2,
rows: 1,
column-gutter: 1.5em,
row-gutter: gutter,
align: bottom,
heading(level: 3, text(weight: "semibold", title)), type_text,
),
text(weight: "regular", timeframe),
),
if long-subtitle {
grid(
columns: 1,
rows: 2,
gutter: gutter,
subtitle_text,
grid(
columns: (auto, 1fr),
rows: 1,
gutter: gutter,
align: (left + bottom, right + bottom),
location_text, skills_text,
),
)
} else if condensed {
grid(
columns: (auto, 1fr),
rows: 1,
gutter: gutter,
align: (left + bottom, right + bottom),
subtitle_text, location_text,
)
} else {
grid(
columns: (auto, 1fr),
rows: 1,
gutter: gutter,
align: (left + bottom, right + bottom),
grid(
columns: 2,
rows: 1,
column-gutter: 1.5em,
row-gutter: gutter,
align: bottom,
subtitle_text, location_text,
),
skills_text,
)
},
),
),
))
}