Typst and a CV template

Sun, Apr 23, 2023 tags: [ typst programming ]

If you are interested in typesetting outside the normal options (Word, LibreOffice), and have had a gnawing feeling that LaTeX is, after all, a bit annoying to use (and I say that as a maybe not power user, but having used it for the past ten years, including all important documents), Typst may be for you.

It’s a new document language, conceptually somewhere between LaTeX and Markdown, has been hyped a bit recently – and that hype is fully deserved. Having had no experience in it, I rewrote my CV on a Sunday morning within less than two hours, and it looks better than the prior LaTeX version. Written in Rust, it is easily installable through cargo, as a standalone binary, or usable on the web. I went the first route (as a matter of pride).

With that said, I don’t want to give a full introduction, because the documentation is amazing as well.

What I will leave here, is my little CV template, which also gives a small taste of it. Note that it is not a proper Typst template, rather a framework you can paste at the beginning of your own CV document. Unfortunately, syntax highlighting doesn’t exist yet in my website generator :-)

#let cv_title(t) = [
    #set align(center)
    #text(t, font : "Fontin", weight : "bold", size : 26pt)
]
#let cv_h2(t) = [
    #smallcaps(text(t, font: "Fontin", size: 18pt, weight: "regular"))
]

/* Standard link, in blue. */
#let cv_link(t, lab) = text(link(t, lab), fill: blue)

/* Standard layout constants. */
#let cv_citysep = " "
#let cv_table_cell_width = 35em

/* Indents a block slightly to offset it from surrounding content. */
#let cv_inset(t) = par(hanging-indent: 1em, first-line-indent: 1em, t)

/* Indicates a station within an overall experience:

    #cv_station([Apr 2019 - Apr 2020], [Taste University], [Flavortown, USA])
*/
#let cv_station(time, inst, loc) = [
    *#time* #h(1em) *#inst* (#loc)
]

/* Not for external use: use cv_table() instead. Feel free to adjust colors etc. */
#let cv_table_cell(t, width: cv_table_cell_width) = block(t, fill: luma(250),
    width: width, outset: 5pt, stroke: (left: black + 1pt))

/* Use like this:

    #cv_table([2024\ 2020], [Some awesome job])
*/
#let cv_table(width1: 7em, row-spacing: 20pt, ..cellpairs) = [
    #grid(
        columns: (width1, cv_table_cell_width - width1 + 7em),
        rows: auto,
        row-gutter: row-spacing,

        ..(cellpairs.pos().enumerate().map(p => {
                let (i, b) = p
                if calc.even(i) [
                    #text(weight: "bold", b)
                ] else [
                    #cv_table_cell(b, width: cv_table_cell_width - width1 + 7em)
                ]
            })
        )
    )
]

/* CV begins below: */
/* ========================================================== */

#cv_title([Your Name])

#cv_h2()[
Personal Information
]

#grid(
    columns: (10%, 90%),
    rows: 16pt,
 
    [Born], [X city; Month 17, 19xy],
    [Phone], [+1 234 567 89]
)

#cv_h2()[Experience]

#cv_table(
    [Year 2], [
        *Great achievement*

        Saving the world (full-time).
    ],
    [Year 1], [
    _Not so great achievement_

    This was not very notable.
    ],
)

Example document

Colors and spacings can be adjusted directly in the header. If you use it or make some modifications – it is admittedly quite bare-bones right now – I’d love to hear from you!