Adding text to *some* level 1 headings

Hello everyone,

This is a followup on a reddit post I did previously, which answered a few of my questions but added two others.

I am experimenting styling for books layout, and I am trying to add a

Chapter [number]
#linebreak()

before numbered chapters of a book, but not every single one (e.g. the Table of Content, Foreword, etc.)

As of now I have this function :

#show heading.where(level: 1): it => {
  let num = counter(heading).display("1")
  pagebreak(weak: true)
  v(20%)
  align(center)[
  #block[
    #text(
      size: 32pt,
      weight: "regular",
    )[#emph[
    Chapter #num
    #linebreak()
    #it.body]]
    
    #v(1.5em)
    ]]

But the title of the table of content and the foreword get added a “Chapter” before them which just doesn’t work.
Is there a way to segregate the level 1 headings that are numbered chapters from the other ones ?

Thanks in advance !

PS : Also, not the same but related question, for my ToC I use #set heading(numbering: "Chapter 1.", supplement: [Chapter]) but the outline only displays “Cha.”, “Chb.”, “Chc.” and such. Then again, is there a way to fix this and display the long text, and also separate numbered chapters from un-numbered ones ?

The styling you’re going for here specifically would be a duplicate of How to display "Chapter X" above level 1 heading name?.

Since the excluded headings all appear at the start, you could simply have the show rule below them in the code:

= Foreword
...

// The `show` rule goes here

= Lorem
...

Alternatively, don’t change the show rule’s positions in the code, but instead add #set heading(numbering: ...) where necessary, especially for more alterations:

#show heading.where(level: 1).and(heading.where(numbering: "1")): set text(red)

= Black

#set heading(numbering: "1")

= Red

#set heading(numbering: none)

= Black

Notice the added and.


Otherwise, I believe you would need to distinguish the headings through labels.


That’s how the numbering is detected. You would need to pass a function, for example Package subpar0.2.2 - #2 by hpcfzl.

1 Like

Thank you, your solution (I went with the second one which I find more flexible).
I did declare a rule for the headings twice :

#show heading.where(level: 1): it => {
  pagebreak(weak: true)
  v(20%)
  align(center)[
  #block[
    #text(size: 32pt, weight: "regular",)[#emph[
    #it.body]]
    #v(1.5em)
    ]]
  par(first-line-indent: 0pt)[] // No indent for first paragraph
}
#show heading.where(level: 1).and(heading.where(numbering: "Chapter 1.")): it => {
  pagebreak(weak: true)
  v(20%)
  align(center)[
  #block[
    #text(size: 32pt, weight: "regular",)[#emph[
  Chapter #counter(heading).display("1")
    #linebreak()
    #it.body]]
    #v(1.5em)
    ]]
  par(first-line-indent: 0pt)[] // No indent for first paragraph
}

Is this good practice or is there a better way ?

Sorry for the double post, but I created another error related to this.
To have the Chapter numbers displayed properly in the outline, I used :
#set heading(numbering: (counter) => [Chapter #counter.], supplement: [Chapter])
However, this way, I cannot seem to be able to target properly the titles with
#show heading.where(level: 1).and(heading.where(numbering:(counter) => [Chapter #counter.])): it => {...}

What am I doing wrong ?

I would at least eliminate the repetition.

So here’s the updated code based on your needs:

#show heading.where(level: 1): it => {
  pagebreak(weak: true)
  set align(center)
  v(20%)
  block(
    below: 1.5em,
    text(size: 32pt, weight: "regular", {
      if heading.numbering != none [
        _Chapter #counter(heading).display()_ \
      ]
      it.body
    }),
  )
}

The obvious changes are:

  • and → if, allowing for a more unified show rule
  • par(first-line-indent: 0pt)[] → removed for having no effect, but I could be missing something
  • align(center) → set align(center), avoiding excessive nesting
  • v(1.5em) → below: 1.5em, however not the same to above which is still v(20%), also couldn’t be inset: (top: 20%) as it’s a ratio that you’re using

The numbering confusion you have addressed meanwhile is that we’re not using a Chapter n counter, but n, because I assumed all your numbered headings should be Chapter n. So I prefer to add the Chapter in the show rule here, not in the numbering. I don’t think we could nicely use those comparisons within numbering.

1 Like

Then again, thanks a lot for your reply ! I didn’t know an if statement existed as the term is not findable in the docs… Very useful !
It works very well ! Last question (hopefully) about the ToC issue : if I’m using your function, it means that my #set heading(numbering: (counter) => [Chapter #counter.], supplement: [Chapter]) has to be modified in order to avoid a “Chapter Chapter n”.

I have to include that in the outline, I suppose.
I’ve tried :

#show outline.entry.where(level: 1) : it => {
  if it.numbering != none [
    Chapter #counter(it).display(). #it
  ]
 }

But it doesn’t work. The Entry does not have field numbering… I’ve tried replacing “it” with “heading” but no luck either…
What am I missing ?

No problem, it’s clearly something to acknowledge! Again, I would advise against using a numbering function for this use case.

I understand that you would like to have Chapter n visible also in the entries? As you encountered, there’s not really a way to counter(element) from that sort of show rule.

What is needed usually I believe is a query, followed by a counter(element).at("queried element's location"). The query is essentially already available to us in outline.entry’s show rule, through it.element.

So you were close, it’s only the matter of adding these together into the initial entry:

#show outline.entry.where(level: 1): it => link(
  it.element.location(),
  it.indented(
    if it.element.numbering != none {
     // This would be needlessly complicated `query(selector(heading.where(level: 1).and(heading.where(numbering: "1"))).before(it.element.location(), inclusive: false))`
     "Chapter " + numbering("1", ..counter(heading).at(it.element.location()))
    } else {
     it.prefix()
    },
    it.inner()
  ),
)
1 Like

I’m very very grateful. Thanks to you, all my problems regarding this matter are solved.
You rock !

1 Like