Reviewed-on: #7 Co-authored-by: Mark <mark@betalupi.com> Co-committed-by: Mark <mark@betalupi.com>
101 lines
2.6 KiB
Typst
101 lines
2.6 KiB
Typst
|
|
/// 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")
|