How to access the underlying value of state with correct type in Typst

264 views Asked by At

I'm currently building a template with polylux where the user can define one of five color themes. As the chosen color theme is global state I used the state type. My colors are organized as a map and i want to use the chosen color scheme as a key for it, to get the correct colors. Howver I'm running into type issues as state stores everything as any.

A barebones example would be:

#let RedTheme = (light: rgb(255, 0, 0), dark: rgb(128, 0, 0))

#let GreenTheme = (light: rgb(0, 255, 0), dark: rgb(0, 128, 0))

#let AllThemes = (theme1: RedTheme, theme2: GreenTheme)

#let theme = state("theme", "theme1")

// sets up state
#let template(user-theme: "", body) = {
  theme.update(user-theme)

  body
}

#show: template.with(user-theme: "theme2")

// FIXME: this is broken
#let color = AllThemes.at(state("theme").display())

Whenever i try to do something like: AllColors.at(state("scheme").display()) i get an error essentielly telling me content cannot be used as string.

Am I missing some conversion function or is this even the right approach?

1

There are 1 answers

2
Peng Guanwen On BEST ANSWER

You must wrap the code into a locate so similar to extract the value of state.

#let with-theme(body) = {
  locate(loc => {
    let theme-color = AllThemes.at(state("theme").at(loc))
    body(theme-color)
  })
}

#show: template.with(user-theme: "theme2")

#with-theme(theme => {
  rect(width: 12pt, fill: theme.light)
})

But this inconvenience only happens when you want to use a state, of which main use case is counters. Otherwise just use a normal variable and you're just fine.

// in template:
#let get-theme(name) = AllThemes.at(name)

// In main.typ:
#let theme = get-theme("theme1")
rect(width: 12pt, fill: theme.light)