Added object metadata & references

This commit is contained in:
Mark 2025-01-24 14:54:57 -08:00
parent f691a49630
commit a7e7f090f8
Signed by: Mark
GPG Key ID: C6D63995FE72FD80

View File

@ -151,34 +151,96 @@
// MARK: Sections // MARK: Sections
// //
#let generic(t) = block( /// Core render code for all objects (problems, theorems, etc)
/// This should never be used directly by client code.
///
/// Args:
/// - kind: the kind of object to make ("Problem", "Definition", etc)
/// - label_name: a string. If provided, generate metadata for this object
/// under the given label. Labels must be unique, and are prefixed with `obj`
/// This label can then be used to reference this object.
///
/// For example:
/// ```
/// #problem(label: "problem1")
/// This is @obj:problem1
/// ```
#let _obj_base(kind, ..args, label_name: none) = {
counter("obj").step()
let n = context counter("obj").get().first()
// The complete title text of this object,
// like "Problem 5:" or "Theorem: "
let obj_content = if args.pos().len() == 0 {
[#kind #n:]
} else {
[#kind #n: #args.pos().at(0)]
}
// Render the object
block(
above: 8mm, above: 8mm,
below: 2mm, below: 2mm,
text(weight: "bold", t), text(weight: "bold", obj_content),
)
#let _generic_base(kind, ..args) = {
counter("obj").step()
if args.pos().len() == 0 {
generic([
#kind
#context counter("obj").display():
])
} else {
generic(
[
#kind
#context counter("obj").display():
]
+ " "
+ args.pos().at(0),
) )
// Generate labeled metadata for this object.
//
// This can be viewed directly with `#context query(<label>).first().value`,
// Or referenced with `@label` (we define a custom renderer for this metadata later)
if label_name != none {
let label_name = "obj:" + label_name
let meta = (
"obj_meta_ref_kind": kind,
// "obj_content": obj_content,
"label": label(label_name),
"counter": counter("obj"),
)
[ #metadata(meta) #label(label_name) ]
} }
} }
#let problem(..args) = _generic_base("Problem", ..args) // `ref` implementation for object meta-references,
#let definition(..args) = _generic_base("Definition", ..args) // see `show: ref`.
#let theorem(..args) = _generic_base("Theorem", ..args) #let _ref_obj(it) = {
let magic_key = "obj_meta_ref_kind"
if not (
it.element != none
and it.element.has("value")
and type(it.element.value) == "dictionary"
and it.element.value.keys().contains(magic_key)
) {
// This label is not attached to object metadata
return none
}
let v = it.element.value
let obj_type = v.at(magic_key)
// The value of this object's counter at its label
let obj_count = v.counter.at(v.label).first()
// Produces text like "Problem 2",
// which takes you to the referenced object when clicked.
link(v.label, [#obj_type #obj_count])
}
/// Factory function for objects.
/// Provided for convenience, lets us define objects in one line.
#let _mkobj(kind) = {
let out(..args, label: none) = _obj_base(
kind,
..args,
label_name: label,
)
return out
}
#let problem = _mkobj("Problem")
#let definition = _mkobj("Definition")
#let theorem = _mkobj("Theorem")
// //
@ -272,6 +334,14 @@
] ]
} }
show ref: it => {
// Custom impl for object references
let x = _ref_obj(it)
if (x != none) { return x }
return it // Use default `ref` implementation
}
make_title( make_title(
group, group,
quarter, quarter,