How can I separate formatting and functionality in own templates?

For your specific case of a figure with an optional and configurable note I would do the following:

#let template(body) = {
  // you can set up your default/recommended rules here
  show figure.caption: set text(fill: red)

  body
}

// you can set up the default style for your notes here
#let my-note(fill: green, supplement: "Note", body) = block[
  #set text(fill: fill)
  #supplement: #body
]

// this function is kept very general, "note" can either be none or content
#let my-figure(content, note: none, ..args) = {
  figure(..args)[
    #content
    #if note != none { note }
  ]
}

#show: template

// you can override the rules from the template here if you don't like the default style
// (this might not work for complex show rules that completely modify an element)
#show figure.caption: set text(fill: purple)

// you can override the style of the figure notes by redefining the default values
#let my-note = my-note.with(fill: blue)

#my-figure(
  rect(width: 80%, height: 20%),
  note: my-note(lorem(30)),
  caption: [#lorem(10)]
)

While this requires you to pass the note content through the function figure-note(), I wouldn’t mind the additional “verbosity” for the gain in the flexibility.

If you haven’t seen it yet, this post is definitely worth reading if you want some more insights into writing and using templates. Don’t get too excited though, you won’t be able to directly apply everything you see there to your template. Some of the answers already look ahead what templates can/would look like when custom types are available.

1 Like