How can I set the default value of a function dependent of a condition?

I would like to create a template which can either be ‘modern’ (using Roboto and related fonts) or ‘classic’ (using Libertinus Serif and friends) dependent on a command line switch (for testing purposes). This works nicely for headers, body text, etc., but drop caps are giving me headaches. How can I make this work most nicely?

this is (part of) the template file

#import "@preview/droplet:0.3.1": dropcap

#let dropcap-font = state("dropcap-font")

#let thesis(classic: false, it) = {
  set text(font: "roboto")
  show heading: set text(font: "Libertinus Serif", features: ("smcp",)) if classic
  show heading: set text(font: "Roboto Slab") if not classic

  if classic {
    dropcap-font.update("Libertinus Serif")
  } 
  else {
    dropcap-font.update("Roboto Slab")
  }

  it
}

#let dropcap = dropcap.with(
  height: 3,
  gap: .2em,
  // does work, but does not depend on condition `classic`:
  // font: "roboto slab",
  // does not work; gives an error `Expected string, dictionary, or array, found content`:
  // font: context(str(dropcap-font.get())),
  weight: 400,
)

this is (part of) the demo file:

#import "template.typ": *

#let classic = sys.inputs.at("classic", default: "false")
#let classic = not (classic == "false")

#let dropcap-font = state("dropcap-font")
#show: thesis.with(classic: classic)

// does not work
#dropcap-font.update("roboto slab")

// does not work
#if not classic {
  let dropcap = dropcap.with(font: "roboto slab",)
}

// does work, but does not depend on condition `classic`
#let dropcap = dropcap.with(fill: red,)

= Demo

#dropcap[#lorem(200)]

I would expect that the switch in the demo file would work, but it doesn’t. I also hope there is a prettier way (setting the dropcap font near where the header font is set)

The current code gives me a Roboto (not Roboto Slab) red initial:

Thanks heaps in advance!

What do you expect to work? The font parameter set inside the if/else statements is the same. Changing it yields the desired results.

You could define your own contextual dropcap function inside template.typ, which gets the font from the state. Something like this:

#import "@preview/droplet:0.3.1": dropcap as dc

#let dropcap-font = state("dropcap-font")

#let thesis(classic: false, it) = {
  ..
  if classic {
    dropcap-font.update("Libertinus Serif")
  } 
  else {
    dropcap-font.update("Roboto Slab")
  }

  it
}

#let dropcap(..args) = context dc(
  height: 3,
  font: dropcap-font.get(),
  gap: .2em,
  weight: 400,
  ..args
)
2 Likes

Thanks for the reply, but I do not see an initial in Roboto Slab. I’ve edited my question to be more clear.

Could you clarify which part is the one causing issues? Is the issue

  1. The compiled PDF does not contain any text written in roboto slab, even if explicitly specified e.g. #text(font: "Roboto Slab")[I am in Roboto Slab!]
  2. The PDF contains text written in Roboto Slab, but the font inside the dropcap can never be set to roboto slab, even through #dropcap(font: "Roboto Slab")[I am in Roboto Slab!]
  3. Writing text and dropcaps in Roboto/Roboto Slab works when the font is explicitly specified, but not through the template you are writing. More specifically, the template only uses one font for the dropcap regardless of what classic is set to, even if you use fonts which are not Roboto/Roboto Slab.

I ask this because the code snippet I provided works on my end:

#import "template.typ": *

#show: thesis.with(classic: true)

= Demo
#dropcap[#lorem(200)]


#show: thesis.with(classic: false)

= Demo
#dropcap[#lorem(200)]

If the issue is either of the first 2, it is probably because you do not have the fonts installed.

sorry, I overlooked you renamed dropcap to dc. This works perfectly :slight_smile: