Refactor handout.typ
#7
@ -151,34 +151,96 @@
|
||||
// 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,
|
||||
below: 2mm,
|
||||
text(weight: "bold", t),
|
||||
)
|
||||
|
||||
#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),
|
||||
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 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)
|
||||
#let definition(..args) = _generic_base("Definition", ..args)
|
||||
#let theorem(..args) = _generic_base("Theorem", ..args)
|
||||
// `ref` implementation for object meta-references,
|
||||
// see `show: ref`.
|
||||
#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(
|
||||
group,
|
||||
quarter,
|
||||
|
Loading…
x
Reference in New Issue
Block a user