jnb

Using Tufte CSS and org-page

I want to use the Tufte CSS for this blog, but one thing that was annoying me was the display of footnotes. They are actually called sidenotes.

I kind of fixed it by using literal html tags but that makes the org source file unpleasant to read. That in turn means that the html export should be changed to not export the footnotes as some internal anchors but as the format specified in the tufte report, which meant that I had to change the html export.

Looking at an exported footnote, we can see that the footnote section is automatically created. I wasn't able to stop it so I simply changed the command string org-html-footnotes-section to comment it out.

(setq org-html-footnotes-section "<!-- %s --><!-- %s -->")

Then I had to derive a new backend from the html export where I override the footnote-reference. Although I also specified a new function for the footnote-definitions I couldn't prevent the section being printed at the bottom of the article so I still had to comment it out.

Since the construct for a side note is a bit specialIt's an input with the type checkbox that will take the next span element as its content. the function does look a bit weird, but it works for my tastes.

(defun tufte-html-footnote-reference (footnote-reference contents info)
  "Create a footnote according to the tufte css format.
FOOTNOTE-REFERENCE is the org element, CONTENTS is nil.  INFO is
a plist holding contextual information."
  (format "<label for=\"%s\" class=\"margin-toggle sidenote-number\"></label><input type=\"checkbox\" id=\"%s\" class=\"margin-toggle\"/><span class=\"sidenote\">%s</span>"
	  (org-export-get-footnote-number footnote-reference info)
	  (org-export-get-footnote-number footnote-reference info)
	  (org-trim (org-export-data (org-export-get-footnote-definition footnote-reference info) info))))

I mostly looked at the backend for LaTeX exports and copied the code from there when it seemed logical to me.

That took care of the side notes but I still wanted to be able to have margin notes. I realized that with an ugly hack that simply checks the links whether they have the prefix mnfor margin note and then wrap it into the according tags which is similar to the way side notes work. You have to write the links with a unique word after the link for the for and id attribute to not get confusedIt takes the first word of the link. The links should come in the format mn:unique-id.

(defun tufte-html-margin-note-link (link desc info)
  "LINK is the margin note (or not).

If it is not, it willl be passed onto the original function in
order to be handled properly.  DESC is the description part of
the link.  INFO is a plist holding contextual information."
  (let ((path (split-string (org-element-property :path link) ":")))
    (if (and (string= (org-element-property :type link) "fuzzy")
	     (string= (car path) "mn"))
	(format "<label for=\"%s\" class=\"margin-toggle\">&#8853;</label><input type=\"checkbox\" id=\"%s\" class=\"margin-toggle\"/><span class=\"marginnote\">%s</span>"
		(cadr path) (cadr path)
		desc)
    (org-html-link link desc info))))

If there is no match it will simply pass everythin along to the original exporter to not mess anything up.

To finally define the exporter you have to define a derived backend.

(org-export-define-derived-backend 'tufte-html 'html
  :translate-alist '((footnote-reference . tufte-html-footnote-reference)
		     (footnote-definition . tufte-html-footnote-definition)
		     (link . tufte-html-margin-note-link)))

Because I build this blog with org-page I simply had to specify in op-template.el lines 150 and 152 in the version from github. my own exporter; I named it tufte-html. Then I copied the css file into the theme folderspeicied by the variable op/theme-root-directory. into its own folder. The folder was simply a copy of another one, then I only had to replace the file main.css with the contents of tufte.css.

Afterwards I noticed that the source blocks were still styled in the normal org style so I had to write yet another function that simply stuffed the code into a <pre> tag. Of course the backend had to be redefined to override the default function.

(defun tufte-html-src-block (src-block contents info)
  "Transcode an SRC-BLOCK element from Org to HTML.
CONTENTS holds the contents of the item.  INFO is a plist holding
contextual information."
  (format "<pre class=\"code\">%s</pre>"
	  (org-html-format-code src-block info)))

(org-export-define-derived-backend 'tufte-html 'html
  :translate-alist '((footnote-reference . tufte-html-footnote-reference)
		     (footnote-definition . tufte-html-footnote-definition)
		     (link . tufte-html-margin-note-link)
		     (src-block . tufte-html-src-block)))

So far that was everything I did, the next things are probably going to be cleaning up the css a bit. I hope it's useful to someone. The code is in a gist/snippet. Although to me it was kind of interesting to dabble into the org exporters so I consider it a success.