Refactor handout.typ
				
					
				
			This commit is contained in:
		| @ -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] | ||||
| name = "handout" | ||||
| description = "A library for math circle handouts" | ||||
| version = "0.1.0" | ||||
| entrypoint = "handout.typ" | ||||
| authors = [] | ||||
| license = "GPL" | ||||
| entrypoint = "lib.typ" | ||||
|  | ||||
| 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"] | ||||
		Reference in New Issue
	
	Block a user