Metadata

Metadata is invisible content that can be extracted using query or other content. This may be very useful with typst query to pass values to external tools.

// Put metadata somewhere.
#metadata("This is a note") <note>

// And find it from anywhere else.
#context {
  query(<note>).first().value
}
Rendered image

Endnote

In this section we will create an endnote function that works similarly to the built-in footnote function, except that it writes notes at endnote-list instead of at the bottom of the page.

If you need help understanding the final code, click here to read a tutorial.

We start with the most simple case: there is only one endnote-list across the whole document.

/// Add an endnote.
#let endnote(body) = {
  // Manage the endnote number, and display it in superscript.
  counter("endnote").step()
  context super(counter("endnote").display(""))
  // Note that only `counter.display` requires the context.
  // `counter.step` affects the context, but it requires nothing from the context.

  // Save the endnote body in a `metadata` for future use.
  [#metadata(body)<endnote>]
}

/// Write the list of endnotes.
#let endnote-list = {
  // Set up basic styles.
  [== Endnotes]
  set enum(numbering: "")
  set text(0.8em)

  // Here is the context-dependant part.
  context {
    // Find out what we have saved.
    let notes = query(<endnote>)
    // Display them in a numbered list (`enum`).
    for x in notes [
      + #x.value
    ]
  }
}

In this section we will create an `endnote` function#endnote[It works similarly to `footnote`.] that writes notes at `endnote-list`#endnote[Instead of at the bottom of the page.].

#endnote-list
Rendered image

Now we make it possible to use multiple endnote-lists. Basically the trick is to replace query(<endnote>) with query(selector(<endnote>).before(here()).after(last-list)).

/// Add an endnote.
#let endnote(body) = {
  counter("endnote").step()
  context super(counter("endnote").display(""))

  [#metadata(body)<endnote>]
}

/// Write the list of endnotes.
#let endnote-list = {
  [== Endnotes]
  set enum(numbering: "")
  set text(0.8em)


  context {
    // 👇 This is the main changed part.
    let note-selector = selector(<endnote>).before(here())
    let last-list = query(
      selector(<endnote-list>).before(here()),
    ).last(default: none)
    if last-list != none {
      note-selector = note-selector.after(last-list.location())
    }

    let notes = query(note-selector)
    for x in notes [
      + #x.value
    ]
  }

  // Prepare for the next list.
  [#metadata(none)<endnote-list>]
  counter("endnote").update(0)
}

In this section we will create an `endnote` function#endnote[It works similarly to `footnote`.] that writes notes at `endnote-list`#endnote[Instead of at the bottom of the page.].

#endnote-list

= Next chapter
Now we make it possible to use multiple `endnote-list`s#endnote[Get the trick?].

#endnote-list

Finally, we add links to the endnotes and lists, so that readers can click them to switch between the main text and the endnotes.

Final code:

/// Add an endnote.
#let endnote(body) = {
  counter("endnote").step()
  context {
    let (n,) = counter("endnote").get()
    let entry = query(
      selector(<endnote-entry>).after(here()),
    ).at(n - 1)

    // Link to the entry in `endnote-list`.
    link(
      entry.location(),
      super(counter("endnote").display("")),
    )
  }

  [#metadata(body)<endnote>]
}

/// Write the list of endnotes.
#let endnote-list = {
  [== Endnotes]
  set enum(numbering: "")
  set text(0.8em)

  context {
    let note-selector = selector(<endnote>).before(here())
    let last-list = query(
      selector(<endnote-list>).before(here()),
    ).last(default: none)
    if last-list != none {
      note-selector = note-selector.after(last-list.location())
    }

    let notes = query(note-selector)
    for x in notes [
      + #metadata(none)<endnote-entry>
        #x.value
        // Link back to `endnote`.
        #link(
          x.location(),
          text(0.8em, sym.arrow.t.curve),
        )
    ]
  }

  // Prepare for the next list.
  [#metadata(none)<endnote-list>]
  counter("endnote").update(0)
}

In this section we will create an `endnote` function#endnote[It works similarly to `footnote`.] that writes notes at `endnote-list`#endnote[Instead of at the bottom of the page.].

#endnote-list

= Next chapter
Now we make it possible to use multiple `endnote-list`s#endnote[Get the trick?].

#endnote-list