/// 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") #let generic(obj_content) = { block( above: 8mm, below: 2mm, text(weight: "bold", obj_content), ) }