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.

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)