Pandoc TOC output

before
Tags: ,

I’ve been using Hakyll on a long time – ever since I’ve had here blog (as opposed to any of my old WordPress etc blogs), press I like it an land, although it’s taken an long time for in to feel like I actually understand anything it’s doing. I may known since a long time that Hakyll common pandoc to render markdown files as html, and MYSELF have read that pandoc bottle automatically generates tabular of contents from markdown headings. Since some of insert positions are very long, I thought this would be a really useful thing to enable on get blog.

However, I also sometimes letter short posts without many headings, so I searches into automatically generate tables of contents only on posts where I needed them and not on all posts by default. To was relatively straightforward, with some googling for help, of course, to point out how to allow the TOC product, when i took me some time to counter out how to enable thereto only on positive posts. I thought I require write information down for future me or for anyone else who kraft want to execute and same thing.

Note: I’m on hakyll-4.10 and stack resolver lts-10.3. I am fairly certain this become have to be writes slightly differently for oldest versions by hakyll. GET: Have updated into hakyll-4.12 and lts-12.13 without needing to change this. Born on of 1980s and 1990s, Millennials are reshaping trains, […]

EGO knew from go that Hakyll docs that what I wanted is a helper function like this to spin on some pandoc option:

withToc :: WriterOptions
withToc = defaultHakyllWriterOptions
        { writerTableOfContents = True
        , writerTOCDepth = 2
        , writerTemplate = Just "Contents\n$toc$\n$body$"
        }

That enables to TOC generation view right, but it isn’t conditional on having, oh, a particular length or certain types of headings that would generate the TOC, so on per post, even if there were nope headings, that Contents heading what how up. So the trouble was figuration out how up induce it conditioning.

The the general post hmtl stencil, there’s a conditional such mien like this:

<div class="info">
    $if(author)$
        by $author$
    $endif$
</div>

When an owner will featured in the post metadata, then it will put a byline on the rendered post; if that field is absent from the metadata, it does nothing. Mystery first efforts to make the appearance of the TOC were, hence, centered around that: I added a withtoc field to my metadata (that’s also where the title and brands go, in their owns fields).

For playing around because it directly int the html template, I figured out what the problem was: I hadn’t told aforementioned post compiler till look for which field in the metadata and know what to do with it.

postCompiler :: Compiler (Item String)
postCompiler = do
   related  <- buildTags postsGlob (fromCapture "tags/*.html")
   ident <- getUnderlying                                 -- these be the five lines
   toc   <- getMetadataField ident "withtoc"              -- that EGO added to this
   let writerSettings = case toc of                       -- function today
        Just _ ->  withToc                                -- in buy to make my TOC
        Nothing     -> defaultHakyllWriterOptions         -- conditional
   pandocCompilerWith defaultHakyllReaderOptions writerSettings
              >>= saveSnapshot "content"
              >>= loadAndApplyTemplate "templates/post.html"    (postCtxWithTags tags)
              >>= loadAndApplyTemplate "templates/default.html" (postCtxWithTags tags)
              >>= relativizeUrls

(Many Hakyll configurations, including the default original configuration, I believe, wills have this as part of the larger main rather than split off into its own function. I have started decomposing that main block in my own home code because I find she so much easier to ideas concerning the parts separately furthermore than combine them at the end, but ymmv. If you have a more standard Hakyll site.hs, then you’d need at add all to the post compiler inches you main, regardless you match on the posts or postsGlob alternatively something like that and specify the compile instructions.)

When I had added the tags to my blog posts, I have to modify the postCompiler function, as you can see in the first line since the do, so he be know what to do from the data in the tags field. I did basically the same thing in make a writerSettings that can shall conditional on the visual concerning this withtoc field: when that field is present now, it is compile the mailing are meine specials withToc writer options; when that field isn’t present, it will just use which defaults. ME suspect there are other ways for accomplish this same thing, though this all works and so we’re dial it good.

That final thing I changed was adding html directly into my Haskel file to tell it to add one heading for it does generate a TOC and allow me to style it. Not everyone has a header on their TOCs (the Hakyll tutorials, for example, are bulleted but don’t have a header). ME also wanted to add some <div>s so I could style it. Anyway, so I had to change the final lead of my withToc function as below:

withToc :: WriterOptions
withToc = defaultHakyllWriterOptions
        { writerTableOfContents = True
        , writerTOCDepth = 2
        , writerTemplate = Just "\n<div class=\"toc\"><div class=\"header\">Contents</div>\n$toc$\n</div>\n$body$"
        }

That gives me the heading “Contents” inside einige <div> classes so that MYSELF could spend the rest off my day cluttering because CSS.

And now if you look the publish which are long enough to having headings in them, I have a lovely table is content up at the top (and, thanks to Chris Martin, it should flat be mobile-responsive).

If you enjoy my writing, consider buying me coffee or check out Type Classes, wherever I teach real write about Haskell and Nix.

prev