diff --git a/packages/preview/ttuile/0.2.0/LICENSE b/packages/preview/ttuile/0.2.0/LICENSE new file mode 100644 index 0000000000..e76575b62f --- /dev/null +++ b/packages/preview/ttuile/0.2.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 vitto4 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/preview/ttuile/0.2.0/README.md b/packages/preview/ttuile/0.2.0/README.md new file mode 100644 index 0000000000..9953639018 --- /dev/null +++ b/packages/preview/ttuile/0.2.0/README.md @@ -0,0 +1,154 @@ +

+ Typst +

+ +

+ + typst + + MIT + + GitHub Release +

+ +

A Typst template for students' lab reports at INSA Lyon.

+ +

+ + Banner + +

+ +> **Note** +> +> This template targets French students, so you may see French words here and there. +> Should you want to write your report in another language, there's a workaround, see [Notes](#-notes). + +## 🧭 Table of contents + +1. [Usage](#-usage) +1. [Documentation](#-documentation) +1. [Notes](#-notes) +1. [Contributing](#-contributing) + + +## 📎 Usage + +Colorful lab report template more or less aligned with guidelines guidelines issued in 1st year at INSA Lyon. +It is available on _Typst Universe_ : [`@preview/ttuile:0.2.0`](https://typst.app/universe/package/ttuile). + +If you wish to use it locally, you'll need to either manually include `ttuile.typ` and folder `internal/` in your project's root directory ; or upload them to the _Typst web app_ if that's what you use. + +You'll find these files in the [releases](https://github.com/vitto4/ttuile/releases) section. + +Your folder structure should then look something like this : + +``` +. +├── ttuile.typ +├── internal/ +│ ├── defaults.typ +│ ├── helpers.typ +│ └── logo-insa-lyon.png +└── main.typ +``` + +The template is now ready to be used, and can be called supplying the following arguments. +`?` means the argument can be null if not applicable. + + +| Argument | Default value | Type | Description | +|:--------:|:-------------:|:----:|:------------| +| `headline` | `none` | `dictionary \| content?` | Title of the report | +| `authors` | `none` | `array \| content?` | One or multiple authors to be credited in the report | +| `group` | `none` | `content?` | Your class (or group) number/letter/identifier to be displayed right after the author(s) | +| `footer-left` | `none` | `content?` | Usually your lab bench number | +| `footer-right` | `none` | `content?` | Usually the date at which the lab work/practical was carried out | +| `outlined` | `true` | `bool` | Display the table of contents ? | +| `logo` | `image("internal/logo-insa-lyon.png")` | `image \| content?` | University logo to display | + +A single positional argument is accepted, being the report's body. + +You can call the template using the following syntax : + +```typ +// Local import +// #import "ttuile.typ": * + +// Universe import +#import "@preview/ttuile:0.2.0": * + +#show: ttuile.with( + // This is one way to set the headline, but the following also works : + // * headline: [You may supply just the title], + // * headline: text(fill: blue, weight: "regular")[And even style it\ however you wish], + headline: ( + lead: [Compte rendu de TP n°1 :], + title: [« #lorem(8) »], + ), + // Same as above : + // * authors: [You may also supply whatever you want], + authors: ( + "Theresa Tungsten", + "Jean Dupont", + "Eugene Deklan", + ), + group: "TD0", + footer-left: [Poste n°0], + footer-right: datetime.today().display("[day]/[month]/[year]"), + outlined: true, + // Also remove the uni logo or insert your own : + // * logo: image("your-logo.png"), + // * logo: none, +) +``` + +## 📚 Documentation + +The package `ttuile.typ` exposes multiple functions, find out more about them in the _documentation_. + +

+ + To the documentation + +

+ +An example file is also available in [`template/main.typ`](https://github.com/vitto4/ttuile/blob/main/template/main.typ) + + +## 🔖 Notes + +- As mentioned previously, the template targets French students, so you'll get things like `Auteurs != Authors`, `Annexe != Appendix` and such. Thankfully I didn't cut corners there hehe, all of that can be tweaked : + ```typ + #show: ttuile.with( + headline: [Yay, the French's all gone !], + authors: [*Authors:* Theresa Tungsten, Jean Dupont and Eugene Deklan], + group: "Group 1", + // This is supposed to be the lab bench number, but you may as well put whatever in there + footer-left: [Hello, world!], + footer-right: datetime.today().display("[day]/[month]/[year]"), + // You can use your own university's logotype + logo: image("path_to/logo.png"), + ) + + // This will fix tables and figures + #set text(lang: "en") + + // And this the appendices section + #appendices-section( + ..., + headline: "Appendices", + supplement: "Appendix", + outline-title: "List of appendices", + ) + ``` +- You may also tweak heading spacing : `#show heading: set block(above: 18pt, below: 5pt)`. +- The MIT license doesn't apply to the file `logo-insa-lyon.png`, it was retrieved from [INSA Lyon - éléments graphiques](https://www.insa-lyon.fr/fr/elements-graphiques). It doesn't apply either to the "INSA" branding. + + +## 🧩 Contributing + +Contributions are welcome ! Parts of the template are very much spaghetti code, so if you know the proper way of achieving what I'm going for, an issue or PR would be greatly appreciated :) \ No newline at end of file diff --git a/packages/preview/ttuile/0.2.0/internal/defaults.typ b/packages/preview/ttuile/0.2.0/internal/defaults.typ new file mode 100644 index 0000000000..e457d5704a --- /dev/null +++ b/packages/preview/ttuile/0.2.0/internal/defaults.typ @@ -0,0 +1,67 @@ +/* ------------------------------- Font sizes ------------------------------- */ +#let fsize-base = 12pt +#let fsize-header = 10.5pt +#let fsize-footer = 10pt +#let fsize-caption = 10pt +#let fsize-footnote = 9pt + +// Headline font sizes, in order : [lead, title] +#let fsize-headline = (14pt, 18pt) + +// Heading font sizes, in order : [h1, h2, h3, h4] +#let fsize-heading = (14pt, 13pt, 13pt, 12pt) + +#let fsize-appendices-outline-title = (16pt,) + +/* ---------------------------------- Fonts --------------------------------- */ +#let ffam-base = "HK Grotesk" +#let ffam-heading = "HK Grotesk" +#let ffam-special = "Liberation Serif" +#let ffam-outline = "Libertinus Serif" + + +/* --------------------------------- Lengths -------------------------------- */ +#let indent-base = 0.76cm +#let indent-outline = 0.4cm +#let indent-heading = 0.50cm +#let indent-numbering = 0.2cm + +// Spacing around headings, in order : [above, below] +#let vspacing-heading = (15pt, 12pt) + +#let vspacing-appendices-outline = 4.25pt +#let vspacing-appendices-heading = 3 * 4.25pt + +/* --------------------------------- Colors --------------------------------- */ + +// Used for the headline +#let color-headline = color.red + +// This one for figures' captions +#let color-blue-caption = color.rgb(0, 69, 134) + +// Heading colors, in order : [h1, h2, h3, h4] +#let color-heading = ( + color.rgb(0, 169, 51), // Green + color.rgb(52, 101, 164), // Blue + color.rgb(166, 77, 121), // Purple + black, +) + + +/* ---------------------------------- Misc ---------------------------------- */ +#let style-numbering-h1 = "I." +#let style-numbering-h2 = "1." +#let style-numbering-h3 = "A." +#let style-numbering-base = style-numbering-h1 + style-numbering-h2 + style-numbering-h3 +#let style-numbering-appendices = "A.1.1.1" + +// Prefix showing before the error messages in `assert`s and `panic`s +#let prefix-errors = "[ template / ttuile ] > " + +#let outline-depth = 3 + +// These are supposed to be random IDs used as markers/tags, +// so that we can tell for sure where the appendices begin and end. +#let metadata-appendices-start = "6a359bbd-b367-4af5-bd82-c80e83a64c78" +#let metadata-appendices-end = "ea2899f8-e9f3-4c70-b4b0-4e6afe77da9c" diff --git a/packages/preview/ttuile/0.2.0/internal/helpers.typ b/packages/preview/ttuile/0.2.0/internal/helpers.typ new file mode 100644 index 0000000000..b3a39b9be8 --- /dev/null +++ b/packages/preview/ttuile/0.2.0/internal/helpers.typ @@ -0,0 +1,239 @@ +#import "defaults.typ": * + +/// Deal with what was supplied through `authors` and `group` to the template +/// +/// See also : https://typst.app/docs/reference/foundations/arguments/#argument-sinks +#let authors-helper(group, authors) = { + let _type = type(authors) + + let _prefix + let _authors + let _group = if (group != none and _type != type(none)) [ -- #group] + + if (_type == array) { + // If there are many authors, we want something like `Auteurs : Auteur-1, Auteur-2 et Auteur-3` + let _len = authors.len() + _prefix = if (_len > 1) [Auteurs : ] else [Auteur : ] + _authors = authors.join(", ", last: " et ") + } else if (_type == content) { + // If a content block is provided, display with minimal tampering + _prefix = [] + _authors = authors + } else if (_type != type(none)) { + panic( + prefix-errors + "Please provide either an `array`, `content` block or `none` (leave empty) for field `authors`.", + ) + } + + return text(weight: "bold", _prefix) + _authors + _group +} + +/// Deal with what was supplied through `headline` to the template +#let headline-helper(headline) = { + let _type = type(headline) + let output + + if _type == dictionary { + let _keys = headline.keys() + assert( + "lead" in _keys and "title" in _keys, + message: prefix-errors + + "If you provide `headline` as a `dictionary`, it should possess keys `\"lead\"` and `\"title\"`. You may also pass `content?` to `headline`.", + ) + output = [ + // Lead + #v(-2pt) + #text( + size: fsize-headline.at(0), + headline.at("lead"), + ) + #v(weak: true, 8pt) + // Title + #text( + headline.at("title"), + ) + ] + } else { output = text(headline) } + + return { + set text(weight: "bold", fill: color-headline, size: fsize-headline.at(1)) + output + } +} + +/// Handle the display of appendices headings +#let appendix-heading-helper(title: none, lbl: none, supplement: none) = { + // These should not display in the document's main outline + set heading(supplement: supplement) + + show heading.where(level: 1): it => block(width: 100%)[ + #text( + size: fsize-heading.at(0), + weight: "bold", + )[ + #it.supplement + #context counter(heading).display() + #h(indent-heading) + #it.body + #{ v(vspacing-appendices-heading) } + ] + ] + + [#heading(level: 1, title) #lbl] +} + +#let appendix( + title: none, + lbl: none, + body, +) = { + if lbl != none { + assert.eq( + type(lbl), + label, + message: prefix-errors + + "`lbl` should be a `label`. You can use it in your document to reference the appendix in question.", + ) + } + return (title: title, lbl: lbl, body: body) +} + +#let appendices-section( + appendices: none, + outlined: true, + pagebreak-after-outline: false, + headline: "Annexes", + supplement: "Annexe", + outline-title: "Table des annexes", +) = { + assert.eq(type(appendices), array, message: prefix-errors + "`appendices` should be an `array`.") + + pagebreak(weak: true) + + /* -------------------------------- Headline -------------------------------- */ + + { + show text: set align(center) + set text(font: ffam-special) + + show heading.where(level: 1): it => text( + size: fsize-headline.at(1), + fill: black, + weight: "bold", + it.body, + ) + + rect( + width: 100%, + radius: 0%, + inset: (top: 8pt, bottom: 9pt), + stroke: 0.7pt, + )[ + #heading(level: 1, headline) + ] + } + + /* --------------------------------- Outline -------------------------------- */ + + if outlined { + // Outline title style + show heading.where(level: 1): it => { + set align(left) + text( + size: fsize-appendices-outline-title.at(0), + font: ffam-special, + weight: "bold", + )[ + #it.body + #v(vspacing-appendices-outline) + ] + } + + show outline.entry: set text(font: ffam-base) + + show outline.entry: it => link( + it.element.location(), + it.indented( + { + set text(weight: 500) + [#it.element.supplement ] + it.prefix() + if it.element.body != [] [ :] // Do not display `:` if the body is empty + }, + it.inner(), + ), + ) + + // Display the outline + outline( + title: outline-title, + target: heading.where(level: 1).after(label(metadata-appendices-start)).before(label(metadata-appendices-end)), + ) + v(0.5cm) // To set it apart from a potential heading + + if pagebreak-after-outline { + pagebreak() + } + } + + /* --------------------------------- Display -------------------------------- */ + + let _len = appendices.len() + + // Capture the context before displaying the appendices + context { + // This requires the `context` + let _counter-snapshot = counter(heading).get() + + // Apply appendices-specific heading numbering + set heading(numbering: style-numbering-appendices, bookmarked: false) + + // Forbid the use of level 1 headings, as it's already what appendices' titles are + show heading: it => if it.level == 1 { + panic( + prefix-errors + + "Headings of `level == 1` aren't supported in appendices ; but you may use headings of `level >= 2` instead.", + ) + } else if it.level <= 4 { + block( + width: 100%, + )[ #context counter(heading).display() #it.body ] // "reset" the style of other headings (see https://github.com/typst/typst/issues/420) + } else { it } + + // Flag this point as the beginning of the appendix section + [ #metadata("appendix-start") #label(metadata-appendices-start) ] + counter(heading).update(0) + + // Craft and display the different appendices + for i in range(_len) { + assert.eq( + type(appendices.at(i)), + dictionary, + message: prefix-errors + + "Got incorrect values in `appendices`. Each element of the array should be created using the `appendix` function.", + ) + let _keys = appendices.at(i).keys() + assert( + "title" in _keys and "lbl" in _keys and "body" in _keys, + message: prefix-errors + + "Got incorrect values in `appendices`. Each element of the array should be created using the `appendix` function.", + ) + + // Display the title + appendix-heading-helper( + title: appendices.at(i).at("title"), + lbl: appendices.at(i).at("lbl"), + supplement: supplement, + ) + + // Display the body + appendices.at(i).at("body") + + // And remember to insert a page break ; except for the last one + if i != _len - 1 { pagebreak() } + } + + // Flag this point as the end of the appendix section + [ #metadata("appendix-end") #label(metadata-appendices-end) ] + // Restore the initial state of the counter + counter(heading).update(_counter-snapshot) + } +} diff --git a/packages/preview/ttuile/0.2.0/internal/logo-insa-lyon.png b/packages/preview/ttuile/0.2.0/internal/logo-insa-lyon.png new file mode 100644 index 0000000000..90fda0fcbd Binary files /dev/null and b/packages/preview/ttuile/0.2.0/internal/logo-insa-lyon.png differ diff --git a/packages/preview/ttuile/0.2.0/template/main.typ b/packages/preview/ttuile/0.2.0/template/main.typ new file mode 100644 index 0000000000..8432a9b896 --- /dev/null +++ b/packages/preview/ttuile/0.2.0/template/main.typ @@ -0,0 +1,193 @@ +// ttuile +// ~~~~~~~~~~ +// Find out more on github +// https://github.com/vitto4/ttuile +// +// +// English-language report ? +// >> https://github.com/vitto4/ttuile#-notes + + +// Imports : ttuile, appendices-section, appendix +#import "@preview/ttuile:0.2.0": * + + +#show: ttuile.with( + // This is one way to set the headline, but the following also works : + // * headline: [You may supply just the title], + // * headline: text(fill: blue, weight: "regular")[And even style it\ however you wish], + headline: ( + lead: [Compte rendu de TP n°1 :], + title: [« #lorem(8) »], + ), + // Same as above : + // * authors: [You may also supply whatever you want], + authors: ( + "Theresa Tungsten", + "Jean Dupont", + "Eugene Deklan", + ), + group: "TD0", + footer-left: [Poste n°0], + footer-right: datetime.today().display("[day]/[month]/[year]"), + outlined: true, + // Also remove the uni logo or insert your own : + // * logo: image("your-logo.png"), + // * logo: none, +) + + +// You may delete everything below this line to get stared. +// +// If you're feeling lazy, give `Ctrl + Shift + End` a try :p +// +// <><><><><><><><><><><><><><><><><><><><><><><><><><><><><> // + + +// ---------------------------------------------------------- // +// Corps du rapport // +// ---------------------------------------------------------- // + +// ---------------------- Introduction ---------------------- // + += #lorem(1) + +#lorem(30) + +- #lorem(30) +- #lorem(25) + + +// Les équations sont numérotées par défaut +$ + E = m c^2 + "AI" +$ + +// Note de bas de page +#lorem(28) #footnote([#lorem(27)]) + + +#{ 2 * linebreak() } + + +// Création d'une figure +#let liste-couleurs = (black, gray, silver, white, navy, blue, aqua, teal, eastern, purple, fuchsia, maroon, red, orange, yellow, olive, green, lime) + +#let couleurs = grid( + columns: 9 * (1fr,), + rows: 2, + row-gutter: 1em, + ..liste-couleurs.map(c => { + square( + size: 45pt, + fill: c, + stroke: if (black, navy, maroon).contains(c) { 1.2pt + silver } else { 1.2pt }, + ) + }) +) + +#figure( + couleurs, + caption: [#lorem(10)], +) + + +// Saut de page après l'introduction +#pagebreak() + + +// ---------------------- Deuxième page --------------------- // + += #lorem(10)

+ +// L'espacement entre les titres peut être modifié : +// * #show heading: set block(above: 18pt, below: 5pt) +== #lorem(7) + +#lorem(26) + +// Il est possible de référencer une annexe définie à la fin du rapport +@annexe-1 #lorem(10) + +== #lorem(2) + +#lorem(18) + +=== #lorem(6) + +#lorem(45) #linebreak() +#lorem(35) + +// Les titres de niveau 4 ne sont pas affichés dans la table des matière +// C'est le plus bas niveau actuellement supporté par le template, un titre de niveau 5 ne sera pas stylisé adéquatement +==== #lorem(1) + +#lorem(30) + +// Cette équation n'est pas numérotée (contrairement à celle en introduction) +#math.equation( + numbering: none, + block: true, + $ + tilde(cal(T)) = + mat( + delim: "|", + 1, 2, ..., 10; + 2, 2, ..., 10; + dots.v, dots.v, dots.down, dots.v; + 10, 10, ..., 10; + gap: #0.3em + ) + $, +) + +#lorem(45) + +==== #lorem(5) + +#lorem(50) #linebreak() +#lorem(23) + +// ------------------------- Annexes ------------------------ // + +// Définition d'une annexe, elle reste pour l'instant simplement +// stockée dans une variable et n'est pas immédiatement affichée +// +// https://github.com/vitto4/ttuile/blob/main/docs/DOCS.md#appendix +#let annexe-1 = appendix( + title: [#lorem(5)], + lbl: , +)[ + // Le corps de l'annexe, i.e. ce qui est affiché sur la page en dessous du titre + #lorem(50) + + #align( + center, + )[ + *95% of people cannot solve this!* + #let rr = $thin \u{1f98f} thin$ + #let bb = $thin \u{1f37b} thin$ + #let ll = $thin \u{1f3ee} thin$ + + #{ + set math.equation(numbering: none) + $ + ll / (bb + rr) + bb / (ll + rr) + rr / (ll + bb) = 4 + $ + } + + *Can you find positive whole values for $ll$, $bb$ and $rr$?* + // https://www.quora.com/How-do-you-find-the-positive-integer-solutions-to-frac-x-y+z-+-frac-y-z+x-+-frac-z-x+y-4/answer/Alon-Amit >:3 + ] + + #lorem(45) +] + +// https://github.com/vitto4/ttuile/blob/main/docs/DOCS.md#appendices-section +#appendices-section( + // Ajouter les éventuelles autres annexes dans la liste + appendices: (annexe-1,), + // `true` par défaut, on demande l'affichage de la table des annexes + outlined: true, + pagebreak-after-outline: false, +) diff --git a/packages/preview/ttuile/0.2.0/thumbnail.png b/packages/preview/ttuile/0.2.0/thumbnail.png new file mode 100644 index 0000000000..44634f6915 Binary files /dev/null and b/packages/preview/ttuile/0.2.0/thumbnail.png differ diff --git a/packages/preview/ttuile/0.2.0/ttuile.typ b/packages/preview/ttuile/0.2.0/ttuile.typ new file mode 100644 index 0000000000..bb860e241e --- /dev/null +++ b/packages/preview/ttuile/0.2.0/ttuile.typ @@ -0,0 +1,300 @@ +/// Expose these to the end user +#import "internal/helpers.typ": appendices-section, appendix + +#let ttuile( + /// Title of the report ; `dictionary | content?` + headline: none, + /// Authors of the report ; `array | content?` + authors: none, + /// Group number ; `content?` + group: none, + /// Usually the lab bench number ; `content?` + footer-left: none, + /// Usually the date at which the lab work/practical was carried out ; `content?` + footer-right: none, + /// Display the table of contents ? ; `bool` + outlined: true, + /// University logo to display ; `image | content?` + logo: image("internal/logo-insa-lyon.png"), + /// Body of the report + doc, +) = { + /// Private imports + import "internal/helpers.typ": authors-helper, headline-helper + import "internal/defaults.typ": * + + /* -------------------------------------------------------------------------- */ + /* Styling */ + /* -------------------------------------------------------------------------- */ + + /// Language and text + set text( + lang: "fr", + size: fsize-base, + font: ffam-base, + weight: "regular", + stretch: 100%, + ) + + /// Paragraphs + set align(left) + set par(justify: true) + + /// Page format + set page( + paper: "a4", + margin: ( + left: 2cm, + right: 2cm, + top: 2.5cm, + bottom: 2.5cm, + ), + header-ascent: 30%, + // Header with authors and uni logo + header: [ + #set text( + font: ffam-special, + size: fsize-header, + ) + // Spacing from the top of the page, somewhat of a magic number + #v(38.51pt) + #grid( + columns: (5fr, 1fr), + column-gutter: 1em, + // Authors, left aligned + align(left + horizon)[ + #authors-helper(group, authors) + ], + // Uni logo (if applicable) + if (logo != none) { + set image(fit: "contain") + align(center + horizon, logo) + }, + ) + ], + footer-descent: 30%, + // Footer with page numbers + footer: [ + // Formatting + #set text( + font: ffam-special, + size: fsize-footer, + ) + #grid( + columns: (1fr, 1fr, 1fr), + align(left)[#footer-left], + // Page number + align(center)[ + #context counter(page).display( + "﹣1 / 1﹣", + both: true, + ) + ], + align(right)[#footer-right], + ) + ], + ) + + /// Underline outgoing links only + show link: it => { + if (type(it.dest) == str) { + underline(it) + } else { it } + } + + /// Heading numbering + /// See : https://www.reddit.com/r/typst/comments/18exrv5/hide_previous_level_heading_counters/ + set heading( + numbering: (..nums) => { + let nums = nums.pos() + // Level of the current heading + let level = nums.len() + + if level < 3 { + let style = style-numbering-h1 + style-numbering-h2 + let num = nums + return numbering(style, ..num) + } else if level == 3 { + let style = style-numbering-h3 + let num = nums.last() + return numbering(style, num) + } else { return none } + }, + ) + + /// Lists + set list( + marker: ([•], [--]), + indent: indent-base, + ) + + /// Footnotes + show footnote.entry: set text(size: fsize-footnote) + + /// Figures + show figure.caption: set text( + size: fsize-caption, + fill: color-blue-caption, + weight: "bold", + ) + show figure.caption: it => [ + #it.supplement #context it.counter.display() : + #set text(style: "italic"); #it.body + ] + + /// Equations + set math.equation(numbering: "(1)") + + /// References + show ref: it => { + // Default return value + let _content = it + + // Underlining style + let stroke-style = (dash: "dotted", thickness: 0.8pt) + + if it.element != none and (it.element.func() == heading) { + // Array of headings from the appendices section + let _appendix-headings = query( + heading.where().after(label(metadata-appendices-start)).before(label(metadata-appendices-end)), + ) + + if (it.element not in _appendix-headings) { + if it.element.level <= 3 { + let number = numbering( + // Cannot use `it.element.numbering` because for level 3 headings it's not the same as `style-numbering-base` + style-numbering-base, + // Here we specifically want the whole "I.1.A." do be displayed + ..counter(heading).at(it.element.location()), + ) + _content = text(weight: 500, number) + } else if it.element.level == 4 { + _content = text(weight: 400, it.element.body) + } else { + panic( + prefix-errors + + "Cannot reference headings of `level >= 5` at the moment. Try defining your own `show ref: it => if it.element != none and (it.element.func() == heading) and it.element.level == _ {...} else {it}` for the levels you're interested in referencing.", + ) + } + } else { + // Else, we are referencing a heading from the appendices section + let number = numbering( + style-numbering-appendices, + ..counter(heading).at(it.element.location()), + ) + if it.element.level == 1 { + _content = text(weight: 500, style: "normal")[#it.element.supplement #number] + } else { + // TODO For now the author is free to add `Annexe` before reference to subsections. Maybe enforce `Annexe #number` ? + _content = text(number) + } + } + // Don't forget to link to the element + _content = link(it.target, _content) + } + return underline(stroke: stroke-style, _content) + } + + /* -------------------------------- Headings -------------------------------- */ + + /// Waiting on https://github.com/typst/typst/issues/1699 to adjust heading spacing + /// See : https://github.com/typst/typst/issues/1699#issuecomment-2144928281 + + /// Positioning + show heading: set block(width: 100%) + show heading: set align(left) + + /// Spacing + show heading: set block(above: vspacing-heading.at(0), below: vspacing-heading.at(1)) + + /// Formatting + show heading: it => { + // Counter or decoration + if it.level < 4 { context counter(heading).display() } else if it.level == 4 { + str.from-unicode(10146) // ➢ + } + // Spacing between the decoration and the body + h(indent-numbering) + // Only underline level 1 through 3 + if it.level < 4 { underline(it.body) } else { it.body } + } + + /// Styling + show heading: it => { + // For headings level 1 through 4 + set text( + size: fsize-heading.at(it.level - 1), + fill: color-heading.at(it.level - 1), + ) if it.level <= 4 + + set text( + font: ffam-heading, + weight: if (it.level == 4) { 600 } else { "bold" }, + ) + + it + } + + /// Indenting + /// + /// See also : + /// * https://github.com/typst/typst/discussions/2812 + /// * https://forum.typst.app/t/how-can-i-indent-my-headings/3185/4 + show heading: it => pad( + left: if (it.level < 4) { (it.level - 1) * indent-heading } else { 1.5 * indent-heading }, + it, + ) + + /// Safeguard, there is no style defined for level 5 and above. + /// Has to be implemented this way, see https://github.com/typst/typst/issues/4950 + /// + /// This snippet also has to come after the others, because at some point we return `it.body` + /// instead of `it`, which "strips" this very safeguard (that was acting on `it` only). + show heading: it => if it.level > 4 { + panic( + prefix-errors + + "Headings of `level > 4` aren't supported by the template ; but you can define your own style `show heading.where(level: _): it => ...`. Get rid of the error by replacing the dots with `it.body` for example.", + ) + } else { it } + + /* -------------------------------------------------------------------------- */ + /* Display */ + /* -------------------------------------------------------------------------- */ + + /// Headline + { + set align(center) + set text(font: ffam-special) + set rect( + width: 100%, + radius: 0%, + inset: (top: 10pt, bottom: 10pt), + stroke: 0.7pt, + ) + if headline != none { + rect(headline-helper(headline)) + } + } + + /// Outline + set outline( + title: none, + indent: indent-outline, + depth: outline-depth, + target: heading + .where() + .before(label(metadata-appendices-start)) + .or(heading.where().after(label(metadata-appendices-end))), + ) + + show outline: set text(size: fsize-base, font: ffam-outline) + + if outlined { + // Spacing under the headline + if headline != none { v(0.3cm) } + outline() + } + + /// Document body + doc +} diff --git a/packages/preview/ttuile/0.2.0/typst.toml b/packages/preview/ttuile/0.2.0/typst.toml new file mode 100644 index 0000000000..1bbee06fd4 --- /dev/null +++ b/packages/preview/ttuile/0.2.0/typst.toml @@ -0,0 +1,17 @@ +[package] +name = "ttuile" +version = "0.2.0" +compiler = "0.13.0" +entrypoint = "ttuile.typ" +authors = ["vitto <@vitto4>"] +license = "MIT" +categories = ["report"] +repository = "https://github.com/vitto4/ttuile" +keywords = ["insa", "engineering", "report", "tp", "cr", "compte-rendu"] +disciplines = ["engineering"] +description = "Students' lab reports at INSA Lyon, a french engineering school." + +[template] +path = "template" +entrypoint = "main.typ" +thumbnail = "thumbnail.png" \ No newline at end of file