101 lines
2.6 KiB
Typst
Raw Normal View History

/// This module defines all handout "objects"
/// (problems, theorems, definitions, etc)
/// 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.
/// This label can then be used to reference this object.
///
/// For example:
/// ```
/// #problem(label: "problem1")
/// This is @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,
below: 2mm,
text(weight: "bold", obj_content),
)
// 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 meta = (
"obj_meta_ref_kind": kind,
// "obj_content": obj_content,
"label": label(label_name),
"counter": counter("obj"),
)
[ #metadata(meta) #label(label_name) ]
}
}
// `ref` implementation for object meta-references.
// Returns `none` if `it` is not object metadata.
#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.
return 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
}
//
// MARK: export
//
// Functions for client code are defined below
#let problem = _mkobj("Problem")
#let definition = _mkobj("Definition")
#let theorem = _mkobj("Theorem")
#let example = _mkobj("Example")
#let remark = _mkobj("Remark")