Build a navigation sidebar using the page tree

Hello! I am very new to Pollen and everything about Racket. I wrote an (yet) unpublished novel, and I was looking for a tool such as Pollen for ages because I wanted precise semantic markup, and a single source file for any output. Big thanks to Matthew and contributors for having created and released Pollen!

But let’s stop the digressions. Regarding my issue…

I have followed the tutorials and have been able to build an HTML page using custom tags and template. The chapters render nicely.

Now, I would like to include the page tree in the page, to help the user navigate between my book chapters.

Unfortunately, I didn’t find any magical helper in the tutorials nor the docs. So I assumed I had to build it myself using the existing pagetree functions. My research led me to this code snippet inside my template.html.p:

        ◊(pagetree->list (current-pagetree))

I currently have two files listed in the index.ptree: chapitre1.html and chapitre2.html.

From what I understand from the manual, pagetree->list gives this result: '(chapitre1.html chapitre2.html) which then translates to chapitre1.htmlchapitre2.html in the final render.

My objective is to encapsulate the elements in a <a href="srcref">Pretty chapter name</a> and other HTML markup (<ol> and such), with “Pretty chapter name” either a static title defined in the pagetree (would it be possible?) or in a variable inside the linked document (it seems not very efficient).

How can I achieve that? I would be very thankful to have code snippets to improve in writing in the racket / pollen syntax.

In general, you would want to do something similar to what I do for my own site – namely, to recurse on the structure of the pagetree.

If you don’t have nested pagetrees, then you can take the simpler approach of mapping each node into an X-expression.

1 Like

I strongly recommend installing the pollen-tfl sample project and reading through how it works. The template.html.p file contains a function called make-subnav that does most of what you want.


flirora, mbutterick, Thank you!

Before your answers, I have tried using a for loop on my page tree items, but I have not been successful in creating the X-expressions for the template.

I’m gonna check both of your source code and try harder to build this navigation for my project!

After a few hours of intense battle with my code, I could create a basic table of content and provide basic links.

For now, flirora’s approach is a bit too overwhelming for a novice like me to study, so I checked out mbutterick’s simpler one.

I still struggle a lot on the right syntax to use (I tried to conditionally include an element keyword by using an if, but to no avail; I gave up on the idea and simply set an empty string as the value when the condition is not met.). But for now, I’m gonna get some rest on the code part after reading so much source code and references, and focus on the content! :blush:

Here’s the result of my experiments (a little bit messy, but it works):

  (titre-chapitre chapitre)
  (or (select-from-metas 'title chapitre) (symbol->string chapitre)))
◊(define here-title (titre-chapitre here))

◊(define (make-side-nav id url text)
  ◊div[#:class "nav-outer" #:id id]{◊a[#:href (symbol->string url)]{◊text}})

◊(define (make-chapternav chapitres)
  (apply ul #:class "subnav"
    (for/list ([child (in-list chapitres)])
          #:aria-disabled "true"
          #:href (if (equal? child here) "#" (symbol->string child))
          #:class (if (equal? child here) "disabled" "")
        ]{◊(titre-chapitre child)}

... and:

        ◊(define wwww
            ◊(make-chapternav (pagetree->list (current-pagetree)))
            ◊(if prev-page ◊make-side-nav["prev" prev-page]{<} "")
            ◊(if next-page ◊make-side-nav["next" next-page]{>} "")
        ◊(->html wwww)

Thank you again!