Hi, I’m fairly new to Typst and I am currently porting my LaTeX doc over to Typst. The styling of that document has a dynamic headline of the current headline the text belongs to, or the first headline on that page. While trying to achieve just that I have hit a few road blocks which I managed to clear, but this one has some weird behavior with the state-Type I have not been able to figure out.
The code as it is now:
#let ht-first = state("page-first-section", [])
#ht-first.
#set page(header: {
let first-heading = context query(
heading.where(level: 1)).find(h => h.location().page() == here().page())
// find last heading of level 1 on current page
context ht-first.get()
// Title top left
set text(8pt)
place(top + left,smallcaps[#{
context if query(
heading.where(level: 1)).find(h => h.location().page() == here().page()) == none {
context ht-first.at(here())
}
else {
ht-first.update([#heading(first-heading).body])
ht-first.at(here())
}
}], dy: 1.2cm)
// Numbering top right
context place(top + right, text(10pt, numbering(here().page-numbering(), counter(page).at(here()).first())), dy: 1.25cm)
// horizontal line underneath
line(length: 100%)
}
)
The goal here is to dynamically display the first level 1headline of the page, or the last level 1 headline of the previous page-/s. The current headline (as in, defined on that page) does work and will display correctly. I want to store that headline in this state:
#let ht-first = state("page-first-section", [])
For some reason however, the state will be empty by the time the next page without headline comes along. Manually overriding the state on the page using #ht-first.update("Some arbitrary text")
does work for that single page, before going back to the non working state.
Ideally this would also carry over the latest level 1 headline of the previous page, if there is no headline on the current page.
I also found this StackOverflow post that has done this exact thing in the past, however, this does not seem to work anymore.
Any ideas and hints would be greatly appreciated!
Update:
After posting this I, as is usual, thought of the solution, so here is a cleaned up working example of my code:
#set page(header: context
{
// Title top left
set text(10pt)
place(top + left, {
if query(heading.where(level: 1))
.find(h => h.location().page() == here().page()) == none {
// Filter headers that come after the current page
let smh = query(heading.where(level: 1)).filter(h => h.location().page() <= here().page())
smh.last().body // last element in array is newest level 1 headline
} else {
let onPageHeading = query(heading.where(level: 1)).filter(h => h.location().page() == here().page())
onPageHeading.first().body
}
}, dy: 1.25cm)
// Numbering top right
place(top + right, numbering(here().page-numbering(), counter(page).at(here()).first()), dy: 1.25cm)
// horizontal line underneath
line(length: 100%)
})
One question remains, however: Is there a simpler/faster/better solution?