Handling multiple posts, and more
At the moment, my blog is basically a single page. This is boring, so let's expand it to handle multiple pages. Also, each page should be templatized in turn, so that we can add a footer to handle analytics, comments, etc.
I'll do this step by step. First, I'll ignore the index page and just add support for the posts. So
blog.hs gets a new "match" rule.
match "posts/*" $ do route $ setExtension "html" compile $ pageCompiler >>> applyTemplateCompiler "templates/post.html" >>> relativizeUrlsCompiler
index.markdown to explicitly point to the two posts for now (i.e. this one and the previous one).
Also, I created
templates/post.html, which has some basic boilerplate difference from the template used to serve the index page :-
<h1>$$title$$</h1> <br> <h2>$$date$$</h2> <br> $$body$$
ghc –make blog.hs && ./blog preview confirms that all is well.
Analytics and Comments
I'll be brief here, since you probably already know this, and this isn't relevant to hakyll in anyway. There are many commenting systems out there, I found Disqus to be really quick to set up.
Showing a list of posts
At a minimum, we'd like to show the last few posts on the index page, and provide a link to the list of all posts.
Let's do the second item first. To do this, we'll create a pseudo-page that will be defined based on the list of posts found in the
(BTW this is heavily
inspired by copy-pasted from this hakyll example)
Since we want to have a 'list of posts' on the index page as well, this common functionality can be abstracted out.
addPostList :: Compiler (Page String, [Page String]) (Page String) addPostList = setFieldA "posts" $ arr (reverse . chronological) >>> require "templates/postitem.html" (\p t -> map (applyTemplate t) p) >>> arr mconcat >>> arr pageBody
Now create a rudimentary html fragment that will hold the 'post summary'
<li> <a href="$ url $">$ title $</a> - <em>$ date $</em> </li>
Finally, to tie it together, add a match for
posts.html, which will be the entry point to show the list of all posts.
match "posts.html" $ route idRoute create "posts.html" $ constA mempty >>> arr (setField "title" "All posts") >>> requireAllA "posts/*" addPostList >>> applyTemplateCompiler "templates/posts.html" >>> applyTemplateCompiler "templates/default.html" >>> relativizeUrlsCompiler
Showing a subset of all posts on the index page
Initially, I had some trouble getting this to work, for some reason the ```match "posts/*"``` wasn't working, and I commented out the ```match "index.html"``` and retained the ```index.markdown``` that I had.
Turned out to be another ommission on my part, I had to replace
match "index.html" $ do create "index.html" $ constA mempty
match "index.html" $ route idRoute create "index.html" $ constA mempty
... and then it works!
Getting the list of the last (say) 3 posts is achieved by having a line similar to the one in the handler for ```posts.html```, except instead of just
>>> requireAllA "posts/*" addPostList
we now have
>>> requireAllA "posts/*" (id *** arr (take 3 . reverse . chronological) >>> addPostList)
You probably know more about this than me, but if you don't want a black-and white, crammed together bunch of text, you probably want atleast a couple of css rules for your headers and the body text etc. I cobbled together mine based on some random examples I found online, pick yours as you see fit.