Hakyll, where am I?

Posted on 22 Feb 2015
Tags: meta, haskell

Unlike this particular post, some of the pages on this site are among the pages that are linked to in the header. For reasons of convention and aesthetics, it is nice for this fact to be made visible. If you navigate to one of those pages, you’ll notice that the corresponding link in the header is highlighted in red (at least that was the styling when this was written). When/if you make it back here, you’ll notice that none of the links is highlighted. This is not quite trivial in Hakyll and isn’t covered in the tutorials, so I’ll describe how I did it here.

For each page for which I wanted to enable header highlighting, I modified the corresponding page generation code in site.hs to push a new field onto the Context. For example, for the about page, I changed the following code:

match "about.md" $ do
    route   $ setExtension "html"
    compile $ pandocCompiler
        >>= loadAndApplyTemplate "templates/default.html" defaultContext
        >>= relativizeUrls

to this:

match "about.md" $ do
    let aboutCtx =
            constField "page-about" "" `mappend`
            defaultContext

    route   $ setExtension "html"
    compile $ pandocCompiler
        >>= loadAndApplyTemplate "templates/default.html" aboutCtx
        >>= relativizeUrls

Having to create a new field for each page of interest is inelegant, but there’s no obvious way around it. The problem is that Hakyll’s conditional acts like the C preprocessor’s #ifdef, and as such can’t check for equality. In the jargon of statistics, we have categorical random variable when we might prefer to have an n = 1 multinomial. There may be a way to get the same effect by pushing the (newly-introduced) boolField onto defaultContext, but I haven’t got that working yet.

With the new fields defined, conditionals can be added to templates/default.html to add class="active" to the appropriate header link, as so:

<body>
    <div id="header">
        ...
        <div id="navigation">
            <a href="/"
               $if(page-home)$ class="active" $endif$>Home</a>
            ...
            <a href="/archive.html"
               $if(page-archive)$ class="active" $endif$>Archive</a>
        </div>
    </div>
    ...

Finally, so that this causes a change in presentation, some styling must be added to css/default.css:

div#header #navigation a.active {
    color: #dd0000;
}

There are certainly simpler ways to achieve this goal, for instance, using JavaScript to write to the DOM and modify the page dynamically. But I couldn’t, in good conscience, go against the static nature of my website like that.