diff --git a/packages/preview/modern-usp-thesis/0.1.0/LICENSE b/packages/preview/modern-usp-thesis/0.1.0/LICENSE new file mode 100644 index 0000000000..12c8e9996b --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rubens Andrade + +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/modern-usp-thesis/0.1.0/LICENSE-MIT-0 b/packages/preview/modern-usp-thesis/0.1.0/LICENSE-MIT-0 new file mode 100644 index 0000000000..7424271a08 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/LICENSE-MIT-0 @@ -0,0 +1,16 @@ +MIT No Attribution + +Copyright (c) 2026 Rubens Andrade + +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. + +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/modern-usp-thesis/0.1.0/README.md b/packages/preview/modern-usp-thesis/0.1.0/README.md new file mode 100644 index 0000000000..198e2d1245 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/README.md @@ -0,0 +1,223 @@ +# USP Thesis Typst Template + +A comprehensive, extensible Typst template for theses and dissertations at the University of São Paulo (USP) and specifically the Institute of Mathematics and Statistics (IMEUSP), following the official guidelines (5th edition, 2024). + +![Cover page of a thesis generated with this template](thumbnail.png) + +Example output PDF generated with this template: [usp-example.pdf](https://github.com/andrader/usp-thesis-typst-template/blob/bc838c7d272bc1e3544a78fa0d8e1155db160622/examples/usp-example.pdf) + +## Features +- **Official Layout**: Correct margins (3cm/2cm), A4 size, and 1.5 line spacing. +- **Automated Elements**: Generates Cover, Title Page, Approval Sheet, and Abstracts. +- **IMEUSP Support**: Specific branding and "Standard Statement" for the Institute of Mathematics and Statistics. +- **Extensible**: Easily adaptable to other USP institutes. +- **Pre-textual Elements**: Support for Dedication, Acknowledgments, and Epigraph. +- **PDF Bookmarks**: Cover, lists and table of contents appear in the PDF viewer's outline. +- **References**: ABNT (NBR 6023) layout in the IME-USP author-date style by default. +- **Appendices and Annexes**: `#show: appendix` / `#show: annex` give lettered headings ("APPENDIX A – TITLE") in the text and the table of contents. +- **Drafting Notes**: `#todo(kind: "verify")[...]` inline notes, colored by kind, listed by `#note-outline()`. + +## Table of Contents +- [USP Thesis Typst Template](#usp-thesis-typst-template) + - [Features](#features) + - [Table of Contents](#table-of-contents) + - [Prerequisites](#prerequisites) + - [Getting Started](#getting-started) + - [Example Usage](#example-usage) + - [Configuration Options](#configuration-options) + - [Future Extensions](#future-extensions) + - [Development and Testing](#development-and-testing) + - [License](#license) + +## Prerequisites + +- [Typst Compiler](https://typst.app/): Typst is a modern, faster, and more intuitive typesetting alternative to LaTeX, featuring cleaner syntax and instant compilation, making it ideal for new projects. + +
+ [Click to expand] How to install Typst ⚙️ + + ### MacOS + + Open Terminal and run: + + ```bash + brew install typst + ``` + + ### Linux + + Open Terminal and run: + + ```bash + # For Debian/Ubuntu-based distributions + sudo apt install typst + # For Fedora-based distributions + sudo dnf install typst + # Snap + sudo snap install typst + ``` + + ### Windows + + Open PowerShell and run: + + ```powershell + winget install typst + ``` + +
+ + + + +## Getting Started + +### Typst web app + +Click **Start from template** on [typst.app](https://typst.app/) and search for `modern-usp-thesis`. + +### Command line + +Create a new project from the template: + +```bash +typst init @preview/modern-usp-thesis:0.1.0 +``` + +Then generate the PDF with: + +```bash +cd modern-usp-thesis +typst compile main.typ +``` + +To watch for changes and recompile automatically: + +```bash +typst watch main.typ +``` + +## Example Usage + +```typst +#import "@preview/modern-usp-thesis:0.1.0": usp-thesis, appendix + +#show: usp-thesis.with( + title: [Your Thesis Title], + author: "Your Name", + advisor: "Advisor's Name", + institute: "Instituto de Matemática e Estatística", + program: "Estatística", + degree: "Mestre", // or "Doutor" + abstract-pt: [ ... ], + keywords-pt: ("Keyword1", "Keyword2"), + abstract-en: [ ... ], + keywords-en: ("Keyword1", "Keyword2"), + banca: ( + (nome: "Examiner 1", instituicao: "USP"), + (nome: "Examiner 2", instituicao: "Unicamp"), + ), +) + += Introduction +Your content starts here... + +#bibliography("refs.bib") // ABNT / IME-USP style unless `style:` is given + +#show: appendix += Proofs // printed as "APPENDIX A – PROOFS", referenced as "Appendix A" +``` + +## Configuration Options + +The `usp-thesis` function accepts the following parameters. Only `title`, `author`, `advisor`, `program` and the abstracts really need to be set; everything else has a sensible default. + +| Parameter | Type | Default | Description | +| :--- | :--- | :--- | :--- | +| `title` | content | `[Título da Dissertação]` | The main title of the work. | +| `title-alt` | content | `none` | The title in the other language (required by USP), printed in the reference above that language's abstract. | +| `subtitle` | content | `none` | Optional subtitle. | +| `author` | string | `"Nome do Autor"` | Full name of the author. | +| `advisor` | string | `"Nome do Orientador"` | Full name of the supervisor. | +| `coadvisor` | string | `none` | Full name of the co-supervisor. | +| `degree` | string | `"Mestre"` | `"Mestre"` or `"Doutor"` (or `degrees.msc` / `degrees.phd`). The template prints the title "Mestre em Ciências" / "Doutor em Ciências" ("Master of Science" / "Doctor of Science" in English). If your program grants another title, pass it in full, e.g. `"Mestre em Engenharia"`. | +| `program` | string | `"Nome do Programa"` | Name of the graduate program, printed as "Programa: …", so write `"Estatística"` rather than `"Programa de Pós-Graduação em Estatística"`. | +| `area` | string | `none` | Concentration area ("Área de Concentração: …"). | +| `institute` | string | `"Instituto de Matemática e Estatística"` | Full name of the USP institute. IME gets its own statement; other institutes get the general USP one. | +| `local` | string | `"São Paulo"` | City shown on the cover and title page. | +| `year` | string / int / auto | `auto` | Year of deposit. `auto` uses the current year. | +| `version` | string | `"Original"` | `"Original"` or `"Corrigida"` (or `versions.original` / `versions.revised`), printed as "Versão Original". | +| `nature` | string | `none` | Overrides the inferred "Dissertação" / "Tese". | +| `lang` | string | `"pt"` | Main language, `"pt"` or `"en"` (or `langs.pt` / `langs.en`). | +| `font` | string / array | `"New Computer Modern"` | Document font, or a list of fallback fonts. Applies to every page, cover included. | +| `cover` | bool | `true` | Whether to print the cover. | +| `title-page` | bool | `true` | Whether to print the title page. | +| `catalog-card` | content | `none` | Optional ficha catalográfica, printed at the foot of the page after the title page (e.g. `image("ficha.png")`). Not printed without the title page. | +| `abstract-pt` | content | `none` | Abstract in Portuguese (Resumo). | +| `keywords-pt` | array | `()` | Keywords in Portuguese. | +| `abstract-en` | content | `none` | Abstract in English. | +| `keywords-en` | array | `()` | Keywords in English. | +| `reference-pt` / `reference-en` | content / auto / none | `auto` | Bibliographic reference above each abstract (auto: built from author, title, year and institute; none: omitted). | +| `dedication` | content | `none` | Optional dedication. | +| `acknowledgments` | content | `none` | Optional acknowledgments. | +| `epigraph` | content | `none` | Optional epigraph. | +| `errata` | content | `none` | Optional errata. | +| `list-of-figures` | bool / auto | `auto` | Whether to include the list of figures (auto: show if there are 5 or more). | +| `list-of-tables` | bool / auto | `auto` | Whether to include the list of tables (auto: show if there are 5 or more). | +| `table-of-contents` | bool | `true` | Whether to include the table of contents (Sumário). | +| `abbreviations` | content | `none` | Optional list of abbreviations and acronyms. | +| `symbols` | content | `none` | Optional list of symbols. | +| `banca` | array | `()` | Jury members as `(nome: "", instituicao: "")` dictionaries. The approval sheet is only printed when this is not empty. | +| `front-matter` | bool | `true` | Whether to print the pre-textual elements. `false` prints only the text, overriding the options above (see below). | + +### Leaving out pre-textual elements + +Most pre-textual elements are only printed when you pass them (abstracts, dedication, `banca`...). The cover, title page and table of contents are always printed unless you turn them off with `cover: false`, `title-page: false` or `table-of-contents: false`. Page numbering counts from the title page (ABNT), or from the first page printed when there is no title page. + +To compile only your chapters, e.g. to share a draft with your advisor, set `front-matter: false`. Every pre-textual element is left out, whatever the other parameters say, so they can stay as they are; the text keeps the same layout, chapter references and bibliography style, numbered from page 1. + +```typst +#show: usp-thesis.with( + title: [Your Thesis Title], + // ... + front-matter: false, +) +``` + +With the defaults above, the title page of an IME master's dissertation reads: + +> Dissertação apresentada ao IME-USP para obtenção do título de Mestre em Ciências. Programa: Estatística + +and for another institute, e.g. `institute: "Escola Politécnica"`, `degree: "Doutor em Engenharia"`: + +> Tese apresentada à Escola Politécnica da Universidade de São Paulo para obtenção do título de Doutor em Engenharia. Programa: Engenharia Elétrica + +## Future Extensions + +To add support for a new institute with a specific "Nature Text", modify the `nature-text` logic in `src/usp-thesis.typ`: + +```typst +let nature-text = if institute.contains("Your Institute") { + "Specific Statement for your Institute" +} else { + // default ABNT/USP statement +} +``` + +## Development and Testing + +To test changes before publishing, link this repository as a local package (macOS example; use `~/.local/share` on Linux or `%APPDATA%` on Windows, or run `typst info` to see the package path): + +```sh +mkdir -p ~/Library/Application\ Support/typst/packages/preview/modern-usp-thesis/ +ln -sfn $PWD ~/Library/Application\ Support/typst/packages/preview/modern-usp-thesis/0.1.0 +``` + +Then `typst init @preview/modern-usp-thesis:0.1.0` uses your local copy. Run `just test` to compile the files in `examples/`. + +## License + +The package code is licensed under the [MIT License](LICENSE), with two exceptions: + +- The files in `src/template/`, which are copied into your project by `typst init`, are licensed under [MIT No Attribution](LICENSE-MIT-0), so you can use and distribute your thesis without any license obligations. +- `src/usp-ime.csl` is the [Universidade de São Paulo – Instituto de Matemática e Estatística](https://www.zotero.org/styles/universidade-de-sao-paulo-instituto-de-matematica-e-estatistica) citation style from the Zotero Style Repository, licensed under [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/). diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/elements.typ b/packages/preview/modern-usp-thesis/0.1.0/src/elements.typ new file mode 100644 index 0000000000..aac9e249bd --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/elements.typ @@ -0,0 +1,164 @@ +// Elements for USP theses and dissertations + +#let cover( + institution: none, + author: none, + title: none, + subtitle: none, + volumes: none, + local: none, + year: none, +) = { + set page(margin: 3cm) + set align(center) + set text(size: 12pt) + + if institution != none { + upper(institution) + v(1cm) + } + + v(3cm) + upper(author) + + v(4cm) + text(14pt, strong(upper(title))) + if subtitle != none { + [: ] + text(14pt, strong(upper(subtitle))) + } + + if volumes != none { + v(1cm) + [Volume #volumes] + } + + v(1fr) + [#local \ #year] + + pagebreak() +} + +#let title-page( + author: none, + title: none, + subtitle: none, + version: "Original", + volumes: none, + nature: none, + institute: none, + degree: none, + program: none, + area: none, + area-label: "Área de Concentração: ", + advisor: none, + coadvisor: none, + local: none, + year: none, +) = { + set page(margin: 3cm) + set align(center) + + upper(author) + + v(4cm) + text(14pt, strong(upper(title))) + if subtitle != none { + [: ] + text(14pt, strong(upper(subtitle))) + } + + v(2cm) + strong(version) + + v(2cm) + align(right)[ + #box(width: 50%)[ + #set align(left) + #set text(size: 10pt) + #nature + + #if area != none [#area-label #area] + + #advisor + #if coadvisor != none [\ #coadvisor] + ] + ] + + v(1fr) + [#local \ #year] + + pagebreak() +} + +#let approval-sheet( + author: none, + title: none, + subtitle: none, + nature: none, + date: "____/____/____", + banca: (), + labels: ( + author: "Autor", + title: "Título", + approved-on: "Aprovado em", + banca: "Banca Examinadora", + judgement: "Julgamento", + ), + is-branded: false, +) = { + set page(margin: 3cm) + set text(size: 12pt) + + [#labels.author: #author \ ] + [#labels.title: #strong(title)] + if subtitle != none [: #strong(subtitle)] + + v(1cm) + nature + if not nature.ends-with(".") [.] + + v(1cm) + [#labels.approved-on: #date] + + v(1cm) + align(center)[#labels.banca] + v(0.5cm) + + for membro in banca [ + #v(1cm) + #line(length: 100%, stroke: 0.5pt) + #membro.nome \ + #membro.instituicao \ + #labels.judgement: #line(length: 3cm, stroke: 0.5pt) + ] + + pagebreak() +} + +#let abstract-page( + title, + body, + keywords-list: (), + keywords-label: "Palavras-chave: ", + reference: none, +) = { + heading(level: 1, numbering: none, outlined: false)[#title] + + set align(left) + if reference != none { + set text(size: 10pt) + reference + v(1cm) + } + + set par(justify: true, leading: 0.5em) + body + + v(1cm) + strong([#keywords-label]) + keywords-list.join([. ]) + [.] + + pagebreak() +} diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/layout.typ b/packages/preview/modern-usp-thesis/0.1.0/src/layout.typ new file mode 100644 index 0000000000..e3d5096759 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/layout.typ @@ -0,0 +1,158 @@ +#import "@preview/drafting:0.2.2": inline-note, note-outline + +// Layout settings for USP theses and dissertations + +#let setup-layout(lang: "pt", body) = { + // Paper and Margins + set page( + paper: "a4", + margin: ( + top: 3cm, + left: 3cm, + right: 2cm, + bottom: 2cm, + ), + ) + + // Typography + set text( + size: 12pt, + lang: lang, + ) + + // 1.5 line spacing (ABNT NBR 14724): an ~18pt baseline-to-baseline distance + // at 12pt, as LaTeX's `\onehalfspacing`. Typst's leading is the gap between + // the baseline and the next line's cap height (~0.7em), hence 0.8em. + set par( + leading: 0.8em, + spacing: 1.5em, + justify: true, + ) + + // Section numbering + set heading(numbering: "1.1.1.1.1") + + // Section styling + show heading.where(level: 1): it => { + pagebreak(weak: true) + v(1.5cm) + set text(size: 14pt, weight: "bold") + if it.numbering == none { + // Pre-textual elements: Centered and All Caps + align(center, upper(it.body)) + } else { + // Textual chapters: Bold, 14pt, keep case as provided + it + } + v(1.5cm) + } + + show heading.where(level: 2): it => { + v(1em) + set text(size: 12pt, weight: "bold") + it + v(0.5em) + } + + show heading.where(level: 3): it => { + v(0.5em) + set text(size: 12pt, weight: "bold") + it + v(0.5em) + } + + // Table of Contents styling + show outline.entry.where(level: 1): it => { + v(1em, weak: true) + // Lists of figures and tables (all level-1 entries) stay in regular weight. + if it.element.func() == figure { + it + } else if it.element.func() == heading and it.element.numbering == "A.1" { + // Appendix and annex entries read "APPENDIX A – Title" (see `appendix`). + let n = numbering("A", ..counter(heading).at(it.element.location())) + strong(link(it.element.location(), it.indented( + none, + [#upper[#it.element.supplement #n –] #it.inner()], + ))) + } else if it.element.func() == heading and it.element.numbering == none { + strong(upper(it)) + } else { + strong(it) + } + } + + // References (ABNT NBR 6023): left-aligned, not justified, in the IME-USP + // author-date style. A `style` passed to `bibliography` overrides it. + set bibliography(style: read("usp-ime.csl", encoding: none)) + show bibliography: set par(justify: false) + + // Captions and Tables + show figure: set text(size: 10pt) + show figure.where(kind: table): set figure.caption(position: top) + show figure.where(kind: image): set figure.caption(position: top) + + body +} + +// Special formatting for long quotes (> 3 lines) +#let quote-long(body) = { + set text(size: 10pt) + set par(leading: 0.5em, justify: true) + pad(left: 4cm, body) +} + +// Table helpers (booktabs style) +#let toprule = table.hline(stroke: 1.5pt) +#let midrule = table.hline(stroke: 0.8pt) +#let bottomrule = table.hline(stroke: 1.5pt) + +// Appendices and annexes (ABNT NBR 14724): lettered numbering, referenced as +// "Appendix A", and the level-1 heading printed as "APPENDIX A – TITLE". +// Use `#show: appendix` (or `#show: annex`) before the first one; the +// numbering restarts at A. +#let appendix(supplement: auto, body) = { + let supplement = if supplement == auto { + context if text.lang == "pt" [Apêndice] else [Appendix] + } else { supplement } + set heading(numbering: "A.1") + show heading.where(level: 1): set heading(supplement: supplement) + show heading.where(level: 1): it => { + pagebreak(weak: true) + v(1.5cm) + set text(size: 14pt, weight: "bold", hyphenate: false) + set par(justify: false) + align(center, upper[#it.supplement #counter(heading).display("A") – #it.body]) + v(1.5cm) + } + counter(heading).update(0) + body +} + +#let annex(body) = appendix( + supplement: context if text.lang == "pt" [Anexo] else [Annex], + body, +) + +// Drafting / TODO notes. Notes are inline, highlighted in the running text: +// margin notes that overlap are pushed down through a state that needs one +// extra layout pass per overlapping note, so dense pages never converge. Each +// kind of note has its own color, which `#note-outline()` also shows. +#let todo-kinds = ( + write: (label: "Write", color: orange), + results: (label: "Results", color: blue), + decision: (label: "Decision", color: purple), + source: (label: "Source", color: red), + verify: (label: "Verify", color: rgb("#008b8b")), + code: (label: "Code", color: rgb("#2e8b57")), +) + +#let todo(kind: "write", content) = { + assert(kind in todo-kinds, message: "unknown todo kind: " + kind) + let (label, color) = todo-kinds.at(kind) + inline-note( + par-break: false, + stroke: color + 1pt, + fill: color.lighten(85%), + text(size: 0.85em)[*#label:* #content], + ) +} diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/lib.typ b/packages/preview/modern-usp-thesis/0.1.0/src/lib.typ new file mode 100644 index 0000000000..bd3e7f0425 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/lib.typ @@ -0,0 +1,29 @@ +#import "usp-thesis.typ": usp-thesis +#import "layout.typ": quote-long, appendix, annex, todo, todo-kinds, note-outline, toprule, midrule, bottomrule +#import "math.typ": * + +// Re-exporting common packages for the user +#import "@preview/unify:0.8.1": num, qty +#import "@preview/subpar:0.2.2" as subpar + +// --- Constants (Pseudo-Enums) --- + +/// Document languages +#let langs = ( + pt: "pt", + en: "en", +) + +/// Degree levels. The template turns these into the full title +/// ("Mestre em Ciências" / "Master of Science"); pass a full title such as +/// "Mestre em Engenharia" to `degree` when your program grants another one. +#let degrees = ( + msc: "Mestre", + phd: "Doutor", +) + +/// Document versions +#let versions = ( + original: "Original", + revised: "Corrigida", +) diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/math.typ b/packages/preview/modern-usp-thesis/0.1.0/src/math.typ new file mode 100644 index 0000000000..fc7f0318b2 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/math.typ @@ -0,0 +1,62 @@ +#import "@preview/ctheorems:2.0.0" +#import ctheorems: qedhere + +// Subscripts go underneath in display math, as for lim and max. +#let argmax = math.op("argmax", limits: true) +#let argmin = math.op("argmin", limits: true) +#let bm(x) = math.bold(x) +#let tr = math.op("tr") +#let diag = math.op("diag") +#let Cov = math.op("Cov") +#let Var = math.op("Var") +#let EE = math.bb("E") +#let RR = math.bb("R") + +// Theorem environments setup +#let thm-rules(body) = { + show: ctheorems.thm-rules + body +} + +// Boxed environments (theorem, lemma, definition) and plain ones +// (corollary, proof), with vertical padding around the boxed ones. +#let _thm-fmt(padding: (top: 0em, bottom: 0em), ..args) = thm => pad( + ..padding, + ctheorems.thm-fmt-block(thm, ..args), +) +#let _boxed = _thm-fmt( + padding: (top: 0.5em, bottom: 0.5em), + block-args: (inset: 1.2em, radius: 0.3em, breakable: false), + body-fmt: x => x, + separator: [#h(0.1em):#h(0.2em)], +) +#let _plain(..args) = _thm-fmt( + block-args: (inset: (top: 0em, left: 1.2em, right: 1.2em), breakable: true), + name-fmt: name => emph[(#name)], + body-fmt: x => x, + separator: [#h(0.1em):#h(0.2em)], + ..args, +) + +#let _theorem = ctheorems.thm.with(counter: "theorem", fmt: _boxed, fill: rgb("#eeeeeef0")) +#let _lemma = ctheorems.thm.with(counter: "lemma", fmt: _boxed, fill: rgb("#eeeeeef0")) +#let _corollary = ctheorems.thm.with(counter: "corollary", base: "theorem", fmt: _plain(title-fmt: strong)) +#let _definition = ctheorems.thm.with(counter: "definition", fmt: _boxed, inset: (x: 1.2em, y: 1em)) +#let _proof = ctheorems.thm.with( + counter: "proof", + numbering: none, + fmt: _plain(title-fmt: emph, name-fmt: emph, body-fmt: ctheorems.proof-body-fmt), +) + +#let theorem = _theorem.with(supplement: "Teorema") +#let lemma = _lemma.with(supplement: "Lema") +#let corollary = _corollary.with(supplement: "Corolário") +#let definition = _definition.with(supplement: "Definição") +#let proof = _proof.with(supplement: "Prova") + +// English aliases +#let en-theorem = _theorem.with(supplement: "Theorem") +#let en-lemma = _lemma.with(supplement: "Lemma") +#let en-corollary = _corollary.with(supplement: "Corollary") +#let en-definition = _definition.with(supplement: "Definition") +#let en-proof = _proof.with(supplement: "Proof") diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/template/main.typ b/packages/preview/modern-usp-thesis/0.1.0/src/template/main.typ new file mode 100644 index 0000000000..bfe2ea56e9 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/template/main.typ @@ -0,0 +1,105 @@ +#import "@preview/modern-usp-thesis:0.1.0": usp-thesis, appendix, annex + +#show: usp-thesis.with( + title: [Desenvolvimento de Templates Typst para a USP], + title-alt: [Development of Typst Templates for USP], + subtitle: [Um Estudo de Caso de Automação Acadêmica], + author: "João da Silva", + advisor: "Prof. Dr. Orientador Exemplar", + institute: "Instituto de Matemática e Estatística", + program: "Estatística", + degree: "Mestre", + local: "São Paulo", + // year: "2026", // defaults to the current year + abstract-pt: [ + Este trabalho descreve a criação de um template Typst para dissertações e teses seguindo as diretrizes da USP. O template automatiza a formatação de capas, resumos e elementos pré-textuais. + ], + keywords-pt: ("Typst", "USP", "Dissertação", "Automação"), + abstract-en: [ + This work describes the creation of a Typst template for theses and dissertations following USP guidelines. The template automates the formatting of covers, abstracts, and pre-textual elements. + ], + keywords-en: ("Typst", "USP", "Thesis", "Automation"), + dedication: [À minha família.], + acknowledgments: [Agradeço à USP e à CAPES pelo apoio.], + epigraph: ["O sucesso é a soma de pequenos esforços repetidos dia após dia." \ --- Robert Collier], + errata: [ + #table( + columns: (1fr, 1fr, 1fr, 1fr), + [Folha], [Linha], [Onde se lê], [Leia-se], + [10], [5], [Typstt], [Typst], + ) + ], + list-of-figures: true, + list-of-tables: true, + abbreviations: [ + #grid( + columns: (100pt, 1fr), + row-gutter: 1em, + [ABNT], [Associação Brasileira de Normas Técnicas], + [USP], [Universidade de São Paulo], + [IME], [Instituto de Matemática e Estatística], + ) + ], + symbols: [ + #grid( + columns: (100pt, 1fr), + row-gutter: 1em, + [$sigma$], [Desvio padrão], + [$mu$], [Média populacional], + ) + ], + banca: ( + (nome: "Prof. Dr. Examinador 1", instituicao: "IME-USP"), + (nome: "Prof. Dr. Examinador 2", instituicao: "IME-USP"), + (nome: "Prof. Dr. Examinador Externo", instituicao: "UNICAMP"), + ), +) + += Introdução + +A USP exige uma formatação rigorosa para trabalhos acadêmicos. Este template visa facilitar esse processo @typst. + +#figure( + rect(width: 100pt, height: 50pt, fill: blue.lighten(80%))[Logo], + caption: [Exemplo de ilustração], +) + += Metodologia + +Utilizamos a linguagem Typst por sua velocidade e facilidade de uso em comparação ao LaTeX. + +#figure( + table( + columns: (auto, auto), + [Recurso], [Benefício], + [Velocidade], [Compilação instantânea], + [Sintaxe], [Fácil de ler e escrever], + ), + caption: [Comparação de recursos], +) + += Resultados + +O template consegue gerar PDFs compatíveis com as normas ABNT adotadas pela USP. + += Conclusão + +Typst é uma alternativa viável para a redação de teses na USP. + +#bibliography("references.bib") + +// --- Pós-textuais --- + += Glossário + +/ Typst: Um novo sistema de composição de documentos baseado em marcação que é projetado para ser tão poderoso quanto o LaTeX e tão fácil de usar quanto o Markdown. + +#show: appendix + += Detalhes da Implementação +Este apêndice contém detalhes técnicos sobre as funções de layout. + +#show: annex + += Regulamento da Pós-Graduação +Documentação oficial da USP. diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/template/references.bib b/packages/preview/modern-usp-thesis/0.1.0/src/template/references.bib new file mode 100644 index 0000000000..768fea3ec8 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/template/references.bib @@ -0,0 +1,6 @@ +@article{typst, + title={Typst: A New Markup-Based Typesetting System}, + author={Typst Team}, + journal={Academic Publishing}, + year={2024} +} diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/usp-ime.csl b/packages/preview/modern-usp-thesis/0.1.0/src/usp-ime.csl new file mode 100644 index 0000000000..2182d5e403 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/usp-ime.csl @@ -0,0 +1,244 @@ + + diff --git a/packages/preview/modern-usp-thesis/0.1.0/src/usp-thesis.typ b/packages/preview/modern-usp-thesis/0.1.0/src/usp-thesis.typ new file mode 100644 index 0000000000..3ea83ead9f --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/src/usp-thesis.typ @@ -0,0 +1,384 @@ +#import "layout.typ": setup-layout, quote-long +#import "elements.typ": cover as cover-page, title-page as make-title-page, approval-sheet, abstract-page + +/// Main template function for USP theses and dissertations. +/// - title (content): The title of the thesis (in the main language). +/// - title-alt (content): The title in the secondary language (Mandatory for USP). +/// - subtitle (content): The subtitle of the thesis. +/// - author (string): The author's name. +/// - advisor (string): The advisor's name. +/// - coadvisor (string): The co-advisor's name. +/// - degree (string): The degree level ("Mestre" or "Doutor"), or a full title such as "Mestre em Engenharia". +/// - program (string): The graduate program name, e.g. "Estatística" (printed after "Programa: "). +/// - area (string): The concentration area. +/// - institute (string): The USP institute name. +/// - local (string): The city. +/// - year (string, int or auto): The year of deposit (auto: the current year). +/// - version (string): "Original" or "Corrigida". +/// - nature (string): Overrides the inferred "Dissertação" or "Tese". +/// - lang (string): Main document language ("pt" or "en"). +/// - font (string or array): The document font, or a list of fallbacks (default: "New Computer Modern"). +/// - cover (bool): Whether to print the cover. +/// - title-page (bool): Whether to print the title page. +/// - catalog-card (content): Optional ficha catalográfica (cataloging-in-publication +/// card), printed at the foot of the page after the title page (only with the +/// title page). Pass the card the +/// library provides, e.g. `image("ficha.png", width: 12.5cm)`. +/// - abstract-pt (content): The abstract in Portuguese (Mandatory). +/// - keywords-pt (array): List of keywords in Portuguese (Mandatory). +/// - abstract-en (content): The abstract in English (Mandatory). +/// - keywords-en (array): List of keywords in English (Mandatory). +/// - reference-pt (content): Bibliographic reference printed above the Portuguese +/// abstract (auto: built from author, Portuguese title, year, nature and institute; +/// none: omitted). +/// - reference-en (content): Same, above the English abstract, with the English title. +/// - dedication (content): Optional dedication. +/// - acknowledgments (content): Optional acknowledgments. +/// - epigraph (content): Optional epigraph. +/// - errata (content): Optional errata content. +/// - list-of-figures (bool or auto): Whether to include the list of figures (auto: show if >= 5). +/// - list-of-tables (bool or auto): Whether to include the list of tables (auto: show if >= 5). +/// - table-of-contents (bool): Whether to include the table of contents (Sumário). +/// - abbreviations (content): Optional list of abbreviations. +/// - symbols (content): Optional list of symbols. +/// - banca (array): List of jury member dictionaries ((nome: "", instituicao: "")). +/// - front-matter (bool): Whether to print the pre-textual elements (cover, title +/// page, abstracts, lists, table of contents...). With false only the body is +/// printed, in the same layout, numbered from page 1, whatever the other options. +/// - body (content): The document body. +#let usp-thesis( + title: [Título da Dissertação], + title-alt: none, + subtitle: none, + author: "Nome do Autor", + advisor: "Nome do Orientador", + coadvisor: none, + degree: "Mestre", + program: "Nome do Programa", + area: none, + institute: "Instituto de Matemática e Estatística", + local: "São Paulo", + year: auto, + version: "Original", + nature: none, + lang: "pt", + font: "New Computer Modern", + cover: true, + title-page: true, + catalog-card: none, + abstract-pt: none, + keywords-pt: (), + abstract-en: none, + keywords-en: (), + reference-pt: auto, + reference-en: auto, + dedication: none, + acknowledgments: none, + epigraph: none, + errata: none, + list-of-figures: auto, + list-of-tables: auto, + table-of-contents: true, + abbreviations: none, + symbols: none, + banca: (), + front-matter: true, + body, +) = { + // Set global language for hyphenation and built-in terms (e.g. outline title), + // and the font, before the cover so every page uses the same one. + set text(lang: lang, font: font) + + // Dictionary for custom localized strings + let i18n = ( + pt: ( + version: v => "Versão " + v, + advisor: "Orientador: ", + coadvisor: "Coorientador: ", + acknowledgments: "AGRADECIMENTOS", + nature-msc: "Dissertação", + nature-phd: "Tese", + errata: "ERRATA", + figures: "Lista de Ilustrações", + tables: "Lista de Tabelas", + abbreviations: "Lista de Abreviaturas e Siglas", + symbols: "Lista de Símbolos", + abstract-title: "RESUMO", + abstract-title-en: "ABSTRACT", + summary-title: "Sumário", + cover: "Capa", + chapter: "Capítulo", + keywords: "Palavras-chave: ", + area: "Área de Concentração: ", + title-msc: "Mestre em Ciências", + title-phd: "Doutor em Ciências", + labels: ( + author: "Autor", + title: "Título", + approved-on: "Aprovado em", + banca: "Banca Examinadora", + judgement: "Julgamento", + ), + ), + en: ( + version: v => v + " Version", + advisor: "Advisor: ", + coadvisor: "Co-advisor: ", + acknowledgments: "ACKNOWLEDGMENTS", + nature-msc: "Master's Dissertation", + nature-phd: "Doctoral Thesis", + errata: "ERRATA", + figures: "List of Figures", + tables: "List of Tables", + abbreviations: "List of Abbreviations and Acronyms", + symbols: "List of Symbols", + abstract-title: "RESUMO", + abstract-title-en: "ABSTRACT", + summary-title: "Contents", + cover: "Cover", + chapter: "Chapter", + keywords: "Keywords: ", + area: "Concentration Area: ", + title-msc: "Master of Science", + title-phd: "Doctor of Science", + labels: ( + author: "Author", + title: "Title", + approved-on: "Approved on", + banca: "Examination Committee", + judgement: "Judgement", + ), + ), + ).at(lang) + + // Infer nature and institute-specifics + // We check for "Mestre" or "Master" to identify Master's degrees + let is-msc = degree.contains(regex("Mestr|Master")) + let is-ime = institute.contains(regex("Matemática e Estatística|Mathematics and Statistics")) + + let actual-nature = if nature != none { nature } + else if is-msc { i18n.nature-msc } + else { i18n.nature-phd } + + // A bare degree level ("Mestre", "Doutor") gets the usual USP title + // ("Mestre em Ciências"); a full title ("Mestre em Engenharia") is kept as is. + let degree-title = if degree.contains(regex("\s(em|in|of)\s")) { degree } + else if is-msc { i18n.title-msc } + else { i18n.title-phd } + + let year = if year == auto { str(datetime.today().year()) } else { str(year) } + + let version-text = (i18n.version)(version) + + // Nature text, e.g. "Dissertação apresentada ao IME-USP para obtenção do + // título de Mestre em Ciências. Programa: Estatística" + let nature-text = if is-ime { + if lang == "pt" { + actual-nature + " apresentada ao IME-USP para obtenção do título de " + degree-title + ". Programa: " + program + } else { + actual-nature + " presented to IME-USP in order to obtain the title of " + degree-title + ". Program: " + program + } + } else { + if lang == "pt" { + let article = if institute.starts-with(regex("Escola|Faculdade")) { " apresentada à " } else { " apresentada ao " } + actual-nature + article + institute + " da Universidade de São Paulo para obtenção do título de " + degree-title + ". Programa: " + program + } else { + actual-nature + " presented to the " + institute + " of the University of São Paulo in order to obtain the title of " + degree-title + ". Program: " + program + } + } + + // Bibliographic reference printed above each abstract (ABNT NBR 6023): + // "SILVA, João da. *Título*: subtítulo. 2024. Dissertação (Mestrado) – ...". + // Each one carries the title in that abstract's language, so the secondary + // one comes from `title-alt`. + let author-entry = if type(author) == str and author.trim().contains(" ") { + let parts = author.trim().split(" ") + upper(parts.last()) + ", " + parts.slice(0, -1).join(" ") + } else { author } + let make-reference(ref-lang) = { + let is-main = ref-lang == lang + let ref-title = if is-main or title-alt == none { title } else { title-alt } + let ref-subtitle = if is-main and subtitle != none [: #subtitle] + let ref-nature = if ref-lang == "pt" { + if is-msc { "Dissertação (Mestrado)" } else { "Tese (Doutorado)" } + } else { + if is-msc { "Dissertation (Master's)" } else { "Thesis (Doctorate)" } + } + let university = if ref-lang == "pt" { "Universidade de São Paulo" } else { "University of São Paulo" } + [#author-entry. #strong(ref-title)#ref-subtitle. #year. #ref-nature -- #institute, #university, #local, #year.] + } + let reference-pt = if reference-pt == auto { make-reference("pt") } else { reference-pt } + let reference-en = if reference-en == auto { make-reference("en") } else { reference-en } + + // Without front matter only the body is printed, in the same layout. + if front-matter { + // 1. Cover + if cover { + // The cover has no heading: an invisible one gives it a PDF bookmark. + { + show heading: none + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.cover] + } + cover-page( + institution: if lang == "pt" { "Universidade de São Paulo\n" + institute } else { "University of São Paulo\n" + institute }, + author: author, + title: title, + subtitle: subtitle, + local: local, + year: year, + ) + + // Page numbering starts counting from title page (ABNT) + counter(page).update(1) + } + + // 2. Title Page + if title-page { + make-title-page( + author: author, + title: title, + subtitle: subtitle, + version: version-text, + nature: nature-text, + institute: institute, + degree: degree, + program: program, + area: area, + area-label: i18n.area, + advisor: i18n.advisor + advisor, + coadvisor: if coadvisor != none { i18n.coadvisor + coadvisor } else { none }, + local: local, + year: year, + ) + + // 2a. Catalog card (ficha catalográfica), on the page after the title page + if catalog-card != none { + page(margin: 3cm, { + v(1fr) + align(center, catalog-card) + }) + } + } + } + + // Setup layout for pre-textual elements (margins and heading styles) + show: setup-layout.with(lang: lang) + + if front-matter { + // Hide page numbering until Introduction + set page(numbering: none) + + // 3. Errata (Optional) + if errata != none { + heading(level: 1, numbering: none, outlined: false)[#i18n.errata] + v(1cm) + errata + pagebreak() + } + + // 4. Approval Sheet + if banca.len() > 0 { + approval-sheet( + author: author, + title: title, + subtitle: subtitle, + nature: nature-text, + banca: banca, + labels: i18n.labels, + ) + } + + // 5. Pre-textual elements + if dedication != none { + v(1fr) + align(right)[#box(width: 60%, dedication)] + pagebreak() + } + + if acknowledgments != none { + heading(level: 1, numbering: none, outlined: false)[#i18n.acknowledgments] + v(1cm) + acknowledgments + pagebreak() + } + + if epigraph != none { + v(1fr) + align(right)[#box(width: 60%, epigraph)] + pagebreak() + } + + if abstract-pt != none { + abstract-page( + i18n.abstract-title, + abstract-pt, + keywords-list: keywords-pt, + keywords-label: if lang == "pt" { i18n.keywords } else { "Palavras-chave: " }, + reference: reference-pt, + ) + } + + if abstract-en != none { + abstract-page( + i18n.abstract-title-en, + abstract-en, + keywords-list: keywords-en, + keywords-label: if lang == "en" { i18n.keywords } else { "Keywords: " }, + reference: reference-en, + ) + } + + // Lists (Conditional) + context { + let figures = query(figure.where(kind: image)) + let tables = query(figure.where(kind: table)) + + let show-figures = if list-of-figures == auto { figures.len() >= 5 } else { list-of-figures } + let show-tables = if list-of-tables == auto { tables.len() >= 5 } else { list-of-tables } + + if show-figures { + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.figures] + outline(title: none, target: figure.where(kind: image)) + pagebreak() + } + + if show-tables { + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.tables] + outline(title: none, target: figure.where(kind: table)) + pagebreak() + } + } + + if abbreviations != none { + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.abbreviations] + v(1cm) + abbreviations + pagebreak() + } + + if symbols != none { + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.symbols] + v(1cm) + symbols + pagebreak() + } + + // Table of Contents (Sumário) - Must be the last pre-textual element + if table-of-contents { + heading(level: 1, numbering: none, outlined: false, bookmarked: true)[#i18n.summary-title] + outline(title: none, indent: auto) + pagebreak() + } + } + + // --- Start of Textual Elements --- + + // Show page numbering from here + set page(numbering: "1", number-align: right + top) + + // Chapter (level-1) references print as "Chapter N"; `appendix` and `annex` + // override the supplement. + show heading.where(level: 1): set heading(supplement: i18n.chapter) + + body +} diff --git a/packages/preview/modern-usp-thesis/0.1.0/thumbnail.png b/packages/preview/modern-usp-thesis/0.1.0/thumbnail.png new file mode 100644 index 0000000000..af09c319d9 Binary files /dev/null and b/packages/preview/modern-usp-thesis/0.1.0/thumbnail.png differ diff --git a/packages/preview/modern-usp-thesis/0.1.0/typst.toml b/packages/preview/modern-usp-thesis/0.1.0/typst.toml new file mode 100644 index 0000000000..4f2eddd584 --- /dev/null +++ b/packages/preview/modern-usp-thesis/0.1.0/typst.toml @@ -0,0 +1,29 @@ +[package] +name = "modern-usp-thesis" +version = "0.1.0" +entrypoint = "src/lib.typ" +authors = ["Rubens Andrade <@andrader>"] +license = "MIT AND MIT-0 AND CC-BY-SA-3.0" +description = "Theses and dissertations at the University of São Paulo." +repository = "https://github.com/andrader/usp-thesis-typst-template" +keywords = [ + "academic", + "thesis", + "dissertation", + "brazil", + "usp", + "imeusp", + "University of São Paulo", + "Institute of Mathematics and Statistics", + "Universidade de São Paulo", + "Instituto de Matemática e Estatística", +] +categories = ["thesis", "paper"] +disciplines = ["mathematics", "computer-science", "engineering"] +compiler = "0.13.0" +exclude = ["/examples/", "/justfile"] + +[template] +path = "src/template" +entrypoint = "main.typ" +thumbnail = "thumbnail.png"