Refactor handout.typ
			#7
		
		
	| @ -1,361 +0,0 @@ | |||||||
| /// Typst handout library, used for all documents in this repository. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// If false, hide instructor info. |  | ||||||
| /// |  | ||||||
| /// Compile with the following command to hide solutions: |  | ||||||
| /// `typst compile main.typ --input show_solutions=false` |  | ||||||
| /// |  | ||||||
| /// Solutions are shown by default. This behavior |  | ||||||
| /// is less surprising than hiding content by default. |  | ||||||
| #let show_solutions = { |  | ||||||
|   if "show_solutions" in sys.inputs { |  | ||||||
|     // Show solutions unless they're explicitly disabled |  | ||||||
|     not ( |  | ||||||
|       sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" |  | ||||||
|     ) |  | ||||||
|   } else { |  | ||||||
|     // Show solutions by default |  | ||||||
|     true |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Colors |  | ||||||
| #let ored = rgb("D62121") |  | ||||||
| #let oorange = rgb("#ffaa3b") |  | ||||||
| #let ogrape = rgb("9C36B5") |  | ||||||
| #let ocyan = rgb("2288BF") |  | ||||||
| #let oteal = rgb("12B886") |  | ||||||
| #let ogreen = rgb("37B26D") |  | ||||||
| #let oblue = rgb("1C7ED6") |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // MARK: header |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #let make_title( |  | ||||||
|   group, |  | ||||||
|   quarter, |  | ||||||
|   title, |  | ||||||
|   subtitle, |  | ||||||
| ) = { |  | ||||||
|   align( |  | ||||||
|     center, |  | ||||||
|     block( |  | ||||||
|       width: 60%, |  | ||||||
|       height: auto, |  | ||||||
|       breakable: false, |  | ||||||
|       align( |  | ||||||
|         center, |  | ||||||
|         stack( |  | ||||||
|           spacing: 7pt, |  | ||||||
|           ( |  | ||||||
|             text(size: 10pt, group) + h(1fr) + text(size: 10pt, quarter) |  | ||||||
|           ), |  | ||||||
|           line(length: 100%, stroke: 0.2mm), |  | ||||||
|           ( |  | ||||||
|             text(size: 20pt, title) + linebreak() + text(size: 10pt, subtitle) |  | ||||||
|           ), |  | ||||||
|           line(length: 100%, stroke: 0.2mm), |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ), |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #let warn = { |  | ||||||
|   set text(ored) |  | ||||||
|   align( |  | ||||||
|     center, |  | ||||||
|     block( |  | ||||||
|       width: 60%, |  | ||||||
|       height: auto, |  | ||||||
|       breakable: false, |  | ||||||
|       fill: rgb(255, 255, 255), |  | ||||||
|       stroke: ored + 2pt, |  | ||||||
|       inset: 3mm, |  | ||||||
|       ( |  | ||||||
|         align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) |  | ||||||
|           + parbreak() |  | ||||||
|           + align( |  | ||||||
|             left, |  | ||||||
|             text( |  | ||||||
|               size: 10pt, |  | ||||||
|               [This handout contains solutions and notes.] |  | ||||||
|                 + linebreak() |  | ||||||
|                 + [Recompile without solutions before distributing.], |  | ||||||
|             ), |  | ||||||
|           ) |  | ||||||
|       ), |  | ||||||
|     ), |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #let preparedby(name) = ( |  | ||||||
|   text( |  | ||||||
|     size: 10pt, |  | ||||||
|     [Prepared by ] |  | ||||||
|       + name |  | ||||||
|       + [ on ] |  | ||||||
|       + datetime |  | ||||||
|         .today() |  | ||||||
|         .display("[month repr:long] [day padding:none], [year]"), |  | ||||||
|   ) |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // MARK: Solutions |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #let solution(content) = { |  | ||||||
|   if show_solutions { |  | ||||||
|     align( |  | ||||||
|       center, |  | ||||||
|       stack( |  | ||||||
|         block( |  | ||||||
|           width: 100%, |  | ||||||
|           breakable: false, |  | ||||||
|           fill: ored, |  | ||||||
|           stroke: ored + 2pt, |  | ||||||
|           inset: 1.5mm, |  | ||||||
|           ( |  | ||||||
|             align(left, text(fill: white, weight: "bold", [Solution:])) |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         block( |  | ||||||
|           width: 100%, |  | ||||||
|           height: auto, |  | ||||||
|           breakable: false, |  | ||||||
|           fill: ored.lighten(80%).desaturate(10%), |  | ||||||
|           stroke: ored + 2pt, |  | ||||||
|           inset: 3mm, |  | ||||||
|           align(left, content), |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #let if_solutions(content) = { |  | ||||||
|   if show_solutions { content } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #let if_no_solutions(content) = { |  | ||||||
|   if not show_solutions { content } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // MARK: Sections |  | ||||||
| // |  | ||||||
|  |  | ||||||
| /// 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", 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) ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // `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") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // MARK: Misc |  | ||||||
| // |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #let note(content, type: none) = { |  | ||||||
|   if type != none { |  | ||||||
|     text(fill: rgb(100, 100, 100), style: "oblique", [#type: ]) |  | ||||||
|   } |  | ||||||
|   text(fill: rgb(100, 100, 100), content) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #let hint(content) = { |  | ||||||
|   note(content, type: "Hint") |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #let examplesolution(content) = { |  | ||||||
|   let c = oblue |  | ||||||
|  |  | ||||||
|   align( |  | ||||||
|     center, |  | ||||||
|     stack( |  | ||||||
|       block( |  | ||||||
|         width: 100%, |  | ||||||
|         breakable: false, |  | ||||||
|         fill: c, |  | ||||||
|         stroke: c + 2pt, |  | ||||||
|         inset: 1.5mm, |  | ||||||
|         ( |  | ||||||
|           align(left, text(fill: white, weight: "bold", [Example solution:])) |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|       block( |  | ||||||
|         width: 100%, |  | ||||||
|         height: auto, |  | ||||||
|         breakable: false, |  | ||||||
|         fill: c.lighten(80%).desaturate(10%), |  | ||||||
|         stroke: c + 2pt, |  | ||||||
|         inset: 3mm, |  | ||||||
|         align(left, content), |  | ||||||
|       ), |  | ||||||
|     ), |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // MARK: wrapper |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #let handout( |  | ||||||
|   doc, |  | ||||||
|   group: none, |  | ||||||
|   quarter: none, |  | ||||||
|   title: none, |  | ||||||
|   by: none, |  | ||||||
|   subtitle: none, |  | ||||||
| ) = { |  | ||||||
|   set par(leading: 0.55em, first-line-indent: 0mm, justify: true) |  | ||||||
|   set text(font: "New Computer Modern") |  | ||||||
|   set par(spacing: 0.5em) |  | ||||||
|   show list: set block(spacing: 0.5em, below: 1em) |  | ||||||
|   set heading(numbering: (..nums) => nums.pos().at(0)) |  | ||||||
|  |  | ||||||
|   set page( |  | ||||||
|     margin: 20mm, |  | ||||||
|     width: 8in, |  | ||||||
|     height: 11.5in, |  | ||||||
|     footer: align( |  | ||||||
|       center, |  | ||||||
|       context counter(page).display(), |  | ||||||
|     ), |  | ||||||
|     footer-descent: 5mm, |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   set list( |  | ||||||
|     tight: false, |  | ||||||
|     indent: 5mm, |  | ||||||
|     spacing: 3mm, |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|   show heading.where(level: 1): it => { |  | ||||||
|     set align(center) |  | ||||||
|     set text(weight: "bold") |  | ||||||
|     block[ |  | ||||||
|       Section #counter(heading).display(): #text(it.body) |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   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, |  | ||||||
|     title, |  | ||||||
|     { |  | ||||||
|       if by == none { none } else { [#preparedby(by)\ ] } |  | ||||||
|       if subtitle == none { none } else { subtitle } |  | ||||||
|     }, |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|   if show_solutions { |  | ||||||
|     warn |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   doc |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										71
									
								
								lib/typst/local/handout/0.1.0/header.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lib/typst/local/handout/0.1.0/header.typ
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | #import "misc.typ": ored | ||||||
|  |  | ||||||
|  | #let solution_warning() = { | ||||||
|  |   set text(ored) | ||||||
|  |   align( | ||||||
|  |     center, | ||||||
|  |     block( | ||||||
|  |       width: 60%, | ||||||
|  |       height: auto, | ||||||
|  |       breakable: false, | ||||||
|  |       fill: rgb(255, 255, 255), | ||||||
|  |       stroke: ored + 2pt, | ||||||
|  |       inset: 3mm, | ||||||
|  |       ( | ||||||
|  |         align(center, text(weight: "bold", size: 12pt, [Instructor's Handout])) | ||||||
|  |           + parbreak() | ||||||
|  |           + align( | ||||||
|  |             left, | ||||||
|  |             text( | ||||||
|  |               size: 10pt, | ||||||
|  |               [ | ||||||
|  |                 This handout contains solutions and notes. \ | ||||||
|  |                 Recompile without solutions before distributing. | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |       ), | ||||||
|  |     ), | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #let make_header( | ||||||
|  |   title, | ||||||
|  |   subtitle: none, | ||||||
|  |   by: none, | ||||||
|  |   top_left: "", | ||||||
|  |   top_right: "", | ||||||
|  | ) = { | ||||||
|  |   let date = datetime | ||||||
|  |     .today() | ||||||
|  |     .display("[month repr:long] [day padding:none], [year]") | ||||||
|  |  | ||||||
|  |   if (by != none) { | ||||||
|  |     by = text(size: 10pt, [Prepared by #by on #date]) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Main title | ||||||
|  |   align( | ||||||
|  |     center, | ||||||
|  |     block( | ||||||
|  |       width: 60%, | ||||||
|  |       height: auto, | ||||||
|  |       breakable: false, | ||||||
|  |       align( | ||||||
|  |         center, | ||||||
|  |         stack( | ||||||
|  |           spacing: 7pt, | ||||||
|  |           // Top | ||||||
|  |           text(size: 10pt, top_left) + h(1fr) + text(size: 10pt, top_right), | ||||||
|  |           line(length: 100%, stroke: 0.2mm), | ||||||
|  |           // Title | ||||||
|  |           text(size: 20pt, title), | ||||||
|  |           // Subtitle | ||||||
|  |           if (by != none) { text(size: 10pt, by) }, | ||||||
|  |           if (subtitle != none) { text(size: 10pt, subtitle) }, | ||||||
|  |           line(length: 100%, stroke: 0.2mm), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ), | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										113
									
								
								lib/typst/local/handout/0.1.0/lib.typ
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										113
									
								
								lib/typst/local/handout/0.1.0/lib.typ
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | /// Typst handout library, used for all documents in this repository. | ||||||
|  |  | ||||||
|  | // Re-exports | ||||||
|  | // All functions that maybe used by client code are listed here | ||||||
|  | #import "misc.typ": * | ||||||
|  | #import "object.typ": problem, definition, theorem | ||||||
|  | #import "solution.typ": if_solutions, if_no_solutions, solution | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// Main handout wrapper. | ||||||
|  | /// Use this as follows: | ||||||
|  | /// | ||||||
|  | /// ``` | ||||||
|  | /// #show: handout.with( | ||||||
|  | ///  group: "Advanced 2", | ||||||
|  | ///  title: [Handout Title], | ||||||
|  | ///  by: "author", | ||||||
|  | ///  subtitle: "optional", | ||||||
|  | /// ) | ||||||
|  | /// | ||||||
|  | /// <rest of document> | ||||||
|  | /// ``` | ||||||
|  | #let handout( | ||||||
|  |   doc, | ||||||
|  |   group: none, | ||||||
|  |   title: none, | ||||||
|  |   by: none, | ||||||
|  |   subtitle: none, | ||||||
|  | ) = { | ||||||
|  |   set page( | ||||||
|  |     margin: 20mm, | ||||||
|  |     width: 8in, | ||||||
|  |     height: 11.5in, | ||||||
|  |     footer: align( | ||||||
|  |       center, | ||||||
|  |       context counter(page).display(), | ||||||
|  |     ), | ||||||
|  |     footer-descent: 5mm, | ||||||
|  |   ) | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Text style | ||||||
|  |   set text(font: "New Computer Modern") | ||||||
|  |   set par( | ||||||
|  |     leading: 0.55em, | ||||||
|  |     first-line-indent: 0mm, | ||||||
|  |     justify: true, | ||||||
|  |     spacing: 0.5em, | ||||||
|  |   ) | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // List style | ||||||
|  |   show list: set block(spacing: 0.5em, below: 1em) | ||||||
|  |   set list( | ||||||
|  |     tight: false, | ||||||
|  |     indent: 5mm, | ||||||
|  |     spacing: 3mm, | ||||||
|  |   ) | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Heading style | ||||||
|  |   set heading(numbering: (..nums) => nums.pos().at(0)) | ||||||
|  |   show heading.where(level: 1): it => { | ||||||
|  |     set align(center) | ||||||
|  |     set text(weight: "bold") | ||||||
|  |     block[ | ||||||
|  |       Section #counter(heading).display(): #text(it.body) | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Hack for custom references | ||||||
|  |   show ref: it => { | ||||||
|  |     import "object.typ": ref_obj | ||||||
|  |  | ||||||
|  |     let x = ref_obj(it) // Custom impl for object references | ||||||
|  |     if (x != none) { return x } | ||||||
|  |  | ||||||
|  |     return it // Use default `ref` implementation otherwise | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Begin content | ||||||
|  |   // | ||||||
|  |  | ||||||
|  |   // Make handout title | ||||||
|  |   { | ||||||
|  |     import "header.typ": make_header, solution_warning | ||||||
|  |     import "solution.typ": show_solutions | ||||||
|  |  | ||||||
|  |     let url = link( | ||||||
|  |       "https://betalupi.com/handouts", | ||||||
|  |       "betalupi.com/handouts", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     make_header( | ||||||
|  |       title, | ||||||
|  |       subtitle: subtitle, | ||||||
|  |       by: by, | ||||||
|  |       top_left: group, | ||||||
|  |       top_right: url, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     if show_solutions { | ||||||
|  |       solution_warning() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Include rest of document | ||||||
|  |   doc | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								lib/typst/local/handout/0.1.0/misc.typ
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								lib/typst/local/handout/0.1.0/misc.typ
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | /// Miscellaneous utilities | ||||||
|  |  | ||||||
|  | #let ored = rgb("D62121") | ||||||
|  | #let oorange = rgb("#ffaa3b") | ||||||
|  | #let ogrape = rgb("9C36B5") | ||||||
|  | #let ocyan = rgb("2288BF") | ||||||
|  | #let oteal = rgb("12B886") | ||||||
|  | #let ogreen = rgb("37B26D") | ||||||
|  | #let oblue = rgb("1C7ED6") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #let note(content, type: none) = { | ||||||
|  |   set text(fill: rgb(100, 100, 100)) | ||||||
|  |   if type != none { | ||||||
|  |     text(style: "oblique", [#type: ]) | ||||||
|  |   } | ||||||
|  |   text(content) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #let hint = note.with(type: "Hint") | ||||||
|  |  | ||||||
|  | #let examplesolution(content) = { | ||||||
|  |   let c = oblue | ||||||
|  |  | ||||||
|  |   align( | ||||||
|  |     center, | ||||||
|  |     stack( | ||||||
|  |       block( | ||||||
|  |         width: 100%, | ||||||
|  |         breakable: false, | ||||||
|  |         fill: c, | ||||||
|  |         stroke: c + 2pt, | ||||||
|  |         inset: 1.5mm, | ||||||
|  |         ( | ||||||
|  |           align(left, text(fill: white, weight: "bold", [Example solution:])) | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       block( | ||||||
|  |         width: 100%, | ||||||
|  |         height: auto, | ||||||
|  |         breakable: false, | ||||||
|  |         fill: c.lighten(80%).desaturate(10%), | ||||||
|  |         stroke: c + 2pt, | ||||||
|  |         inset: 3mm, | ||||||
|  |         align(left, content), | ||||||
|  |       ), | ||||||
|  |     ), | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								lib/typst/local/handout/0.1.0/object.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								lib/typst/local/handout/0.1.0/object.typ
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | |||||||
|  |  | ||||||
|  | /// 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") | ||||||
							
								
								
									
										56
									
								
								lib/typst/local/handout/0.1.0/solution.typ
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										56
									
								
								lib/typst/local/handout/0.1.0/solution.typ
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | #import "misc.typ": ored | ||||||
|  |  | ||||||
|  | /// If false, hide instructor info. | ||||||
|  | /// | ||||||
|  | /// Compile with the following command to hide solutions: | ||||||
|  | /// `typst compile main.typ --input show_solutions=false` | ||||||
|  | /// | ||||||
|  | /// Solutions are shown by default. This behavior | ||||||
|  | /// is less surprising than hiding content by default. | ||||||
|  | #let show_solutions = { | ||||||
|  |   if "show_solutions" in sys.inputs { | ||||||
|  |     // Show solutions unless they're explicitly disabled | ||||||
|  |     not ( | ||||||
|  |       sys.inputs.show_solutions == "false" or sys.inputs.show_solutions == "no" | ||||||
|  |     ) | ||||||
|  |   } else { | ||||||
|  |     // Show solutions by default | ||||||
|  |     true | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #let if_solutions(content) = { | ||||||
|  |   if show_solutions { content } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #let if_no_solutions(content) = { | ||||||
|  |   if not show_solutions { content } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #let solution(content) = { | ||||||
|  |   if_solutions( | ||||||
|  |     align( | ||||||
|  |       center, | ||||||
|  |       stack( | ||||||
|  |         block( | ||||||
|  |           width: 100%, | ||||||
|  |           breakable: false, | ||||||
|  |           fill: ored, | ||||||
|  |           stroke: ored + 2pt, | ||||||
|  |           inset: 1.5mm, | ||||||
|  |           align(left, text(fill: white, weight: "bold", [Solution:])), | ||||||
|  |         ), | ||||||
|  |  | ||||||
|  |         block( | ||||||
|  |           width: 100%, | ||||||
|  |           height: auto, | ||||||
|  |           breakable: false, | ||||||
|  |           fill: ored.lighten(80%).desaturate(10%), | ||||||
|  |           stroke: ored + 2pt, | ||||||
|  |           inset: 3mm, | ||||||
|  |           align(left, content), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ), | ||||||
|  |   ) | ||||||
|  | } | ||||||
| @ -1,6 +1,12 @@ | |||||||
| [package] | [package] | ||||||
| name = "handout" | name = "handout" | ||||||
|  | description = "A library for math circle handouts" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| entrypoint = "handout.typ" | entrypoint = "lib.typ" | ||||||
| authors = [] |  | ||||||
| license = "GPL" | homepage = "https://betalupi.com/handouts" | ||||||
|  | repository = "https://git.betalupi.com/Mark/handouts" | ||||||
|  | authors = ["Mark <mark@betalupi.com>"] | ||||||
|  | license = "GPL-3.0-only " | ||||||
|  | disciplines = ["education", "mathematics"] | ||||||
|  | categories = ["layout", "components"] | ||||||
| @ -1,13 +1,6 @@ | |||||||
| #import "@local/handout:0.1.0": * | #import "@local/handout:0.1.0": * | ||||||
|  |  | ||||||
| #show: doc => handout( | #show: handout.with( | ||||||
|   doc, |  | ||||||
|   group: "Advanced 2", |  | ||||||
|   quarter: link( |  | ||||||
|     "https://betalupi.com/handouts", |  | ||||||
|     "betalupi.com/handouts", |  | ||||||
|   ), |  | ||||||
|  |  | ||||||
|   title: [Tropical Polynomials], |   title: [Tropical Polynomials], | ||||||
|   by: "Mark", |   by: "Mark", | ||||||
|   subtitle: "Based on a handout by Bryant Mathews", |   subtitle: "Based on a handout by Bryant Mathews", | ||||||
|  | |||||||
| @ -153,7 +153,7 @@ What are the roots of the following polynomial? | |||||||
| #v(1fr) | #v(1fr) | ||||||
| #pagebreak() // MARK: page | #pagebreak() // MARK: page | ||||||
|  |  | ||||||
| #problem() | #problem(label: "findci") | ||||||
| If | If | ||||||
| $ | $ | ||||||
|   f(x) = c_0 #tp c_1 x #tp c_2 x^2 #tp ... #tp c_n x^n |   f(x) = c_0 #tp c_1 x #tp c_2 x^2 #tp ... #tp c_n x^n | ||||||
| @ -183,7 +183,7 @@ Find a formula for each $C_i$ in terms of $c_0, c_1, ..., c_n$. | |||||||
|  |  | ||||||
|  |  | ||||||
| #problem() | #problem() | ||||||
| With the same setup as the previous problem, \ | With the same setup as @findci, \ | ||||||
| find formulas for the roots $r_1, r_2, ..., r_n$. | find formulas for the roots $r_1, r_2, ..., r_n$. | ||||||
|  |  | ||||||
| #solution([ | #solution([ | ||||||
|  | |||||||
| @ -1,12 +1,6 @@ | |||||||
| #import "@local/handout:0.1.0": * | #import "@local/handout:0.1.0": * | ||||||
|  |  | ||||||
| #show: doc => handout( | #show: handout.with( | ||||||
|   doc, |  | ||||||
|   quarter: link( |  | ||||||
|     "https://betalupi.com/handouts", |  | ||||||
|     "betalupi.com/handouts", |  | ||||||
|   ), |  | ||||||
|  |  | ||||||
|   title: [Somewhat Random Numbers], |   title: [Somewhat Random Numbers], | ||||||
|   by: "Mark", |   by: "Mark", | ||||||
| ) | ) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user