Have extended this to match the format and behavior of regular footnotes more closely, and called it “local footnotes”:
GitHub Gist
Code (possibly outdated, compared to Gist)
#let _local-footnotes-state = state("local-footnotes", (
numbering-format: "a",
notes: (),
))
/// (internal) unique ID per group of local footnotes
#let _local-footnotes-counter = counter("local-footnotes")
/// Changes the setup for local footnotes
#let local-footnotes-setup(numbering-format: "a") = {
context {
if _local-footnotes-state.get().notes.len() > 0 {
panic("cannot change local-footnotes-setup when there are not yet shown footnotes")
}
}
_local-footnotes-state.update(s => {
s.numbering-format = numbering-format
s
})
}
/// (internal) Creates labels for linking from ref to note and vice versa
#let _local-footnotes-labels(footnotes-group-id, index) = {
(
ref: label("_local-footnotes-ref-" + str(footnotes-group-id) + "-" + str(index)),
note: label("_local-footnotes-note-" + str(footnotes-group-id) + "-" + str(index)),
)
}
#let _local-footnotes-format(notes) = {
set text(size: 0.9em)
parbreak()
// Indent notes, similar to what `footnote` does
pad(left: 1em, notes)
parbreak()
v(1em)
}
/// Shows the local footnotes which have been added so far, and resets the list of footnotes.
/// The `format` parameter can be used to overwrite the default formatting of the footnotes.
#let local-footnotes-show(format: _local-footnotes-format) = context {
let local-footnotes-state = _local-footnotes-state.get()
let footnotes = local-footnotes-state.notes
if footnotes.len() == 0 {
panic("no footnotes to show")
}
local-footnotes-state.notes = ()
_local-footnotes-state.update(local-footnotes-state)
_local-footnotes-counter.step()
let footnotes-group-id = _local-footnotes-counter.get().at(0)
let numbering-format = local-footnotes-state.numbering-format
format({
let footnotes-entries = ()
for (i, note) in footnotes.enumerate() {
let number = i + 1
let formatted-number = numbering(numbering-format, number)
let labels = _local-footnotes-labels(footnotes-group-id, number)
// First add the footnote number
footnotes-entries.push([
// Set link color to regular text color, but only for this link, not for links in note text
#show link: set text(fill: text.fill)
#link(labels.ref, [#super(formatted-number)])#labels.note
])
// Then add the corresponding footnote text
footnotes-entries.push(align(left, note))
}
grid(columns: (auto, 1fr), column-gutter: 0.2em, row-gutter: 0.7em, ..footnotes-entries)
})
}
/// Creates a local footnote with the given text.
/// Can provide more than one note, to separate the footnote references with a comma.
#let local-footnote(note, ..additional-notes) = {
// Similar to regular `footnote` support placing a label on a local footnote
// and then referring to that again at a later point
let is-label = type(note) == label
if not is-label {
_local-footnotes-state.update(s => {
s.notes.push(note)
s
})
}
context {
let local-footnotes-state = if is-label {
// TODO: This implementation might be rather error-prone because it also 'works'
// for labels not attached to local footnotes (?)
_local-footnotes-state.at(note)
} else { _local-footnotes-state.get() }
let number = local-footnotes-state.notes.len()
if is-label {
// Apparently at the position of the label the state has not been updated yet (?),
// therefore increase the number
// TODO: This is rather brittle, it only works because the referenced note itself, which
// is not accessible here due to the state not having been updated, is not necessary
// when referencing an existing footnote
number += 1
}
let formatted-number = numbering(local-footnotes-state.numbering-format, number)
let footnotes-group-id = _local-footnotes-counter.get().at(0)
let labels = _local-footnotes-labels(footnotes-group-id, number)
let color = text.fill
show link: set text(fill: color)
// Only add label if this is not itself a label referring to an existing footnote
let ref-label = if not is-label { labels.ref }
// Use `weak: true` to collapse space, similar to built-in `footnote`
[#h(0.1em, weak: true)#link(labels.note, super(formatted-number))#ref-label]
}
for note in additional-notes.pos() {
super(",")
local-footnote(note)
}
}
It basically tries to recreate / mimic built-in footnotes, without actually using (or being able to use) any of the built-in footnote functionality.
Seems to work ok, but maybe there are better ways to implement this (see also the TODOs in the code).
Here is an example:
#local-footnotes-setup(numbering-format: "1)")
#figure(caption: [Table with footnotes], {
table(
columns: 2,
table.header[*Number*][*Word*],
[1], [one #local-footnote[the number 1]<fn:number-one>],
[2], [two #local-footnote[the number 2]],
[1], [one #local-footnote(<fn:number-one>)],
)
align(left, line())
local-footnotes-show()
})
Rendered: