/// 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(