// Base document styling: CJK fonts, headings, math, paragraph layout, page. // // Heading numbering is PER-LEVEL and built from a numbly pattern array passed // in by the caller (lib.typ resolves it from config + framework default). This // fixes the old single-pattern bug where one `numbering: "一、"` was reused for // every level (a level-2 heading rendered as `二、一、…`). The only @preview // dependency is `@preview/numbly`, vendored under `render/vendor/...` for // network-free CI; see render/typst.toml's note. #import "@preview/numbly:0.1.0": numbly #import "fonts.typ" /// Framework-default per-level heading numbering patterns (numbly syntax). /// Level 1 -> `一、`, level 2 -> `1.1`, level 3 -> `1.1.1`. This is the /// correct-by-default scheme; `config.numbering.heading` overrides it. #let default-heading-numbering = ( "{1:一}、", "{1:1}.{2:1}", "{1:1}.{2:1}.{3:1}", ) /// Apply the base style to a document body. Used as `show: base-style(..)`. /// /// `heading-numbering` is an array of per-level numbly pattern strings; it is /// spread into `numbly(..)` to build the per-level heading numbering function. #let base-style(heading-numbering: default-heading-numbering, 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) // Per-level heading numbering via numbly: each level gets its own pattern, // so level 2 renders `1.1`, not the old buggy `二、一、`. set heading(numbering: numbly(..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) }