forked from bai/curriculum-project-hub
c17af60bb0
Single entry `display(info, target, parts)` over an ordered parts array, the frozen contract the generated typst driver calls. Per-kind dispatch for segment/example/lemma/sop; student/teacher matrix derived internally from `target` (student hides example solution + lemma proof; teacher shows all). Content-field values are consumed as already-evaluated content (driver `include`s them ⇒ module body, ADR-0006), never imported/stringified. Optional fields (lemma proof, example source) handled gracefully; unknown kind/target degrade without crashing. Zero @preview deps (CI-robust); CJK + math styled. Smoke compiles to non-empty student/teacher PDFs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
1.1 KiB
Typst
39 lines
1.1 KiB
Typst
// example: a worked example / problem.
|
||
//
|
||
// Contract fields:
|
||
// content: `problem` (required), `solution` (required)
|
||
// scalar: `source` (optional string)
|
||
//
|
||
// Numbered "例题 N" via the shared example-counter.
|
||
// student: show `problem`, HIDE `solution`.
|
||
// teacher: show both.
|
||
// `source`, when present, is shown as a small annotation on the problem line.
|
||
|
||
#import "../fonts.typ"
|
||
#import "common.typ": element-box, tag-line, divider, example-counter, hue-of
|
||
|
||
#let display-example(part, show-solution: true) = {
|
||
let theme = oklch(70%, 0.08, hue-of.example * 1deg)
|
||
example-counter.step()
|
||
|
||
element-box(hue-of.example, {
|
||
// Problem
|
||
tag-line(context [例题 #example-counter.display()])
|
||
let source = part.at("source", default: none)
|
||
if source != none and source != "" {
|
||
text(size: 0.85em, fill: gray.darken(30%))[(来源:#source)]
|
||
h(0.3em)
|
||
}
|
||
set text(font: fonts.accent)
|
||
part.problem
|
||
|
||
// Solution (teacher-only by default)
|
||
if show-solution {
|
||
divider(theme)
|
||
tag-line[解析]
|
||
set text(font: fonts.accent)
|
||
part.solution
|
||
}
|
||
})
|
||
}
|