andreasKroepelin / polylux

A package for creating slides in Typst
https://polylux.dev/book
MIT License
1.17k stars 54 forks source link

Variable section depth #182

Open TiemenSch opened 2 months ago

TiemenSch commented 2 months ago

As proposed in #160, I created this issue to discuss the handling of variable depth sections.

The main challenge resides in the bookkeeping. In it's simplest form this would just be an array of entries.

For the Ratio theme I currently use the array approach, with the additions that section ends are also calculated (rather forcefully). https://gitlab.com/ratio-case-os/typst/polylux-ratio/-/blob/main/src/sections.typ

/// Sections state variable that tracks the first reveal of any section.
#let ratio-sections = state("ratio-sections", ())

/// Register a new section.
#let register-section(level: 1, body) = locate(loc => {
  ratio-sections.update(s => {
    let new = ()
    for sec in s {
      if sec.end == none and level <= sec.level {
        sec.end = loc
      }
      new.push(sec)
    }
    new.push((body: body, level: level, start: loc, end: none))
    new
  })
})

/// Get the current section, regardless of level.
#let current-section = locate(loc => {
  let sections = ratio-sections.at(loc)
  sections.last()
})

/// Get the current section of a given level. Returns the last seen section of that kind,
/// or any higher up section if that was more recently seen.
#let current-section-of(level: 1) = locate(loc => {
  let sections = ratio-sections.at(loc)
  for sec in sections.rev() {
    if sec.level <= level {
      return sec
    }
  }
  none
})

To register headings on the fly I then use

// Heading setup.
#show heading: it => (
  context {
    let settings = ratio-settings.get()

    // Register sections and subsections.
    let register = settings.heading-registration-level
    let first-subslide = logic.subslide.get().first() == 1
    if settings.heading-registration-level != none and first-subslide and it.level <= register {
      register-section(it.body, level: it.level)
    }
    it
  }
)

Although I would love to only register them on their first "uncover" instead of the first subslide where they might still be hidden, but that is another matter.

TiemenSch commented 2 months ago

I would love for all/most themes to use the same machinery for this, such that it behaves more predictable for users.