Refactor "Making a Template" tutorial

This commit is contained in:
Andrew Voynov 2025-06-12 09:03:09 +03:00
parent 7f24cd9253
commit 6daae2e292
No known key found for this signature in database
GPG Key ID: 1BE92DD685700329

View File

@ -25,7 +25,10 @@ You are #amazed[beautiful]!
This function takes a single argument, `term`, and returns a content block with This function takes a single argument, `term`, and returns a content block with
the `term` surrounded by sparkles. We also put the whole thing in a box so that the `term` surrounded by sparkles. We also put the whole thing in a box so that
the term we are amazed by cannot be separated from its sparkles by a line break. the term we are amazed by cannot be separated from its sparkles by a line
break. Alternatively, you can use a
[shorthand](https://typst.app/docs/reference/symbols/#shorthands)
for a no-break space and write `{[✨~#term~✨]}`.
Many functions that come with Typst have optional named parameters. Our Many functions that come with Typst have optional named parameters. Our
functions can also have them. Let's add a parameter to our function that lets us functions can also have them. Let's add a parameter to our function that lets us
@ -34,7 +37,7 @@ parameter isn't given.
```example ```example
#let amazed(term, color: blue) = { #let amazed(term, color: blue) = {
text(color, box[✨ #term ✨]) text(color)[✨~#term~✨]
} }
You are #amazed[beautiful]! You are #amazed[beautiful]!
@ -43,7 +46,7 @@ I am #amazed(color: purple)[amazed]!
Templates now work by wrapping our whole document in a custom function like Templates now work by wrapping our whole document in a custom function like
`amazed`. But wrapping a whole document in a giant function call would be `amazed`. But wrapping a whole document in a giant function call would be
cumbersome! Instead, we can use an "everything" show rule to achieve the same cumbersome! Instead, we can use an "global" show rule to achieve the same
with cleaner code. To write such a show rule, put a colon directly after the with cleaner code. To write such a show rule, put a colon directly after the
show keyword and then provide a function. This function is given the rest of the show keyword and then provide a function. This function is given the rest of the
document as a parameter. The function can then do anything with this content. document as a parameter. The function can then do anything with this content.
@ -52,7 +55,7 @@ just pass it by name to the show rule. Let's try it:
```example ```example
>>> #let amazed(term, color: blue) = { >>> #let amazed(term, color: blue) = {
>>> text(color, box[✨ #term ✨]) >>> text(color)[✨~#term~✨]
>>> } >>> }
#show: amazed #show: amazed
I choose to focus on the good I choose to focus on the good
@ -68,69 +71,56 @@ powerful.
## Embedding set and show rules { #set-and-show-rules } ## Embedding set and show rules { #set-and-show-rules }
To apply some set and show rules to our template, we can use `set` and `show` To apply some set and show rules to our template, we can use `set` and `show`
within a content block in our function and then insert the document into within a code block in our function and then insert the document into
that content block. that code block.
```example ```example
#let template(doc) = [ #let template(doc) = {
#set text(font: "Inria Serif") set text(font: "Inria Serif")
#show "something cool": [Typst] show "something cool": [Typst]
#doc doc
] }
#show: template #show: template
I am learning something cool today. I am learning something cool today.
It's going great so far! It's going great so far!
``` ```
Just like we already discovered in the previous chapter, set rules will apply to Just like we already discovered in the previous chapter, set rules will apply
everything within their content block. Since the everything show rule passes our to everything within their scope. Since the global show rule passes our whole
whole document to the `template` function, the text set rule and string show document to the `template` function, the text set rule and string show rule in
rule in our template will apply to the whole document. Let's use this knowledge our template will apply to the whole document.
to create a template that reproduces the body style of the paper we wrote in the
previous chapter. We used a curly-braced code block instead of a content block. This way, we
don't need to prefix all set rules and function calls with a `#`. This also
removes the implicit spaces that are naturally introduced in the markup mode.
In exchange, we cannot write markup directly in the code block anymore.
Let's use this knowledge to create a template that reproduces the body style of
the paper we wrote in the previous chapter.
```example ```example
#let conf(title, doc) = { #let conf(title, doc) = {
set page( set page(
paper: "us-letter", paper: "us-letter",
>>> margin: auto, header: align(right, title),
header: align(
right + horizon,
title
),
columns: 2, columns: 2,
<<< ... <<< ...
) )
set par(justify: true) set par(justify: true)
set text( set text(
11pt,
font: "Libertinus Serif", font: "Libertinus Serif",
size: 11pt,
) )
// Heading show rules. // Heading show rules.
<<< ... <<< ...
>>> show heading.where( >>> show heading.where(level: 1): set align(center)
>>> level: 1 >>> show heading.where(level: 1): set text(13pt, weight: "regular")
>>> ): it => block( >>> show heading.where(level: 1): it => block(smallcaps(it.body))
>>> align(center, >>>
>>> text( >>> show heading.where(level: 2): set text(11pt, weight: "regular", style: "italic")
>>> 13pt, >>> show heading.where(level: 2): it => [#it.body.]
>>> weight: "regular",
>>> smallcaps(it.body),
>>> )
>>> ),
>>> )
>>> show heading.where(
>>> level: 2
>>> ): it => box(
>>> text(
>>> 11pt,
>>> weight: "regular",
>>> style: "italic",
>>> it.body + [.],
>>> )
>>> )
doc doc
} }
@ -154,24 +144,17 @@ previous chapter.
>>> #lorem(200) >>> #lorem(200)
``` ```
We copy-pasted most of that code from the previous chapter. The two differences We copied most of that code from the previous chapter. However, now we wrapped
are this: everything in the function `conf` using a global show rule. The function applies
a few set and show rules and echoes the content it has been passed at the end.
1. We wrapped everything in the function `conf` using an everything show rule. Also note where the title comes from: we previously had it inside of a variable.
The function applies a few set and show rules and echoes the content it has
been passed at the end.
2. Moreover, we used a curly-braced code block instead of a content block. This
way, we don't need to prefix all set rules and function calls with a `#`. In
exchange, we cannot write markup directly in the code block anymore.
Also note where the title comes from: We previously had it inside of a variable.
Now, we are receiving it as the first parameter of the template function. To do Now, we are receiving it as the first parameter of the template function. To do
so, we passed a closure (that's a function without a name that is used right so, we passed a closure (that's a function without a name that is used right
away) to the everything show rule. We did that because the `conf` function away) to the global show rule. We did that because the `conf` function expects
expects two positional arguments, the title and the body, but the show rule will two positional arguments: the title and the body, but the show rule will only
only pass the body. Therefore, we add a new function definition that allows us pass the body. Therefore, we add a new function definition that allows us to set
to set a paper title and use the single parameter from the show rule. a paper title and use the single parameter from the show rule.
## Templates with named arguments { #named-arguments } ## Templates with named arguments { #named-arguments }
Our paper in the previous chapter had a title and an author list. Let's add Our paper in the previous chapter had a title and an author list. Let's add
@ -230,6 +213,9 @@ multiple arguments for the grid. We can do that by using the
[`spread` operator]($arguments). It takes an array and applies each of its items [`spread` operator]($arguments). It takes an array and applies each of its items
as a separate argument to the function. as a separate argument to the function.
Let's also include some PDF metadata. We can achieve this by using
the [`document`] function and specifying fields such as `title` and `author`.
The resulting template function looks like this: The resulting template function looks like this:
```typ ```typ
@ -239,12 +225,15 @@ The resulting template function looks like this:
abstract: [], abstract: [],
doc, doc,
) = { ) = {
set document(title: title, author: authors.map(author => author.name))
// Set and show rules from before. // Set and show rules from before.
>>> #set page(columns: 2)
<<< ... <<< ...
{
set align(center) set align(center)
text(17pt, title) set par(justify: false)
block(text(17pt, strong(title)))
let count = authors.len() let count = authors.len()
let ncols = calc.min(count, 3) let ncols = calc.min(count, 3)
@ -258,12 +247,11 @@ The resulting template function looks like this:
]), ]),
) )
par(justify: false)[ strong[Abstract]
*Abstract* \ linebreak()
#abstract abstract
] }
set align(left)
doc doc
} }
``` ```
@ -291,49 +279,26 @@ call.
>>> abstract: [], >>> abstract: [],
>>> doc, >>> doc,
>>> ) = { >>> ) = {
>>> set text(font: "Libertinus Serif", 11pt) >>> set document(title: title, author: authors.map(author => author.name))
>>> set par(justify: true)
>>> set page( >>> set page(
>>> "us-letter", >>> "us-letter",
>>> margin: auto, >>> header: align(right, title),
>>> header: align(
>>> right + horizon,
>>> title
>>> ),
>>> numbering: "1", >>> numbering: "1",
>>> columns: 2, >>> columns: 2,
>>> ) >>> )
>>> set par(justify: true)
>>> set text(11pt, font: "Libertinus Serif")
>>> >>>
>>> show heading.where( >>> show heading.where(level: 1): set align(center)
>>> level: 1 >>> show heading.where(level: 1): set text(13pt, weight: "regular")
>>> ): it => block( >>> show heading.where(level: 1): it => block(smallcaps(it.body))
>>> align(center,
>>> text(
>>> 13pt,
>>> weight: "regular",
>>> smallcaps(it.body),
>>> )
>>> ),
>>> )
>>> show heading.where(
>>> level: 2
>>> ): it => box(
>>> text(
>>> 11pt,
>>> weight: "regular",
>>> style: "italic",
>>> it.body + [.],
>>> )
>>> )
>>> >>>
>>> place( >>> show heading.where(level: 2): set text(11pt, weight: "regular", style: "italic")
>>> top, >>> show heading.where(level: 2): it => [#it.body.]
>>> float: true, >>>
>>> scope: "parent", >>> place(top + center, float: true, scope: "parent", clearance: 2em, {
>>> clearance: 2em, >>> set par(justify: false)
>>> { >>> block(text(17pt, title))
>>> set align(center)
>>> text(17pt, title)
>>> let count = calc.min(authors.len(), 3) >>> let count = calc.min(authors.len(), 3)
>>> grid( >>> grid(
>>> columns: (1fr,) * count, >>> columns: (1fr,) * count,
@ -344,19 +309,15 @@ call.
>>> #link("mailto:" + author.email) >>> #link("mailto:" + author.email)
>>> ]), >>> ]),
>>> ) >>> )
>>> par(justify: false)[ >>> strong[Abstract]
>>> *Abstract* \ >>> linebreak()
>>> #abstract >>> abstract
>>> ] >>> })
>>> },
>>> )
>>> doc >>> doc
>>> } >>> }
<<< #import "conf.typ": conf <<< #import "conf.typ": conf
#show: conf.with( #show: conf.with(
title: [ title: [Towards Improved Modelling],
Towards Improved Modelling
],
authors: ( authors: (
( (
name: "Theresa Tungsten", name: "Theresa Tungsten",
@ -397,7 +358,7 @@ that define reusable document styles. You've made it far and learned a lot. You
can now use Typst to write your own documents and share them with others. can now use Typst to write your own documents and share them with others.
We are still a super young project and are looking for feedback. If you have any We are still a super young project and are looking for feedback. If you have any
questions, suggestions or you found a bug, please let us know questions, suggestions, or you found a bug, please let us know
in the [Forum](https://forum.typst.app/), in the [Forum](https://forum.typst.app/),
on our [Discord server](https://discord.gg/2uDybryKPe), on our [Discord server](https://discord.gg/2uDybryKPe),
on [GitHub](https://github.com/typst/typst/), on [GitHub](https://github.com/typst/typst/),