How to create an outline where certain entries do not linebreak?

I would like to create an outline like this:

I tried the following:

#set text(size: 12pt)
#set heading(numbering: "1.")
#show outline.entry.where(level: 1): set text(size: 1.5em, weight: "bold")
#show outline.entry.where(level: 1): set block(above: 6mm, below: 4mm)
#show outline.entry.where(level: 2): it => box(
  link(
    it.location(),
    [#it.prefix() #it.body() (#it.page()). #h(2mm)]
  )
)

#outline(title: none)

= #lorem(5)
== #lorem(4)
== #lorem(3)
== #lorem(10)
== #lorem(1)

= #lorem(2)
== #lorem(2)
== #lorem(2)
== #lorem(3)
== #lorem(6)

Ok. But I have (at least) two problems:

  • The indentation is broken.
  • The words do not wrap.

Please help me. I have no idea what I am doing.

There is an open issue, https://github.com/typst/typst/issues/6965 that requests run-in lists for footnotes and points out that such run-in lists are valuable elsewhere.

Your outline issue is exactly the problem I had in mind when I commented there.

2 Likes

Thanks for the link, I had not seen that. It would be a nice feature addition. In the mean time, I cobbled together the following ‘solution’.

#set text(size: 12pt)
#set page(numbering: "1")
#set heading(numbering: "1.A")

#context {
  let section_mapper(section) = {
    let section_location = section.location()
    let section_num = numbering(
      heading.numbering,
      ..counter(heading).at(section_location)
    )
    let section_page = numbering(
      section_location.page-numbering(),
      ..counter(page).at(section_location),
    )
    return link(
      section_location,
      [#section_num #section.body (#section_page).] + h(0.5em)
    )
  }
  
  let chapters = query(heading.where(level: 1))
  let sections = query(heading.where(level: 2))
  
  for (i, chapter) in chapters.enumerate(start: 1) {
    let chapter_location = chapter.location()
    let chapter_num = numbering(
      heading.numbering,
      ..counter(heading).at(chapter_location)
    )
    let chapter_page = numbering(
      chapter_location.page-numbering(),
      ..counter(page).at(chapter_location),
    )
    let chapter_sections = sections.filter(section => counter(heading).at(section.location()).at(0) == i)
    let chapter_sections_body = chapter_sections.map(section_mapper).join()
    
    block(above: 6mm, below: 4mm,
      link(
        chapter_location,
        text(
          size: 1.5em,
          weight: "bold",
          [#chapter_num] + h(0.4em) + chapter.body + h(0.2em) + box(
            width: 1fr, repeat(gap: 0.15em, [.])
          ) + h(0.2em) + chapter_page
        )
      ) + align(
        right,
        block(
          width: 96%,
          above: 5mm,
          align(left, par(justify: true, chapter_sections_body))
        )
      )
    )
  }
}

#pagebreak()

= The first chapter
== First chapter, first section
#pagebreak()
== First chapter, second section
#pagebreak()
== First chapter, third section
#pagebreak()
== First chapter, fourth section
#pagebreak()
= The second chapter
== Second chapter, first section
#pagebreak()
== Second chapter, second section
#pagebreak()
== Second chapter, third section
#pagebreak()
== Second chapter, fourth section

It does the job, but I am not much of a software scientist. Maybe someone can clean up my terrible code.

1 Like

Much too overthought! Try something built on this:

#set page(numbering: "1")
#set heading(numbering: "1.A")

#{
    set outline(
      title: [Table of contents],
      depth: 2,
    )
    set par(hanging-indent: 1em)
    show outline.entry.where(level: 1): it => {
      v(0.5em)
      it
      v(-0.5em)
    }
    show outline.entry.where(level: 2): it => {
      h(1em)
      it.prefix() + sym.space.nobreak
      it.body() + sym.space.nobreak
      "(" + it.page() + ") "
    }
    outline()
}


= The first chapter
== First chapter, first section
#pagebreak()
== First chapter, second section
#pagebreak()
== First chapter, third section
#pagebreak()
== First chapter, fourth section
#pagebreak()
= The second chapter
== Second chapter, first section
#pagebreak()
== Second chapter, second section
#pagebreak()
== Second chapter, third section
#pagebreak()
== Second chapter, fourth section

to get:

There is still no way that I have found to set the width of the list – it should not go to the right margin as it can here.

1 Like