In this repo you will find the source code for my personal blog where I write about crypto and code. The website is compiled from Markdown files using Hakyll. Hakyll allows you to compose a compiler using a DSL which specifies the rules which transform the inputs to the final output. The source code for my compiler is here.
The project depends on:
-
The stackage build system
Please see the chapter How to install in the official documentation for stack. On macOS I find it easisest to use Homebrew with
brew install haskell-stack. -
The sass SCSS compiler
Install using either Node.js or Homebrew.
npm install -g sass(using Node.js)brew install sass/sass/sass(using Homebrew)
$ stack build
Stack will pull in all the dependencies specified in the cabal file, the correct version of `ghc, and build the compiler.
Pages and blogs are written in static Markdown like the About page. Metadata can be placed in the front matter formatted as YAML. The metadata can be made available both to the compiler and to the template. Page titles are either set explicity in the front matter or derived from the file name.
---
title: This is the blog title
tags: tag1, tag2
image: /img/image.png
summary: |
Introduction to the blog content
---
This is the blog bodyPages in the blog directory are considered to be blog posts which have additional features like pagination, categories and tags. Blog posts are ordered newest to oldest and each post's date is extracted from the date field, the published field or from the a prefix of the filename. Tags are generated from the tags field in the metadata but categories are derived from the parent folder's name. When an image is specified it is used in Twitter summary cards.
Summary is either set explicitly in the front matter, read from the content and upto the <!--more--> comment or derived from the first sentence. Summaryr set in the front matter is used as the description for Twitter summary cards.
Some parts of the site are generated without an existing source using Hakyll combinators like the index page which lists a few of the latest blog.
create ["index.html"] $ do
route $ idRoute
compile $ makeItem ""
>>= loadAndApplyTemplate "templates/blog-list.html" (blogCtx 1 pages categories tags)
>>= loadAndApplyTemplate "templates/default.html" defaultCtx
>>= indexCompiler
>>= relativizeUrlsFor longer blog posts or pages it can be very convenient to include a table of contains. This is simply achieved by defining the withtoc field in the metadata. The compiler now uses <h1></h1> and `
---
title: This is a long blog post
withtoc: true
---Math equations can be written in LaTeX and enclosed in double dollar signs. The equations are rendered by KaTeX.
Decks and presentations are created in a similar fashion to blog files but placed in the decks directory instead. Decks either contain embedded presentation such as Google Slides or marked up and rendered by reveal.js. To enable reveal.js in a presentation the reveal key has to be defined. Optionally a theme key controls which theme should be used to render the presentation.
---
reveal: true
theme: league
featureimage: 2014/06/bitcoin.png
---
Rest of the deckTemplates are found in the templates directory. The base layout is defined in default.html and its $page.body$ variable is replaced by the previous step in the build pipeline. Variables include:
page.bodyfor the content bodypage.urlfor the destination URL of the pagepage.pathfor the original filepath of the pagepage.foowhere foo is specified in the metadatapage.titlefor the page titlepolish(text)to exchange certain words in the text for an emoji
Blog lists has a blogs variable which can be iterated over and these additional variables:
-pages.first.number
-pages.first.url
-pages.next.number
-pages.next.url
-pages.previous.number
-pages.previous.url
-pages.last.number
-pages.last.url
-pages.current.number
-pages.count
Single blog posts have these additions:
blog.titleblog.dateblog.categoryblog.tagsblog.imageblog.next.urlblog.previous.urlblog.summaryblog.reading.time
Deck lists has a decks variable which is a list field and can be iterated over.
Single decks have a theme variable.
For more information about templates including control flow, conditionals, partials and loops, refer to this tutorial.
I have created a script transforms the Markdown to HTML using the compiler. Relevant templates from the templates directory are applied in the build pipeline before the final results are stored in the _site directory.
$ ./build
When working on the content itself it is quite convenient to have a HTTP server which watches which files have been saved recently and compiles the website incrementally. There is also a script for that which binds the server to http://localhost:8000.
$ ./watch