diff --git a/packages/preview/progressive-layout/1.0.0/.gitignore b/packages/preview/progressive-layout/1.0.0/.gitignore new file mode 100644 index 0000000000..938fec3a5b --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +*.pdf diff --git a/packages/preview/progressive-layout/1.0.0/LICENSE b/packages/preview/progressive-layout/1.0.0/LICENSE new file mode 100644 index 0000000000..cff6e2e288 --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 David Hajage + +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/progressive-layout/1.0.0/README.md b/packages/preview/progressive-layout/1.0.0/README.md new file mode 100644 index 0000000000..bb79041786 --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/README.md @@ -0,0 +1,68 @@ +# progressive-outline + +This package provides a Typst function, `progressive-outline`, to generate a dynamic table of contents, similar to what is found in some LaTeX's Beamer presentations. + +## Context and Ultimate Goal + +This function was developed to meet a need within the Typst community for displaying partial or progressive outlines, especially in presentations. It is inspired by the following discussions: + +- [GitHub Issue (touying)](https://github.com/touying-typ/touying/issues/137) +- [Typst Forum](https://forum.typst.app/t/how-to-display-partial-outlines-with-touying/5526) + +The ultimate goal would be to integrate this functionality directly into a presentation package like **[`polylux`](https://typst.app/universe/package/polylux/)**, **[`touying`](https://typst.app/universe/package/touying/)**, or **[`presentate`](https://typst.app/universe/package/presentate/)**. This would allow for the creation of "Beamer-like" presentations where the outline unfolds flexibly as you progress through the slides. Feel free to draw inspiration from this code to contribute to these projects! + +## Function Usage + +To use the function, import the package and call `progressive-outline` where you want the outline to appear. + +```typst +#import "@preview/progressive-layout:1.0.0": progressive-outline + +#progressive-outline( + h1-style: "all", + h2-style: "current-and-grayed", + h3-style: "current", + show-numbering: true, +) +``` + +## Example: The `progressive-layout` Template + +This package also contains a simple template, `progressive-layout`, which shows an example of how to use the function. Here is a minimal code example to test it: + +```typst +// Import the template +#import "@preview/progressive-layout:1.0.0": progressive-layout, progressive-outline + +// Apply the template to your document +#show: doc => progressive-layout(doc) + +// Your headings... += Chapter 1 +== Section 1.1 += Chapter 2 +``` + +## Examples + +This package includes two files to demonstrate its usage: + +- [`example.typ`](https://github.com/eusebe/progressive-layout/blob/main/example.typ): This file shows how the `progressive-outline` function works with different options. +- [`demo.typ`](https://github.com/eusebe/progressive-layout/blob/main/demo.typ): This file provides an example of how to use the `progressive-layout` template. + +## `progressive-outline` Parameters + +| Parameter | Description | Options | Default | +| :--- | :--- | :--- | :--- | +| `h1-style` | Controls the display of level 1 headings. | `"all"`, `"current"`, `"current-and-grayed"`, `"none"` | `"all"` | +| `h2-style` | Controls the display of level 2 headings. | `"all"`, `"current"`, `"current-and-grayed"`, `"none"` | `"all"` | +| `h3-style` | Controls the display of level 3 headings. | `"all"`, `"current"`, `"current-and-grayed"`, `"none"` | `"all"` | +| `scope-h2` | Restricts the display of level 2 headings. | `"all"`, `"current-h1"` | `"current-h1"` | +| `scope-h3` | Restricts the display of level 3 headings. | `"all"`, `"current-h2"` | `"current-h2"` | +| `show-numbering` | Shows or hides the numbering of headings. | `true`, `false` | `true` | + +--- + +## Note on Code Generation + +This package was initially generated with the help of a Large Language Model (LLM). It is a demonstration of what I would like to see one day included in a typst package dedicated to creating presentations, but I am unable to integrate such a feature into the packages I mentioned above in the readme. While functional, it may contain errors, inefficiencies, or programming practices that could be improved. Please use it with discretion and feel free to suggest improvements! diff --git a/packages/preview/progressive-layout/1.0.0/demo.typ b/packages/preview/progressive-layout/1.0.0/demo.typ new file mode 100644 index 0000000000..ef00ce66f4 --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/demo.typ @@ -0,0 +1,42 @@ +// Import the layout function from the local template +#import "@preview/progressive-layout:1.0.0": progressive-layout, progressive-outline +// #import "lib.typ": progressive-layout, progressive-outline + +// Apply the layout to the entire document +#show: doc => progressive-layout(doc, show-numbering: true) + += First Section : General Introduction + +== Project Context + +#lorem(20) + +== Objectives + +#lorem(20) + += Second Section : Detailed Analysis + +== Analysis of User's Need + +#lorem(20) + +== Proposed Solutions + +=== Solution A + +#lorem(20) + +=== Solution B + +#lorem(20) + += Third Section : Conclusion + +== Appraisal + +#lorem(20) + +== Perspectives + +#lorem(20) diff --git a/packages/preview/progressive-layout/1.0.0/example.typ b/packages/preview/progressive-layout/1.0.0/example.typ new file mode 100644 index 0000000000..fd184bbdbf --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/example.typ @@ -0,0 +1,95 @@ +#import "@preview/progressive-layout:1.0.0": progressive-outline +// #import "lib.typ": progressive-outline + +#progressive-outline( + h1-style: "all", + h2-style: "all", + h3-style: "all", + show-numbering: false +) + += Title 1 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +#progressive-outline( + h1-style: "current-and-grayed", + h2-style: "none", + h3-style: "none", + show-numbering: false +) + +== Subtitle 1.1 + +Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +#progressive-outline( + h1-style: "none", + h2-style: "current-and-grayed", + h3-style: "none", + show-numbering: false +) + +=== Sub-subtitle 1.1.1 + +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +#progressive-outline( + h1-style: "none", + h2-style: "none", + h3-style: "current-and-grayed", + show-numbering: false +) + +=== Sub-subtitle 1.1.2 + +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + +#progressive-outline( + h1-style: "none", + h2-style: "current", + h3-style: "current-and-grayed", + show-numbering: false +) + +== Subtitle 1.2 + +Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + += Title 2 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +#progressive-outline( + h1-style: "current-and-grayed", + h2-style: "none", + h3-style: "none", + show-numbering: false +) + +== Subtitle 2.1 + +Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +#progressive-outline( + h1-style: "current", + h2-style: "current-and-grayed", + h3-style: "none", + show-numbering: false +) + +== Subtitle 2.2 + +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + += Title 3 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +== Subtitle 3.1 + +Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +== Subtitle 3.2 + +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. diff --git a/packages/preview/progressive-layout/1.0.0/lib.typ b/packages/preview/progressive-layout/1.0.0/lib.typ new file mode 100644 index 0000000000..0baa4f5f3c --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/lib.typ @@ -0,0 +1,138 @@ +#let progressive-outline( + h1-style: "all", + h2-style: "all", + h3-style: "all", + scope-h2: "current-h1", + scope-h3: "current-h2", + show-numbering: true, +) = { + context { + let loc = here() + let all-headings = query(heading.where(outlined: true)) + + let is-before(loc1, loc2) = { + if loc1.page() < loc2.page() { + return true + } + if loc1.page() == loc2.page() and loc1.position().y < loc2.position().y { + return true + } + return false + } + + let current-h1 = if query(heading.where(outlined: true, level: 1).before(loc)).len() > 0 { + query(heading.where(outlined: true, level: 1).before(loc)).last() + } else { none } + + let current-h2 = if query(heading.where(outlined: true, level: 2).before(loc)).len() > 0 { + query(heading.where(outlined: true, level: 2).before(loc)).last() + } else { none } + + let current-h3 = if query(heading.where(outlined: true, level: 3).before(loc)).len() > 0 { + query(heading.where(outlined: true, level: 3).before(loc)).last() + } else { none } + + let style-heading(heading, style, current) = { + let content = if show-numbering { + numbering("1.1.1", ..counter(heading.func()).at(heading.location())) + " " + heading.body + } else { + heading.body + } + if style == "all" { + return content + } else if style == "current" { + if heading == current { + return content + } else { + return none + } + } else if style == "current-and-grayed" { + if heading == current { + return content + } else { + return text(fill: gray, content) + } + } else if style == "none" { + return none + } else { + return content + } + } + + for heading in all-headings { + let styled-heading = if heading.level == 1 { + style-heading(heading, h1-style, current-h1) + } else if heading.level == 2 { + if scope-h2 == "current-h1" and current-h1 != none { + let parent-h1 = all-headings.rev().find(h => h.level == 1 and is-before(h.location(), heading.location())) + if parent-h1 != current-h1 { + continue + } + } + style-heading(heading, h2-style, current-h2) + } else if heading.level == 3 { + if scope-h3 == "current-h2" and current-h2 != none { + let parent-h2 = all-headings.rev().find(h => h.level == 2 and is-before(h.location(), heading.location())) + if parent-h2 != current-h2 { + continue + } + } + style-heading(heading, h3-style, current-h3) + } else { + heading.body + } + + if styled-heading != none { + let indent = 2em * (heading.level - 1) + block(pad(left: indent, styled-heading)) + } + } + } +} + +/// Applies dynamic layout with outlines. +#let progressive-layout(doc, show-numbering: true) = { + // --- Base styles --- + set text(font: "Arial", size: 22pt) + set page( + paper: "presentation-16-9", + margin: (top: 2cm, bottom: 2cm, x: 2cm), + ) + set heading(numbering: "1.1.1") + + // --- Display logic --- + + // At the beginning of the document, display the full table of contents. + outline() + + // For each level 1 heading, display the list of level 2 sub-sections. + show heading.where(level: 1): it => { + pagebreak(weak: true) // Each section 1 starts on a new page + // Display the progressive outline for the current H1, without the heading text itself. + set text(size: 22pt) // Homogenize font size for the outline + progressive-outline(h1-style: "current", h2-style: "all", h3-style: "none", show-numbering: show-numbering) + pagebreak(weak: true) // Start the actual content on a new page + } + + // For each level 2 heading, display the list of *all* H2s, + // with the current H2 highlighted. + show heading.where(level: 2): it => { + pagebreak(weak: true) // Each H2 starts on a new page + // Display the progressive outline for the current H2, without the heading text itself. + set text(size: 22pt) // Homogenize font size for the outline + progressive-outline(h1-style: "current", h2-style: "current-and-grayed", h3-style: "none", show-numbering: show-numbering) + pagebreak(weak: true) // Start the actual content on a new page + } + // For each level 3 heading, display the list of *all* H3s, + // with the current H3 highlighted. + show heading.where(level: 3): it => { + pagebreak(weak: true) // Each H3 starts on a new page + // Display the progressive outline for the current H3, without the heading text itself. + set text(size: 22pt) // Homogenize font size for the outline + progressive-outline(h1-style: "current", h2-style: "current-and-grayed", h3-style: "current-and-grayed", show-numbering: show-numbering) + pagebreak(weak: true) // Start the actual content on a new page + } + + // --- Document content --- + doc +} \ No newline at end of file diff --git a/packages/preview/progressive-layout/1.0.0/typst.toml b/packages/preview/progressive-layout/1.0.0/typst.toml new file mode 100644 index 0000000000..75790585f7 --- /dev/null +++ b/packages/preview/progressive-layout/1.0.0/typst.toml @@ -0,0 +1,12 @@ +[package] +name = "progressive-layout" +version = "1.0.0" +entrypoint = "lib.typ" +authors = ["David Hajage "] +description = "A Typst function to display a dynamic table of contents, inspired by LaTeX's Beamer class." +license = "MIT" +keywords = ["outline", "table of contents", "presentation", "dynamic"] +compiler = "0.11.0" +exclude = ["example.typ", "demo.typ"] +repository = "https://github.com/eusebe/progressive-layout" +