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: [], >>> abstract: [],
>>> doc, >>> doc,
>>> ) = { >>> ) = {
>>> set text(font: "Libertinus Serif", 11pt) >>> set text(font: "Libertinus Serif", 11pt)
>>> set par(justify: true) >>> set par(justify: true)
>>> set page( >>> set page(
>>> "us-letter", >>> "us-letter",
>>> margin: auto, >>> margin: auto,
>>> header: align( >>> header: align(
>>> right + horizon, >>> right + horizon,
>>> title >>> title
>>> ), >>> ),
>>> numbering: "1", >>> numbering: "1",
>>> ) >>> columns: 2
>>> )
>>> >>>
>>> show heading.where( >>> show heading.where(
>>> level: 1 >>> level: 1
>>> ): it => block( >>> ): it => block(
>>> align(center, >>> align(center,
>>> text( >>> text(
>>> 13pt, >>> 13pt,
>>> weight: "regular", >>> weight: "regular",
>>> smallcaps(it.body), >>> smallcaps(it.body),
>>> ) >>> )
>>> ), >>> ),
>>> ) >>> )
>>> show heading.where( >>> show heading.where(
>>> level: 2 >>> level: 2
>>> ): it => box( >>> ): it => box(
>>> text( >>> text(
>>> 11pt, >>> 11pt,
>>> weight: "regular", >>> weight: "regular",
>>> style: "italic", >>> style: "italic",
>>> it.body + [.], >>> it.body + [.],
>>> ) >>> )
>>> ) >>> )
>>> >>>
>>> set align(center) >>> place(top, float: true, scope: "parent", {
>>> 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,
>>> row-gutter: 24pt, >>> row-gutter: 24pt,
>>> ..authors.map(author => [ >>> ..authors.map(author => [
>>> #author.name \ >>> #author.name \
>>> #author.affiliation \ >>> #author.affiliation \
>>> #link("mailto:" + author.email) >>> #link("mailto:" + author.email)
>>> ]), >>> ]),
>>> ) >>> )
>>> >>>
>>> par(justify: false)[ >>> par(justify: false)[
>>> *Abstract* \ >>> *Abstract* \
>>> #abstract >>> #abstract
>>> ] >>> ]
>>> })
>>> >>>
>>> set align(left) >>> set align(left)
>>> columns(2, doc) >>> doc
>>>} >>> }
<<< #import "conf.typ": conf <<< #import "conf.typ": conf
#show: conf.with( #show: conf.with(
title: [ title: [
@ -404,14 +407,34 @@ function. The following example illustrates how it works:
Let's get started writing this Let's get started writing this
article by putting insightful article by putting insightful
paragraphs right here! paragraphs right here!
>>> #lorem(500)
``` ```
The [`{import}`]($scripting/#modules) statement makes The [`{import}`]($scripting/#modules) statement makes [functions]($function)
[functions]($function) (and other definitions) from another file available. (and other definitions) from another file available. In this example, it imports
In this example, it imports the `conf` function from the `conf.typ` file. This the `conf` function from the `conf.typ` file. This function formats a document
function formats a document as a conference article. We use a show rule to apply as a conference article. We use a show rule to apply it to the document and also
it to the document and also configure some metadata of the article. After configure some metadata of the article. After applying the show rule, we can
applying the show rule, we can start writing our article right away! 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"> <div class="info-box">
@ -428,18 +451,6 @@ function and pre-configures some if its arguments before passing it on to the
show rule. show rule.
</div> </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 } ## How do I load packages? { #packages }
Typst is "batteries included," so the equivalent of many popular LaTeX 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 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 } ### Use columns anywhere in your document { #columns-anywhere }
To create columns within a nested layout, e.g. within a rectangle, you can use 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 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, because it has better interactions with things like page-level floats,
footnotes, and line numbers. 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); document.pages.truncate(1);
} }
let hash = typst::utils::hash128(text); let hash = typst::utils::hash128(&(lang, text));
resolver.example(hash, highlighted, &document) resolver.example(hash, highlighted, &document)
} }

View File

@ -10,7 +10,7 @@ base a conference paper on it! The report will of course have to comply with the
conference's style guide. Let's see how we can achieve that. conference's style guide. Let's see how we can achieve that.
Before we start, let's create a team, invite your supervisor and add them to the Before we start, let's create a team, invite your supervisor and add them to the
team. You can do this by going back to the app dashboard with the back icon in team. You can do this by going back to the app dashboard with the back icon in
the top left corner of the editor. Then, choose the plus icon in the left the top left corner of the editor. Then, choose the plus icon in the left
toolbar and create a team. Finally, click on the new team and go to its settings toolbar and create a team. Finally, click on the new team and go to its settings
by clicking 'manage team' next to the team name. Now you can invite your by clicking 'manage team' next to the team name. Now you can invite your
@ -248,17 +248,34 @@ on another title, we can easily change it in one place.
## Adding columns and headings { #columns-and-headings } ## Adding columns and headings { #columns-and-headings }
The paper above unfortunately looks like a wall of lead. To fix that, let's add 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`] some headings and switch our paper to a two-column layout. Fortunately, that's
function takes a number and content, and layouts the content into the specified easy to do: We just need to amend our `page` set rule with the `columns`
number of columns. Since we want everything after the abstract to be in two argument.
columns, we need to apply the column function to our whole document.
Instead of wrapping the whole document in a giant function call, we can use an By adding `{columns: 2}` to the argument list, we have wrapped the whole
"everything" show rule. To write such a show rule, put a colon directly behind document in two columns. However, that would also affect the title and authors
the show keyword and then provide a function. This function is given the rest of overview. To keep them spanning the whole page, we can wrap them in a function
the document as a parameter. We have called the parameter `rest` here, but you call to [`{place}`]($place). Place expects an alignment and the content it
are free to choose any name. The function can then do anything with this should place as positional arguments. Using the named `{scope}` argument, we can
content. In our case, it passes it on to the `columns` function. 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 ```example:single
>>> #let title = [ >>> #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 text(font: "Libertinus Serif", 11pt)
>>> #set par(justify: true) >>> #set par(justify: true)
>>> #set page(
>>> "us-letter",
>>> margin: auto,
>>> header: align(
>>> right + horizon,
>>> title
>>> ),
>>> numbering: "1",
>>> )
>>> >>>
>>> #align(center, text( #set page(
>>> 17pt, >>> margin: auto,
>>> weight: "bold", paper: "us-letter",
>>> title, header: align(
>>> )) right + horizon,
>>> title
>>> #grid( ),
>>> columns: (1fr, 1fr), numbering: "1",
>>> align(center)[ columns: 2,
>>> 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)
<<< ...
#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 = Introduction
#lorem(300) #lorem(300)
@ -315,6 +337,11 @@ content. In our case, it passes it on to the `columns` function.
#lorem(200) #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 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 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. 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 >>> title
>>> ), >>> ),
>>> numbering: "1", >>> numbering: "1",
>>> columns: 2,
>>> ) >>> )
#show heading: it => [ #show heading: it => [
#set align(center) #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( >>> #place(
>>> 17pt, >>> top + center,
>>> weight: "bold", >>> float: true,
>>> title, >>> scope: "parent",
>>> )) >>> clearance: 2em,
>>> )[
>>> #text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> )
>>> >>>
>>> #grid( >>> #grid(
>>> columns: (1fr, 1fr), >>> columns: (1fr, 1fr),
>>> align(center)[ >>> [
>>> Therese Tungsten \ >>> Therese Tungsten \
>>> Artos Institute \ >>> Artos Institute \
>>> #link("mailto:tung@artos.edu") >>> #link("mailto:tung@artos.edu")
>>> ], >>> ],
>>> align(center)[ >>> [
>>> Dr. John Doe \ >>> Dr. John Doe \
>>> Artos Institute \ >>> Artos Institute \
>>> #link("mailto:doe@artos.edu") >>> #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 >>> = Introduction
>>> #lorem(35) >>> #lorem(35)
>>> >>>
@ -411,6 +442,7 @@ differentiate between section and subsection headings:
>>> title >>> title
>>> ), >>> ),
>>> numbering: "1", >>> numbering: "1",
>>> columns: 2,
>>> ) >>> )
>>> >>>
#show heading.where( #show heading.where(
@ -430,35 +462,38 @@ differentiate between section and subsection headings:
it.body + [.], it.body + [.],
) )
>>> >>>
>>> #align(center, text( >>> #place(
>>> 17pt, >>> top + center,
>>> weight: "bold", >>> float: true,
>>> title, >>> scope: "parent",
>>> )) >>> clearance: 2em,
>>> )[
>>> #text(
>>> 17pt,
>>> weight: "bold",
>>> title,
>>> )
>>> >>>
>>> #grid( >>> #grid(
>>> columns: (1fr, 1fr), >>> columns: (1fr, 1fr),
>>> align(center)[ >>> [
>>> Therese Tungsten \ >>> Therese Tungsten \
>>> Artos Institute \ >>> Artos Institute \
>>> #link("mailto:tung@artos.edu") >>> #link("mailto:tung@artos.edu")
>>> ], >>> ],
>>> align(center)[ >>> [
>>> Dr. John Doe \ >>> Dr. John Doe \
>>> Artos Institute \ >>> Artos Institute \
>>> #link("mailto:doe@artos.edu") >>> #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 >>> = Introduction
>>> #lorem(35) >>> #lorem(35)
>>> >>>

View File

@ -41,8 +41,14 @@ You are #amazed[beautiful]!
I am #amazed(color: purple)[amazed]! I am #amazed(color: purple)[amazed]!
``` ```
Templates now work by using an "everything" show rule that applies the custom Templates now work by wrapping our whole document in a custom function like
function to our whole document. Let's do that with our `amazed` function. `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 ```example
>>> #let amazed(term, color: blue) = { >>> #let amazed(term, color: blue) = {
@ -55,8 +61,8 @@ negative thoughts or beliefs.
In fact, I am amazing! In fact, I am amazing!
``` ```
Our whole document will now be passed to the `amazed` function, as if we Our whole document will now be passed to the `amazed` function, as if we wrapped
wrapped it around it. This is not especially useful with this particular 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 function, but when combined with set rules and named arguments, it can be very
powerful. powerful.
@ -93,6 +99,7 @@ previous chapter.
right + horizon, right + horizon,
title title
), ),
columns: 2,
<<< ... <<< ...
) )
set par(justify: true) set par(justify: true)
@ -125,7 +132,7 @@ previous chapter.
>>> ) >>> )
>>> ) >>> )
columns(2, doc) doc
} }
#show: doc => conf( #show: doc => conf(
@ -147,24 +154,31 @@ previous chapter.
>>> #lorem(200) >>> #lorem(200)
``` ```
We copy-pasted most of that code from the previous chapter. The only two We copy-pasted most of that code from the previous chapter. The two differences
differences are that we wrapped everything in the function `conf` and are are this:
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 1. We wrapped everything in the function `conf` using an everything show rule.
block instead of a content block. This way, we don't need to prefix all set The function applies a few set and show rules and echoes the content it has
rules and function calls with a `#`. In exchange, we cannot write markup been passed at the end.
directly into it anymore.
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. 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. Now, we are receiving it as the first parameter of the template function. To do
Thus, we must specify it in the show rule where we call the template. 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 } ## Templates with named arguments { #named-arguments }
Our paper in the previous chapter had a title and an author list. Let's add these Our paper in the previous chapter had a title and an author list. Let's add
things to our template. In addition to the title, we want our template to accept these things to our template. In addition to the title, we want our template to
a list of authors with their affiliations and the paper's abstract. To keep accept a list of authors with their affiliations and the paper's abstract. To
things readable, we'll add those as named arguments. In the end, we want it to keep things readable, we'll add those as named arguments. In the end, we want it
work like this: to work like this:
```typ ```typ
#show: doc => conf( #show: doc => conf(
@ -226,6 +240,7 @@ The resulting template function looks like this:
doc, doc,
) = { ) = {
// Set and show rules from before. // Set and show rules from before.
>>> #set page(columns: 2)
<<< ... <<< ...
set align(center) set align(center)
@ -249,7 +264,7 @@ The resulting template function looks like this:
] ]
set align(left) 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 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 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 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 `{import}` keyword and a colon, then name the function that you want to import.
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 ```example:single
>>> #let conf( >>> #let conf(
@ -280,6 +301,7 @@ want to import.
>>> title >>> title
>>> ), >>> ),
>>> numbering: "1", >>> numbering: "1",
>>> columns: 2,
>>> ) >>> )
>>> >>>
>>> show heading.where( >>> show heading.where(
@ -304,30 +326,34 @@ want to import.
>>> ) >>> )
>>> ) >>> )
>>> >>>
>>> set align(center) >>> place(
>>> text(17pt, title) >>> top,
>>> >>> float: true,
>>> let count = calc.min(authors.len(), 3) >>> scope: "parent",
>>> grid( >>> clearance: 2em,
>>> columns: (1fr,) * count, >>> {
>>> row-gutter: 24pt, >>> set align(center)
>>> ..authors.map(author => [ >>> text(17pt, title)
>>> #author.name \ >>> let count = calc.min(authors.len(), 3)
>>> #author.affiliation \ >>> grid(
>>> #link("mailto:" + author.email) >>> columns: (1fr,) * count,
>>> ]), >>> row-gutter: 24pt,
>>> ..authors.map(author => [
>>> #author.name \
>>> #author.affiliation \
>>> #link("mailto:" + author.email)
>>> ]),
>>> )
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>> },
>>> ) >>> )
>>> >>> doc
>>> par(justify: false)[
>>> *Abstract* \
>>> #abstract
>>> ]
>>>
>>> set align(left)
>>> columns(2, doc)
>>>} >>>}
<<< #import "conf.typ": conf <<< #import "conf.typ": conf
#show: doc => conf( #show: conf.with(
title: [ title: [
Towards Improved Modelling Towards Improved Modelling
], ],
@ -344,7 +370,6 @@ want to import.
), ),
), ),
abstract: lorem(80), abstract: lorem(80),
doc,
) )
= Introduction = Introduction