From ee15ae9c657fc21ac20c62463c2105939ae56ef3 Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Fri, 18 Oct 2024 10:36:21 +0200 Subject: [PATCH] Use `set page(columns: n)` in tutorial (#5228) Co-authored-by: Laurenz --- docs/guides/guide-for-latex-users.md | 149 +++++++++-------- docs/guides/page-setup.md | 2 +- docs/src/html.rs | 2 +- docs/tutorial/3-advanced.md | 231 +++++++++++++++------------ docs/tutorial/4-template.md | 113 ++++++++----- 5 files changed, 284 insertions(+), 213 deletions(-) diff --git a/docs/guides/guide-for-latex-users.md b/docs/guides/guide-for-latex-users.md index f8b2e4393..743afa5a6 100644 --- a/docs/guides/guide-for-latex-users.md +++ b/docs/guides/guide-for-latex-users.md @@ -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!
@@ -428,18 +451,6 @@ function and pre-configures some if its arguments before passing it on to the show rule.
-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 diff --git a/docs/guides/page-setup.md b/docs/guides/page-setup.md index 6ae92f83f..d4a1e62c8 100644 --- a/docs/guides/page-setup.md +++ b/docs/guides/page-setup.md @@ -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. diff --git a/docs/src/html.rs b/docs/src/html.rs index 58c8e54c2..d702d115b 100644 --- a/docs/src/html.rs +++ b/docs/src/html.rs @@ -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) } diff --git a/docs/tutorial/3-advanced.md b/docs/tutorial/3-advanced.md index f1ed81541..b7f338db5 100644 --- a/docs/tutorial/3-advanced.md +++ b/docs/tutorial/3-advanced.md @@ -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. 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 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 @@ -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) >>> diff --git a/docs/tutorial/4-template.md b/docs/tutorial/4-template.md index 3416e6e49..209fa5546 100644 --- a/docs/tutorial/4-template.md +++ b/docs/tutorial/4-template.md @@ -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