📚

Typstでヘッダーに章のタイトルを表示する

2025/01/02に公開

図のように、今のどの章にいるのか、という情報をページのヘッダー(一番上)に表示したいってとき、ありますよね

最初の状態

まず何もしていない状態です。

#set page(numbering: "— 1 —")
#set text(25pt)
#set par(justify: true)


= First Chapter
#lorem(50)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

#pagebreak()

= Second Chapter
#lorem(100)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

ヘッダーを追加する

まず、ヘッダーを追加してみましょう。page.headersetすればできます。

上にI'm a headerって見えましたよね。

見出し情報をヘッダーに入れる

そこに今のheadingの内容を入れたいのです。やり方は色々考えられますが、一つとして、今いるヘッダーの位置の前の章の見出し(第一階層のheading)を選択します。

#set page(
  header: context [
    #set text(10pt)
    #let selector = selector(heading).before(here())
    #let all-headings-before = query(selector)
    #repr(all-headings-before)
  ],
  margin: (top: 50%),
)

このようにすれば、First Chapterがあるページの前は何もないはずで、()になりますが、First SectionからThird Sectionまで、そしてSecond Chapterのページでもは以下のようになります。

(
    heading(
        level: 1,
        depth: 1,
        offset: 0,
        numbering: none,
        supplement: [Section],
        outlined: true,
        bookmarked: auto,
        hanging-indent: auto,
        body: [First Chapter],
    )
)

そして、Second Chapter以下のFirst SectionからThird Section以下のようになるはずです

(
    heading(
        level: 1,
        depth: 1,
        offset: 0,
        numbering: none,
        supplement: [Section],
        outlined: true,
        bookmarked: auto,
        hanging-indent: auto,
        body: [First Chapter],
    ),
    heading(
        level: 1,
        depth: 1,
        offset: 0,
        numbering: none,
        supplement: [Section],
        outlined: true,
        bookmarked: auto,
        hanging-indent: auto,
        body: [Second Chapter],
    ),
)

このように、今のヘッダーにある位置以前のすべての章の見出しを取得できました。

ヘッダーに前の章の body を表示する

そこのその最後にあるやつのbodyを、ヘッダーに出して表示すれば一歩進みます。やってみましょう。


#set page(
  header: context [
    #let selector = heading.where(level: 1).before(here())
    #let all-headings-before = query(selector)

    #if all-headings-before.at(-1, default: none) != none {
      all-headings-before.at(-1).body
    }
  ],
)

#set page(numbering: "— 1 —")
#set text(25pt)
#set par(justify: true)


= First Chapter
#lorem(50)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

#pagebreak()

= Second Chapter
#lorem(100)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

章があるページに前の章が表示される問題を解決

しかし、問題になるのが、3ページ目、Second Chapterの直前、もちろん前の最後のChapterを取り出すわけですから、前の章になっている。これは望ましくないですし、そもそもそのページに章の見出しが見えるのであれば、ヘッダーに章は不要ですので、これを消します。


#set page(
  header: context [
    #let first-heading-selector = heading.where(level: 1)

    #let pages-with-first-level-heading = query(first-heading-selector).map(it => it.location().page())
    #let has-first-level-heading-on-current-page = here().page() in pages-with-first-level-heading

    #let all-headings-before = query(first-heading-selector.before(here()))


    #if not has-first-level-heading-on-current-page and all-headings-before.at(-1, default: none) != none {
      all-headings-before.at(-1).body
    }
  ],
)

#set page(numbering: "— 1 —")
#set text(25pt)
#set par(justify: true)


= First Chapter
#lorem(50)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

#pagebreak()

= Second Chapter
#lorem(100)
== First Section
#lorem(50)
== Second Section
#lorem(50)
== Third Section
#lorem(100)

Discussion