How to `show` an outline at each level 1 heading for all its child headings?

I am hoping to use a show rule to insert an outline at each level 1 heading, where these outlines only show the child headings of each level 1 heading. In other words (assuming no deeper heading levels than 2), for each level 1 heading there should be one outline which shows all the level 2 headings that occur before the next level 1 heading. The idea is like a section table of contents.

I’ve found something that works, but I’m worried I’m overcomplicating things. Is there an easier way to do this?

#set heading(numbering: "(1.1)")

#show heading.where(level:1): it => {
  it
  let future-level-1-headings = query(selector(heading.where(level:1)).after(here(), inclusive: false))
  let child-heading-selector = selector(heading.where(level:2)).after(here())
  outline(
    title:none, 
    target: if future-level-1-headings.len() > 0 {
      child-heading-selector.before(future-level-1-headings.at(0).location())
    } else {
      child-heading-selector
    }
  )
}

=
==
==
==
=
==
==
==
=
==
==
==

Here are some things I can see that would make this easier:

  1. a way to select children headers directly instead of between
  2. a location object like the one returned for here() except for the end of the document (would help simplify the if statement)
  3. a way to get the subsequent level one heading directly

Are any of these listed options possible in typst?

You can use a show rule for the outline entries that hides the sections from other chapters. I will leave the decision whether this is simpler than your current solution up to you. :slight_smile:

#show heading.where(level: 1): it => {
  it

  let heading-number = counter(heading).get().at(0)
  show outline.entry: it => {
    if counter(heading).at(it.element.location()).at(0) == heading-number { it }
  }

  outline(
    title: none, 
    target: heading.where(level: 2)
  )
}

I would also ask you to change the category of your post to Questions.

2 Likes

For future reference, an unmaintained package exists under the name “minitoc”, which uses the first approach (query heading in-between).

I find @janekfleper’s approach much more elegant though!

#import "@preview/suboutline:0.3.0": suboutline
#set heading(numbering: "1.1.")
#show heading.where(level: 1): it => it + suboutline()

= Heading
== Heading
#lorem(20)

=== Heading
#lorem(30)

== Heading
#lorem(10)

= Heading 2
== Heading
#lorem(20)

=== Heading
#lorem(30)

== Heading
#lorem(10)

3 Likes