// Auto-generated quillmark-helper package
// Version: {version}
/// Emit an unsigned signature field. PDF: a clickable AcroForm SigField
/// widget here. SVG/PNG: same invisible layout space.
/// `name` must be unique and match `[A-Za-z0-9_]+`. `width` / `height` must
/// be absolute lengths (pt/mm/cm/in).
/// `<__qm_sig__>` and `kind: "__qm_sig__"` are reserved for this hand-off.
#let signature-field(name, width: 200pt, height: 50pt) = {
assert(type(name) == str,
message: "signature-field: name must be a string, got " + repr(type(name)))
assert(name.match(regex("^[A-Za-z0-9_]+$")) != none,
message: "signature-field: name must match [A-Za-z0-9_]+, got " + repr(name))
let abs-pt(field, l) = {
let r = repr(l)
assert(not (r.contains("em") or r.ends-with("%")),
message: "signature-field: " + field + " must be an absolute length, got " + r)
l / 1pt
}
[#metadata((
kind: "__qm_sig__",
name: name,
width: abs-pt("width", width),
height: abs-pt("height", height),
)) <__qm_sig__>]
box(width: width, height: height, stroke: none, fill: none)
}
/// Parse an ISO 8601 date string (YYYY-MM-DD) to a Typst datetime
/// Handles both pure dates (2024-01-15) and datetime strings (2024-01-15T10:30:00)
/// Must be defined before `data` — Typst does not hoist `#let` bindings.
#let _parse-date(s) = {
if s == none { return none }
let date-str = str(s)
// Handle datetime strings by extracting just the date part
if date-str.contains("T") {
date-str = date-str.split("T").at(0)
}
let parts = date-str.split("-")
if parts.len() < 3 { return none }
let year = int(parts.at(0))
let month = int(parts.at(1))
// Take only the first 2 characters in case there's extra content
let day-str = parts.at(2)
if day-str.len() > 2 { day-str = day-str.slice(0, 2) }
let day = int(day-str)
datetime(year: year, month: month, day: day)
}
/// Document data as a dictionary.
/// Markdown fields are automatically converted to Typst content objects.
/// The `__meta__` key (injected by the Rust backend) is consumed here and
/// never exposed to plate authors.
#let data = {
let d = json(bytes("{escaped_json}"))
// Read and consume __meta__ (injected by transform_fields)
let meta = d.remove("__meta__", default: (
content_fields: (),
card_content_fields: (:),
date_fields: (),
card_date_fields: (:),
))
// Auto-eval top-level content fields
for key in meta.content_fields {
if key in d {
let val = d.at(key)
if type(val) == str and val != "" {
d.insert(key, eval(val, mode: "markup"))
}
}
}
// Auto-convert top-level date fields to datetime
for key in meta.date_fields {
if key in d {
let val = d.at(key)
if val != none {
d.insert(key, _parse-date(val))
}
}
}
// Auto-eval content fields within each CARD
if "CARDS" in d {
let cards = ()
for card in d.at("CARDS") {
let card-type = card.at("CARD", default: none)
let fields = meta.card_content_fields.at(card-type, default: ())
for key in fields {
if key in card {
let val = card.at(key)
if type(val) == str and val != "" {
card.insert(key, eval(val, mode: "markup"))
}
}
}
// Auto-convert date fields for this card type
let date-fields = meta.card_date_fields.at(card-type, default: ())
for key in date-fields {
if key in card {
let val = card.at(key)
if val != none {
card.insert(key, _parse-date(val))
}
}
}
cards.push(card)
}
d.insert("CARDS", cards)
}
d
}