123 lines
No EOL
3.4 KiB
Typst
123 lines
No EOL
3.4 KiB
Typst
// Glossary code by Hugo Cartigny (BlueskyFR) 🍉
|
|
|
|
#let glossary(indent-defs: false, doc) = {
|
|
// ✨ The glossary displays its items using level 99 headings
|
|
let glossary = state("wow", (:))
|
|
|
|
// Hide the numbering for level 99 titles
|
|
show heading.where(level: 99): it => text(weight: "regular", it.body)
|
|
|
|
let page-refs-color = rgb("#7630EA")
|
|
|
|
show terms: list => {
|
|
let terms-grid = ()
|
|
// Add terms to glossary
|
|
for item in list.children {
|
|
glossary.update(v => {
|
|
v.insert(
|
|
item.term.text,
|
|
(
|
|
// Holds the list of the locations referencing the term
|
|
ref-locs: (),
|
|
// The actual term definition
|
|
def: item.description,
|
|
)
|
|
)
|
|
|
|
// Return the new state with the added entry
|
|
v
|
|
})
|
|
|
|
if indent-defs {
|
|
// Term
|
|
terms-grid.push([
|
|
#heading(level: 99, numbering: "1")[*#item.term*]
|
|
#label(item.term.text)
|
|
])
|
|
|
|
// Definition
|
|
terms-grid.push([
|
|
#item.description
|
|
// Pages where the term is referenced
|
|
#show: text.with(page-refs-color)
|
|
#locate(loc => {
|
|
glossary.final(loc).at(item.term.text).ref-locs
|
|
.map(l => link(l, str(l.page)))
|
|
.join(", ")
|
|
})
|
|
])
|
|
|
|
} else [
|
|
// Display items directly one by one since
|
|
// we don't need to build a grid
|
|
|
|
// Use a level 99 title so it doesn't conflict with regular ones
|
|
// and it can be refered to by @citations
|
|
#heading(level: 99, numbering: "1")[
|
|
*#item.term*:~~#item.description
|
|
// Pages where the term is referenced
|
|
#show: text.with(page-refs-color)
|
|
#locate(loc => {
|
|
glossary.final(loc).at(item.term.text).ref-locs
|
|
.map(l => link(l, str(l.page)))
|
|
.join(", ")
|
|
})
|
|
]
|
|
#label(item.term.text) \
|
|
]
|
|
}
|
|
|
|
if indent-defs {
|
|
grid(
|
|
columns: (1fr, 4fr),
|
|
column-gutter: 2mm,
|
|
row-gutter: 8mm,
|
|
..terms-grid
|
|
)
|
|
}
|
|
|
|
// 🐛 Debug
|
|
//glossary.display()
|
|
}
|
|
|
|
show ref: r => {
|
|
locate(loc => {
|
|
// Search for the source of the ref
|
|
let term = str(r.target)
|
|
let res = query(r.target, loc)
|
|
|
|
// If the source exists and is the glossary (heading level 99)
|
|
if res.len() > 0 and res.first().level == 99 {
|
|
let entry = glossary.at(loc).at(term)
|
|
|
|
// Replace term by the user-specified supplement if not none
|
|
let custom-term = {
|
|
if r.citation.supplement != none { r.citation.supplement }
|
|
else { term }
|
|
}
|
|
|
|
// If it is the first reference to the term, display its definition too
|
|
link(res.first().location(), {
|
|
if entry.ref-locs.len() == 0 [*#entry.def* (#custom-term)]
|
|
else [#custom-term]
|
|
})
|
|
|
|
// Add location to the term's ref list if the current page
|
|
// is not already listed
|
|
glossary.update(v => {
|
|
// If this page is not in, push the loc in!
|
|
if v.at(term).ref-locs.all(l => l.page != loc.page()) {
|
|
v.at(term).ref-locs.push(
|
|
// Current page loc
|
|
loc.position()
|
|
)
|
|
}
|
|
v
|
|
})
|
|
}
|
|
else { r } // Otherwise just return the ref as it is
|
|
})
|
|
}
|
|
|
|
doc
|
|
} |