|
I am working on a template where each chapter is supposed to begin on its own odd page: // Place new chapters on a new odd page
#show heading.where(level: 1): it => {
pagebreak(weak: true, to: "odd")
it
}and I have headings and page numbers configured: #set page(header: ["Header contents!"], numbering: "1")Unfortunately, the header and page numbers are repeated on the completely empty pages, which I find undesireable. I've played around with locate and query to try and figure out whether the current page has elements, but I haven't gotten anything to work. Is there a way to achieve this? |
Replies: 5 comments 22 replies
|
Hi, This is possible to do, but it took me some time to figure it out. At first, I thought it would be the easiest way to replace The second attemp wraps chapter headings with markers (using a Take a look at those two examples:
The // returns true if page at location is an inserted page and false otherwise
#let page-is-inserted(loc) = {
let page = loc.page()
let pairs = state("chapter-markers").at(loc)
if pairs == none { return false }
// page is inserted if surrounded by end- and start-marker for any chapter
return pairs.any(((end-page, start-page)) => {
page > end-page and page < start-page
})
}
#let custom-header = {
locate(loc => {
if not page-is-inserted(loc) [Header contents!]
})
}
#let custom-numbering(page, maxPage) = {
locate(loc => {
if not page-is-inserted(loc) [#page]
})
}
#set page(header: custom-header, numbering: custom-numbering, paper: "a6")
// wraps heading with end-marker and start-marker
#show heading.where(level: 1): it => [
#[]<chapter-end-marker> // marker positioned before the pagebreak
#pagebreak(to: "odd", weak: true)
#it
#[]<chapter-start-marker> // marker positioned after the pagebreak
]
// queries markers and updates state with pairwise pages for each chapter
#locate(loc => {
let chapter-end-markers = query(<chapter-end-marker>, loc)
let chapter-start-markers = query(<chapter-start-marker>, loc)
let pairs = chapter-end-markers.enumerate().map(((index, chapter-end-marker)) => {
let chapter-start-marker = chapter-start-markers.at(index)
let end-page = chapter-end-marker.location().page()
let start-page = chapter-start-marker.location().page()
(end-page, start-page)
})
state("chapter-markers").update(pairs)
})
= Chapter 1
== Section A
== Section B
== Section C
= Chapter 2
== Section A
== Section B
== Section CReproduction URL: https://typst.app/project/rbX2FRMrJFIIGCpoh15wq4 I agree that this is a complicated thing to do and it would be nice to have this built-in to the |
|
The solution that worked for me looks like this: // Advances to the next odd page
#let pagebreak-to-odd = context {
let n = here().page()
if calc.odd(n) {
page(header: [], footer: [])[]
} else if calc.even(n) {
v(100%, weak: true)
}
}so when I end on an odd page, I insert a blank page with no styling, and when I end on an even page, I simply add vertical spacing to fill up the page. By this I always start a new chapter on an odd page. |
|
so i needed something similar and found this thread. The issue with the presented solutions is that the first content created in a #show heading.where(level: 1): it => {
state("content.switch").update(false)
pagebreak(weak: true, to:"odd")
state("content.switch").update(true)
it
}
#set page(
header: context {
let page = here().page()
let is-start-chapter = query(heading.where(level:1))
.map(it => it.location().page())
.contains(page)
if not state("content.switch", false).get() and not is-start-chapter {
[ Empty Page ]
return
}
state("content.pages", (0,)).update(it => {
it.push(page)
return it
})
if is-start-chapter {
[ Start of chapter ]
} else {
[ There is content on page ]
}
line()
},
footer: context {
let has-content = state("content.pages", (0,)).get()
.contains(here().page())
if has-content {
align(center, counter(page).display())
} else {
[ Empty Page ]
}
}
)
|
|
I have found another way without using states or labels at all, producing an empty page before starting a new level 1 heading: #let headings-on-odd-page(it) = {
show heading.where(level: 1): it => {
{
set page(header: none, numbering: none)
pagebreak(to: "odd")
}
it
}
it
}
#show heading.where(level: 1): it => // do your normal header styling here
#show: headings-on-odd-pageThis works, because we restrict the scope of |



I have found another way without using states or labels at all, producing an empty page before starting a new level 1 heading:
This works, because we restrict the scope of
set page(header: none, numbering: none)to the scope inside theheadings-on-odd-pageshow rule. Applying the show rule insideheadings-on-odd-pagewill produce a header on an odd page, which is then matched by the show rule right before it (whe…