Pelican Margin Notes with Pandoc

Dheepak Krishnamurthy

Published on

Update

I’ve made additional changes to javascript and css since the writing of this post, including an update to the filters and the use of Pelican’s HTML reader to perform some additional fixes. Margin notes match their intended location a lot more closely now. I’ll possibly add another post describing these changes.

Introduction

I’ve been inspired by a few other blogs to consider adding margin notes to this theme. This theme is called pelican-smoothie and is freely available on Github. As you may have guessed from the name, this is a theme for Pelican, a static site generator powered by Python. Pelican allows you to write posts in Markdown or RestructuredText, and convert them into structured and beautiful websites. There are a few advantages of using a static site generator instead of a Content Management System (CMS) like WordPress, and I have covered it briefly in this post. Since Pelican is an open source project, it is inherently pretty customization. I can almost guarantee if you think of a feature that you’d like, you’ll be able to search for a plugin that does exactly that. There is in fact a collection of pelican-plugins. Their maintainer @justinmayer is also very responsive to feature requests and pull requests.

And, on the rare occasion that you can’t find a plugin that does exactly what you want it to, you’ll be able to (with a little bit of research) create a plugin to do exactly just that. Their documentation is pretty good too. If you are looking at a creating a blog I highly recommend checking out Pelican.

That’s probably not why you are reading this post though. You are probably interested in getting margin notes working on your blog too. I’ll have to caveat the following post by saying that this is a proof of concept and by no means a final stable version that you can deploy on your site. This approach worked for me, and the reason I went down this path was because I was curious to see how far I could push my static site generation workflow.

Setup

Firstly, I’m not using Pelican’s built in reader for Markdown files, but instead am using Pandoc. I wrote a pretty long post on using Pandoc for academic writing; I think it’s safe to say that I’m a fan of Pandoc. Pelican has better built-in support for RestructuredText compared to Markdown, but plugins allow you to do pretty much everything you want with Markdown as your source file format. However the number of plugins required to get everything you want working quickly adds up1. I’ve used Pandoc for other projects before and wanted to see if I could get it working in my blogging workflow. I’ve since incorporated Pandoc and it seems to be working quite well. Getting jupyter notebooks working with Pandoc was a bit of challenge though, but I was able to get past it by writing a filter for converting Jupyter notebooks with Pandoc.

And as I mentioned earlier, one of the main purposes of this implementation was because I was curious to see how far I could push this static site generation workflow. So if you are not using Pandoc in Pelican, you will not be able to use this theme with margin notes straight away2. So, the short version is that this implementation of margin notes employs Pandoc, filters with Pandoc using the pandocfilters package and this current specific theme.

Inspiration

A list of blogs, posts, websites, web books have inspired this implementation. Most notably are the following articles – tuftle-css and this article published on Medium about Medium sidenotes. They both speak to some length on how margin notes can be used to improve the experience for a reader, especially on the web. Butterick’s Practical Typography is also a great example of effective use of margin notes. There are a few other articles [1], [2] that talk about this; I’ve added citations to these articles below in case you are interested. The CSS for this page and the CSS for the margin notes have been heavily inspired by gameprogrammingpatterns.com.

Implementation

At the time of writing this article, Pandoc does not support creating margin notes for HTML documents. Pandoc does however support footnotes in the form of footnotes and inline notes. Inline notes are different for traditional footnotes in the source document. The following is an example of footnotes in Pandoc Markdown.


Here is a footnote reference,[^1] and another.[^longnote]

[^1]: Here is the footnote.

[^longnote]: Here's one with multiple blocks.

    Subsequent paragraphs are indented to show that they
belong to the previous footnote.

        { some.code }

    The whole paragraph can be indented, or just the first
    line.  In this way, multi-paragraph footnotes work like
    multi-paragraph list items.

This paragraph won't be part of the note, because it
isn't indented.

The following is an example of inline footnotes in Pandoc Markdown.

Here is an inline note.^[Inlines notes are easier to write, since
you don't have to pick an identifier and move down to type the
note.]

As described in the example, inline notes are easier to write. Pandoc also conveniently also supports filters. They allow for additional functionality to be added by walking through the Abstract Syntax Tree, and parsing or modifying information. I chose the following syntax for implementing a aside tag when converting from a Markdown file to a HTML document.

This is an example for the syntax^[__aside__: This is a note that will appear in a tag] in Markdown.

When run through the filter, the above will be rendered as the following html.

<p>This is an example for the syntax<span id='aside-0'></span> in Markdown.</p>
<div id='div-aside-0'>
    <aside id='aside-0'>This is a note that will appear in a tag</aside>
</div>

The location of the footnote is replaced with a <span> tag, and an <aside> tag wrapped in a <div> tag is added to the end of the paragraph. This filter will also assign id to the <span>, <aside> and <div> tags sequentially. Additional functionally can be added here, but for now this seems to work for my purposes.

With the HTML generated with <aside> tags, it is now a question of assigning the right css. This turned out to be more tricky than I originally anticipated. The current theme uses bootstrap and the following layout to display content.

<div class='row'>
    <div class='col-sm-8'></div> <div class='col-sm-4'></div>
</div>

Because of the way Pelican and Jinja work, and because of how Pandoc returns the content to Pelican, the entire article content is stored in the first <div> element of width 8 units. Ideally, each paragraph would be wrapped in <div> elements of one class, with <aside> elements wrapped in a neighboring div class. With the current structure of Pelican, the only way I could do that is by injecting <div> elements all over the place using something like beautifulsoup. However I decided against it for now, and am using CSS to move the <aside> elements outside the element they are currently positioned in. Since the <aside> elements are located below the actual paragraph, I added javascript to move them up by their height. A better implementation could use the location of the <span> elements to fix the position of the notes.

Conclusions

I’m sure there are definitely better ways to do the same thing, but this is what worked for now. There are a few limitations in the current implementation. One noticeable flaw is that I cannot have one margin note and one footnote in the same paragraph. And I’m positive there are more. Hopefully I’ll get a chance to work on this more to improve it in the near future. All the code is on GitHub in case you were curious and wanted to take a look at it. If you have thoughts on how this could be done better or would like to ask questions in general, I’m open to chatting about this.

References

[1] J. Jameson, “Responsive Sidenotes.”.

[2] J. Gruber, “Notes on notes.”.


  1. Not that’s a bad thing. The way Pelican signals works I believe will only activate a plugin if it has to, so it doesn’t slow down your deployment process.

  2. You will still be able to use this theme, either with Pandoc or Pelican’s default readers, however as you might see later in the post, I use aside tag elements for side notes or margin notes and I haven’t been able to find a plugin that does just that


Comments