Reviewed-on: #5 Co-authored-by: Mark <mark@betalupi.com> Co-committed-by: Mark <mark@betalupi.com>
287 lines
5.2 KiB
Typst
Executable File
287 lines
5.2 KiB
Typst
Executable File
/// 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 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
|
|
//
|
|
|
|
#let generic(t) = block(
|
|
above: 8mm,
|
|
below: 2mm,
|
|
text(weight: "bold", t),
|
|
)
|
|
|
|
#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),
|
|
)
|
|
}
|
|
}
|
|
|
|
#let problem(..args) = _generic_base("Problem", ..args)
|
|
#let definition(..args) = _generic_base("Definition", ..args)
|
|
#let theorem(..args) = _generic_base("Theorem", ..args)
|
|
|
|
|
|
//
|
|
// MARK: Misc
|
|
//
|
|
|
|
|
|
#let hint(content) = {
|
|
text(fill: rgb(100, 100, 100), style: "oblique", "Hint: ")
|
|
text(fill: rgb(100, 100, 100), content)
|
|
}
|
|
|
|
#let note(content) = {
|
|
text(fill: rgb(100, 100, 100), content)
|
|
}
|
|
|
|
#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)
|
|
]
|
|
}
|
|
|
|
make_title(
|
|
group,
|
|
quarter,
|
|
title,
|
|
{
|
|
if by == none { none } else { [#preparedby(by)\ ] }
|
|
if subtitle == none { none } else { subtitle }
|
|
},
|
|
)
|
|
|
|
if show_solutions {
|
|
warn
|
|
}
|
|
doc
|
|
}
|
|
|