2.3 KiB
title |
---|
Making a blog from scratch |
Making a blog from scratch
Let's see how to use achille for making a static site generator for a blog. First we decide what will be the structure of our source directory. We choose the following:
content
└── posts
├── 2020-04-13-hello-world.md
├── 2020-04-14-another-article.md
└── 2020-05-21-some-more.md
We define the kind of metadata we want to allow in the frontmatter header of our markdown files:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Data.Aeson
import Data.Text (Text)
data Meta = Meta
{ title :: Text
} deriving (Generic)
instance FromJSON Meta
This way we enfore correct metadata when retrieving the content of our files. Every markdown file will have to begin with the following header for our generator to proceed:
---
title: Something about efficiency
---
Then we create a generic template for displaying a page, thanks to lucid:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE BlockArguments #-}
import Lucid.Html5
renderPost :: Text -> Text -> Html a
renderPost title content = wrapContent do
h1_ $ toHtml title
toHtmlRaw content
renderIndex :: [(Text, FilePath)] -> Html a
renderIndex = wrapContent .
ul_ . mconcat . map \(title, path) ->
li_ $ a_ [href_ path] $ toHtml title
wrapContent :: Html a -> Html a
wrapContent content = doctypehtml_ do
head_ do
meta_ [charset_ "utf-8"]
title_ "my very first blog"
body_ do
header_ $ h1_ "BLOG"
content_
We define a recipe for rendering every post:
buildPosts :: Task IO [(String, FilePath)]
buildPosts =
match "posts/*.md" do
(Meta title, text) <- compilePandocMetadata
saveFileAs (-<.> "html") (renderPost title text)
<&> (title,)
We can define a simple recipe for rendering the index, given a list of posts:
buildIndex :: [(Text, FilePath)] -> Task IO FilePath
buildIndex posts =
save (renderIndex posts) "index.html"
Then, it's only a matter of composing the recipes and giving them to achille:
main :: IO ()
main = achille do
posts <- buildPosts
buildIndex posts
And that's it, you now have a very minimalist incremental blog generator!