Refactor handout.typ
			#7
		
		
	| @ -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, | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user