Files
curriculum-project-hub/render/src/style.typ
T
sjfhsjfh c17af60bb0 feat(render): rebuild typst render package cph-render (WU-2)
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>
2026-06-22 01:33:40 +08:00

86 lines
2.1 KiB
Typst

// Base document styling: CJK fonts, headings, math, paragraph layout, page.
//
// Zero external dependencies. Heading numbering uses builtin `numbering`
// strings (no @preview/numbly) so the package compiles with no network.
#import "fonts.typ"
/// Apply the base style to a document body. Used as `show: base-style`.
#let base-style(doc) = {
// Language / region drive CJK line-breaking and punctuation.
set text(lang: "zh", region: "cn", size: 12pt, font: fonts.serif)
set text(cjk-latin-spacing: auto)
// Heading numbering: 一、 / 1.1 / 1.1.1 — builtin numbering, no deps.
set heading(numbering: "一、")
show heading: set text(font: fonts.sans)
// Number display equations.
set math.equation(numbering: "(1)")
set par(
first-line-indent: (amount: 2em, all: true),
leading: 0.8em,
spacing: 1.5em,
justify: true,
)
set page(
margin: (x: 2.2cm, y: 2.4cm),
footer: context align(center)[
#counter(page).get().at(0) / #counter(page).final().at(0)
],
)
set table(inset: 5pt, stroke: 0.75pt)
// Inline quotes -> subtle highlight (matches prototype feel).
show quote.where(block: false): it => highlight(
it.body,
fill: gray.transparentize(60%),
top-edge: 1em,
bottom-edge: -0.2em,
extent: 0.35em,
radius: 0.25em,
)
show link: set text(fill: eastern)
show link: underline
doc
}
/// Cancel the active paragraph first-line indent (for tag lines that should
/// start flush-left). Defensive against both `length` and `dict` indent forms.
#let no-indent = context {
let fli = par.first-line-indent
if type(fli) == length {
h(-fli)
} else {
h(-fli.amount)
}
}
/// Document title block.
#let title-block() = {
set align(center)
set text(font: fonts.sans, size: 22pt, weight: "bold")
context document.title
}
/// Subtitle + authors block under the title.
#let subtitle-block(subtitle) = {
set align(center)
set text(size: 14pt)
v(1.2em, weak: true)
subtitle
context {
let authors = document.author
if authors != () {
v(0.8em, weak: true)
authors.join(h(1.5em))
}
}
v(1.2em, weak: true)
}