How to make appendix optional in template, and how to hide it from "main" contents?

I’m working on a template that for illustration I’ve reduced to the following:

#let conf(
  title: none,
  doc,
) = {
  set heading(numbering: (..nums) => nums.pos().map(str).join("."))
  v(15%, weak: false)
  align(center, text(17pt, weight: "bold", title))

  pagebreak()

  set page(numbering: "1")

  show outline.entry.where(
    level: 1
  ): it => {
    v(12pt, weak: true)
    strong(it)
  }

  outline(indent: auto)

  pagebreak()
  outline(target: heading.where(supplement: [Appendix]), title: [Appendix])

  pagebreak()

  doc
}

#let appendix(body) = {
  counter(heading).update(0)

  set heading(
    numbering: "A",
    supplement: [Appendix]
  );

  body
}

#show: doc => conf(
  title: "Lorem",
  doc
)

= About
#lorem(16)

== References
#lorem(32)

= Introduction
#lorem(16)

#show: appendix

= Tables
#lorem(16)

= Graphs
#lorem(16)

I have two questions:

  1. How can I make the appendix outline generation dependent on whether the document contains #show: appendix? I.e. if document doesn’t contain an #show appendix, it shouldn’t generate the appendix’es outline or the pagebreak related to it.
  2. How do I hide the appendix’es headings from the regular Contents outline?

One way to easily detect whether the #show: appendix rule has been applied is to make the appendix function insert metadata into the document, which you can then query . Note that queries should be inside contextual blocks. Finally, you can use conditionals to choose what should be displayed.

Something like this:

#let conf(
  title: none,
  doc,
) = {
  // stuff here

  context {
    if query(metadata.where(value: "appendix")).len() == 0 {
      outline(indent: auto)
    }
    else {
      let appendix-pos = query(metadata.where(value: "appendix")).first().location()
      
      outline(
        indent: auto,
        target: selector(heading).before(appendix-pos)
      )
      pagebreak()
      outline(
        target: heading.where(supplement: [Appendix]), 
        title: [Appendix]
      )
    }
  }

  pagebreak()

  doc
}

#let appendix(body) = {
  // stuff here

  metadata("appendix")

  body
}

4 Likes

Hello. Here is an optimized version for your code + solution:

#let conf(title: none, doc) = {
  set heading(numbering: "1.1")
  set pagebreak(weak: true)

  v(15%)
  align(center, text(17pt, strong(title)))
  pagebreak()

  set page(numbering: "1")
  show outline.entry.where(level: 1): set block(above: 12pt)
  show outline.entry.where(level: 1): strong

  context if query(<appendix-exists>).len() == 0 { outline() } else {
    outline(target: selector(heading).before(locate(<appendix-exists>)))
    pagebreak()

    outline(title: [Appendix], target: heading.where(supplement: [Appendix]))
  }
  pagebreak()

  doc
}

#let appendix(body) = {
  set heading(numbering: "A", supplement: [Appendix])
  counter(heading).update(0)
  [#metadata(none)<appendix-exists>]
  body
}

#show: conf.with(title: "Lorem")

= About
#lorem(16)

== References
#lorem(32)

= Introduction
#lorem(16)

#show: appendix

= Tables
#lorem(16)

= Graphs
#lorem(16)
1 Like