Use set page(columns: n) in tutorial (#5228)

Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
Martin Haug 2024-10-18 10:36:21 +02:00 committed by GitHub
parent ebb60001d8
commit ee15ae9c65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 284 additions and 213 deletions

View File

@ -325,62 +325,65 @@ function. The following example illustrates how it works:
>>> abstract: [],
>>> doc,
>>> ) = {
>>> set text(font: "Libertinus Serif", 11pt)
>>> set par(justify: true)
>>> set page(
>>> "us-letter",
>>> margin: auto,
>>> header: align(
>>> right + horizon,
>>> title
>>> ),
>>> numbering: "1",
>>> )
>>> set text(font: "Libertinus Serif", 11pt)
>>> set par(justify: true)
>>> set page(
>>> "us-letter",
>>> margin: auto,
>>> header: align(
>>> right + horizon,
>>> title
>>> ),
>>> numbering: "1",
>>> columns: 2
>>> )
>>>
>>> show heading.where(
>>> level: 1
>>> ): it => block(
>>> align(center,
>>> text(
>>> 13pt,
>>> weight: "regular",
>>> smallcaps(it.body),
>>> )
>>> ),
>>> )
>>> show heading.where(
>>> level: 2
>>> ): it => box(
>>> text(
>>> 11pt,
>>> weight: "regular",
>>> style: "italic",
>>> it.body + [.],
>>> )
>>> )
>>> show heading.where(
>>> level: 1
>>> ): it => block(
>>> align(center,
>>> text(
>>> 13pt,
>>> weight: "regular",
>>> smallcaps(it.body),
>>> )
>>> ),
>>> )
>>> show heading.where(
>>> level: 2
>>> ): it => box(
>>> text(
>>> 11pt,
>>> weight: "regular",
>>> style: "italic",
>>> it.body + [.],
>>> )
>>> )
>>>
>>> set align(center)
>>> text(17pt, title)
>>> place(top, float: true, scope: "parent", {
>>> set align(center)
>>> text(17pt, title)
>>>
>>> let count = calc.min(authors.len(), 3)
>>> grid(
>>> columns: (1fr,) * count,
>>> row-gutter: 24pt,
>>> ..authors.map(author => [
>>> #author.name \
>>> #author.affiliation \
>>> #link("mailto:" + author.email)
>>> ]),
>>> )
>>> let count = calc.min(authors.len(), 3)
>>> grid(
>>> columns: (1fr,) * count,
>>> row-gutter: 24pt,
>>> ..authors.map(author => [
>>> #author.name \
>>> #author.affiliation \
>>> #link("mailto:" + author.email)
>>> ]),
>>> )
>>>
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>> })
>>>
>>> set align(left)
>>> columns(2, doc)
>>>}
>>> set align(left)
>>> doc
>>> }
<<< #import "conf.typ": conf
#show: conf.with(
title: [
@ -404,14 +407,34 @@ function. The following example illustrates how it works:
Let's get started writing this
article by putting insightful
paragraphs right here!
>>> #lorem(500)
```
The [`{import}`]($scripting/#modules) statement makes
[functions]($function) (and other definitions) from another file available.
In this example, it imports the `conf` function from the `conf.typ` file. This
function formats a document as a conference article. We use a show rule to apply
it to the document and also configure some metadata of the article. After
applying the show rule, we can start writing our article right away!
The [`{import}`]($scripting/#modules) statement makes [functions]($function)
(and other definitions) from another file available. In this example, it imports
the `conf` function from the `conf.typ` file. This function formats a document
as a conference article. We use a show rule to apply it to the document and also
configure some metadata of the article. After applying the show rule, we can
start writing our article right away!
You can also use templates from Typst Universe (which is Typst's equivalent of
CTAN) using an import statement like this: `[#import
"@preview/elsearticle:0.2.1": elsearticle]`. Check the documentation of an
individual template to learn the name of its template function. Templates and
packages from Typst Universe are automatically downloaded when you first use
them.
In the web app, you can choose to create a project from a template on Typst
Universe or even create your own using the template wizard. Locally, you can use
the `typst init` CLI to create a new project from a template. Check out [the
list of templates]($universe/search/?kind=templates) published on Typst
Universe. You can also take a look at the [`awesome-typst`
repository](https://github.com/qjcg/awesome-typst) to find community templates
that aren't available through Universe.
You can also [create your own, custom templates.]($tutorial/making-a-template)
They are shorter and more readable than the corresponding LaTeX `.sty` files by
orders of magnitude, so give it a try!
<div class="info-box">
@ -428,18 +451,6 @@ function and pre-configures some if its arguments before passing it on to the
show rule.
</div>
In the web app, you can choose from predefined templates or even
create your own using the template wizard. Locally, you can use the
`typst init` CLI to create a new project from a template. Check out
[the list of templates]($universe/search/?kind=templates) published on Typst
Universe, our official package ecosystem. You can also take a look at the
[`awesome-typst` repository](https://github.com/qjcg/awesome-typst) to find
community templates that aren't yet available as packages.
You can also [create your own, custom templates.]($tutorial/making-a-template)
They are shorter and more readable than the corresponding LaTeX `.sty` files by
orders of magnitude, so give it a try!
## How do I load packages? { #packages }
Typst is "batteries included," so the equivalent of many popular LaTeX packages
is built right-in. Below, we compiled a table with frequently loaded packages

View File

@ -432,7 +432,7 @@ frequently used for [figures]($figure.placement).
### Use columns anywhere in your document { #columns-anywhere }
To create columns within a nested layout, e.g. within a rectangle, you can use
the [`columns` function]($columns) directly. However, it should really only be
the [`columns` function]($columns) directly. However, it really should only be
used within nested layouts. At the page-level, the page set rule is preferrable
because it has better interactions with things like page-level floats,
footnotes, and line numbers.

View File

@ -427,7 +427,7 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html {
document.pages.truncate(1);
}
let hash = typst::utils::hash128(text);
let hash = typst::utils::hash128(&(lang, text));
resolver.example(hash, highlighted, &document)
}

View File

@ -248,17 +248,34 @@ on another title, we can easily change it in one place.
## Adding columns and headings { #columns-and-headings }
The paper above unfortunately looks like a wall of lead. To fix that, let's add
some headings and switch our paper to a two-column layout. The [`columns`]
function takes a number and content, and layouts the content into the specified
number of columns. Since we want everything after the abstract to be in two
columns, we need to apply the column function to our whole document.
some headings and switch our paper to a two-column layout. Fortunately, that's
easy to do: We just need to amend our `page` set rule with the `columns`
argument.
Instead of wrapping the whole document in a giant function call, we can use an
"everything" show rule. To write such a show rule, put a colon directly behind
the show keyword and then provide a function. This function is given the rest of
the document as a parameter. We have called the parameter `rest` here, but you
are free to choose any name. The function can then do anything with this
content. In our case, it passes it on to the `columns` function.
By adding `{columns: 2}` to the argument list, we have wrapped the whole
document in two columns. However, that would also affect the title and authors
overview. To keep them spanning the whole page, we can wrap them in a function
call to [`{place}`]($place). Place expects an alignment and the content it
should place as positional arguments. Using the named `{scope}` argument, we can
decide if the items should be placed relative to the current column or its
parent (the page). There is one more thing to configure: If no other arguments
are provided, `{place}` takes its content out of the flow of the document and
positions it over the other content without affecting the layout of other
content in its container:
```example
#place(
top + center,
rect(fill: black),
)
#lorem(30)
```
If we hadn't used `{place}` here, the square would be in its own line, but here
it overlaps the few lines of text following it. Likewise, that text acts like as
if there was no square. To change this behavior, we can pass the argument
`{float: true}` to ensure that the space taken up by the placed item at the top
or bottom of the page is not occupied by any other content.
```example:single
>>> #let title = [
@ -268,45 +285,50 @@ content. In our case, it passes it on to the `columns` function.
>>>
>>> #set text(font: "Libertinus Serif", 11pt)
>>> #set par(justify: true)
>>> #set page(
>>> "us-letter",
>>> margin: auto,
>>> header: align(
>>> right + horizon,
>>> title
>>> ),
>>> numbering: "1",
>>> )
>>>
>>> #align(center, text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> ))
>>>
>>> #grid(
>>> columns: (1fr, 1fr),
>>> align(center)[
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> align(center)[
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> ]
>>> )
>>>
>>> #align(center)[
>>> #set par(justify: false)
>>> *Abstract* \
>>> #lorem(80)
>>> ]
>>> #v(4mm)
<<< ...
#set page(
>>> margin: auto,
paper: "us-letter",
header: align(
right + horizon,
title
),
numbering: "1",
columns: 2,
)
#show: rest => columns(2, rest)
#place(
top + center,
float: true,
scope: "parent",
clearance: 2em,
)[
>>> #text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> )
>>>
>>> #grid(
>>> columns: (1fr, 1fr),
>>> [
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> [
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> ]
>>> )
<<< ...
#par(justify: false)[
*Abstract* \
#lorem(80)
]
]
= Introduction
#lorem(300)
@ -315,6 +337,11 @@ content. In our case, it passes it on to the `columns` function.
#lorem(200)
```
In this example, we also used the `clearance` argument of the `{place}` function
to provide the space between it and the body instead of using the [`{v}`]($v)
function. We can also remove the explicit `{align(center, ..)}` calls around the
various parts since they inherit the center alignment from the placement.
Now there is only one thing left to do: Style our headings. We need to make them
centered and use small capitals. Because the `heading` function does not offer
a way to set any of that, we need to write our own heading show rule.
@ -335,6 +362,7 @@ a way to set any of that, we need to write our own heading show rule.
>>> title
>>> ),
>>> numbering: "1",
>>> columns: 2,
>>> )
#show heading: it => [
#set align(center)
@ -344,35 +372,38 @@ a way to set any of that, we need to write our own heading show rule.
<<< ...
>>>
>>> #align(center, text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> ))
>>> #place(
>>> top + center,
>>> float: true,
>>> scope: "parent",
>>> clearance: 2em,
>>> )[
>>> #text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> )
>>>
>>> #grid(
>>> columns: (1fr, 1fr),
>>> align(center)[
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> align(center)[
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> #grid(
>>> columns: (1fr, 1fr),
>>> [
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> [
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> ]
>>> )
>>>
>>> #par(justify: false)[
>>> *Abstract* \
>>> #lorem(80)
>>> ]
>>> )
>>>
>>> #align(center)[
>>> #set par(justify: false)
>>> *Abstract* \
>>> #lorem(80)
>>> ]
>>>
>>> #v(4mm)
>>> #show: rest => columns(2, rest)
>>>
>>> = Introduction
>>> #lorem(35)
>>>
@ -411,6 +442,7 @@ differentiate between section and subsection headings:
>>> title
>>> ),
>>> numbering: "1",
>>> columns: 2,
>>> )
>>>
#show heading.where(
@ -430,35 +462,38 @@ differentiate between section and subsection headings:
it.body + [.],
)
>>>
>>> #align(center, text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> ))
>>> #place(
>>> top + center,
>>> float: true,
>>> scope: "parent",
>>> clearance: 2em,
>>> )[
>>> #text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> )
>>>
>>> #grid(
>>> columns: (1fr, 1fr),
>>> align(center)[
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> align(center)[
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> #grid(
>>> columns: (1fr, 1fr),
>>> [
>>> Therese Tungsten \
>>> Artos Institute \
>>> #link("mailto:tung@artos.edu")
>>> ],
>>> [
>>> Dr. John Doe \
>>> Artos Institute \
>>> #link("mailto:doe@artos.edu")
>>> ]
>>> )
>>>
>>> #par(justify: false)[
>>> *Abstract* \
>>> #lorem(80)
>>> ]
>>> )
>>>
>>> #align(center)[
>>> #set par(justify: false)
>>> *Abstract* \
>>> #lorem(80)
>>> ]
>>>
>>> #v(4mm)
>>> #show: rest => columns(2, rest)
>>>
>>> = Introduction
>>> #lorem(35)
>>>

View File

@ -41,8 +41,14 @@ You are #amazed[beautiful]!
I am #amazed(color: purple)[amazed]!
```
Templates now work by using an "everything" show rule that applies the custom
function to our whole document. Let's do that with our `amazed` function.
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
cumbersome! Instead, we can use an "everything" show rule to achieve the same
with cleaner code. To write such a show rule, put a colon directly behind 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.
Since the `amazed` function can be called with a single content argument, we can
just pass it by name to the show rule. Let's try it:
```example
>>> #let amazed(term, color: blue) = {
@ -55,8 +61,8 @@ negative thoughts or beliefs.
In fact, I am amazing!
```
Our whole document will now be passed to the `amazed` function, as if we
wrapped it around it. This is not especially useful with this particular
Our whole document will now be passed to the `amazed` function, as if we wrapped
it around it. Of course, this is not especially useful with this particular
function, but when combined with set rules and named arguments, it can be very
powerful.
@ -93,6 +99,7 @@ previous chapter.
right + horizon,
title
),
columns: 2,
<<< ...
)
set par(justify: true)
@ -125,7 +132,7 @@ previous chapter.
>>> )
>>> )
columns(2, doc)
doc
}
#show: doc => conf(
@ -147,24 +154,31 @@ previous chapter.
>>> #lorem(200)
```
We copy-pasted most of that code from the previous chapter. The only two
differences are that we wrapped everything in the function `conf` and are
calling the columns function directly on the `doc` argument as it already
contains the content of the document. 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 into it anymore.
We copy-pasted most of that code from the previous chapter. The two differences
are this:
1. We wrapped everything in the function `conf` using an everything show rule.
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.
Thus, we must specify it in the show rule where we call the template.
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
away) to the everything show rule. We did that because the `conf` function
expects two positional arguments, the title and the body, but the show rule will
only pass the body. Therefore, we add a new function definition that allows us
to set a paper title and use the single parameter from the show rule.
## Templates with named arguments { #named-arguments }
Our paper in the previous chapter had a title and an author list. Let's add these
things to our template. In addition to the title, we want our template to accept
a list of authors with their affiliations and the paper's abstract. To keep
things readable, we'll add those as named arguments. In the end, we want it to
work like this:
Our paper in the previous chapter had a title and an author list. Let's add
these things to our template. In addition to the title, we want our template to
accept a list of authors with their affiliations and the paper's abstract. To
keep things readable, we'll add those as named arguments. In the end, we want it
to work like this:
```typ
#show: doc => conf(
@ -226,6 +240,7 @@ The resulting template function looks like this:
doc,
) = {
// Set and show rules from before.
>>> #set page(columns: 2)
<<< ...
set align(center)
@ -249,7 +264,7 @@ The resulting template function looks like this:
]
set align(left)
columns(2, doc)
doc
}
```
@ -260,8 +275,14 @@ your template is easily reused. Create a new text file in the file panel by
clicking the plus button and name it `conf.typ`. Move the `conf` function
definition inside of that new file. Now you can access it from your main file by
adding an import before the show rule. Specify the path of the file between the
`{import}` keyword and a colon, then name the function that you
want to import.
`{import}` keyword and a colon, then name the function that you want to import.
Another thing that you can do to make applying templates just a bit more elegant
is to use the [`.with`]($function.with) method on functions to pre-populate all
the named arguments. This way, you can avoid spelling out a closure and
appending the content argument at the bottom of your template list. Templates on
[Typst Universe]($universe) are designed to work with this style of function
call.
```example:single
>>> #let conf(
@ -280,6 +301,7 @@ want to import.
>>> title
>>> ),
>>> numbering: "1",
>>> columns: 2,
>>> )
>>>
>>> show heading.where(
@ -304,30 +326,34 @@ want to import.
>>> )
>>> )
>>>
>>> set align(center)
>>> text(17pt, title)
>>>
>>> let count = calc.min(authors.len(), 3)
>>> grid(
>>> columns: (1fr,) * count,
>>> row-gutter: 24pt,
>>> ..authors.map(author => [
>>> #author.name \
>>> #author.affiliation \
>>> #link("mailto:" + author.email)
>>> ]),
>>> place(
>>> top,
>>> float: true,
>>> scope: "parent",
>>> clearance: 2em,
>>> {
>>> set align(center)
>>> text(17pt, title)
>>> let count = calc.min(authors.len(), 3)
>>> grid(
>>> columns: (1fr,) * count,
>>> row-gutter: 24pt,
>>> ..authors.map(author => [
>>> #author.name \
>>> #author.affiliation \
>>> #link("mailto:" + author.email)
>>> ]),
>>> )
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>> },
>>> )
>>>
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>>
>>> set align(left)
>>> columns(2, doc)
>>> doc
>>>}
<<< #import "conf.typ": conf
#show: doc => conf(
#show: conf.with(
title: [
Towards Improved Modelling
],
@ -344,7 +370,6 @@ want to import.
),
),
abstract: lorem(80),
doc,
)
= Introduction