How to have different color schemes for template?

Hello everyone (this is my first question on the forum, please let me know if I’m doing something wrong).

I’m trying to write a template that would have two possible set of colors, say light or dark, to typeset certain elements (background, text, titles, etc). I also want to expose these colors to the template user. Before writing it as a template, I was simply doing

#let theme = "dark"
#let color_lib = (
  dark: (
    background: oklch(25%, 0.03, 290deg),
    text: oklch(90%, 0.045, 270deg),
    highlight: oklch(88%, 0.08, 220deg)
  ),
  light: (
    background: oklch(90%, 0.02, 290deg),
    text: oklch(25%, 0.03, 290deg),
    highlight: oklch(50%, 0.25, 290deg),
  )
)
// insert defaults in the color dict
#for (name, color) in color_lib.at(theme) { 
    color_lib.insert(name, color)
}

#set page(fill: color_lib.background)
#set text(fill: color_lib.text)

Hello #text(fill: color_lib.highlight)[there].

Then, I can change the full theme just by changing the variable theme, and while writing, I can decide either to follow the theme by using colors in color_lib.<name> or specify I want a color from a specific theme with color_lib.<theme>.<name>.

I now would like to hide this logic away into a package/template, which I believe should look like

#import "lib.typ" : template_func

#show: template_func.with(
    theme: "dark", 
    ...
)

but things get complicated inside lib.typ :

  • If I try to just copy paste things within the definition of template_func, I am not allowed to mutate the color_lib dictionnary anymore to inject defaults based on the selected theme.
  • Elsewhere in lib.typ, I do not know which theme the user has selected.
  • To what I understood from the documentation, I could use a state variable for color_lib, which would allow to mutate it inside a function, but it sounds completely overkill to me : conceptually, I don’t want to be able to change the theme mid document : theme should be an unmutable constant. In practice, it also forces me to put context statements everytime I want a color, which makes the code pretty ugly.

Since I’m very new to typst, I’m not sure if I misunderstood some concept, if I’m really meant to use state/context everywhere, or if I’m missing something much simpler. Any help is very welcome :)

Hello. “Elsewhere in lib.typ” sounds strange if the template function is the only thing that user will use. The whole point of the template function is to include all the styling that is applied once.

If there are some styling wrapper functions, then you either have to provide an explicit argument for colors dictionary or use state.