generated from me/nix-flake-typst-template
197 lines
4.8 KiB
Typst
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,
|
|
)
|
|
},
|
|
),
|
|
),
|
|
))
|
|
}
|