Hello,
I also want to generate html files from json (a feature which surprisingly few static site generators support), so I expanded your stub above into a working example (code below). I have a few questions though:
Is there a more elegant and general way to generate the Contexts (and maybe even the data types)? Fortunately my json files are not that complicated, but the current approach feels clumsy and tedious and is not really scalable.
I think using non-String Contexts might have some drawbacks, eg. when chaining templates, my journalCtx can only be used once (and must be the first one). So I guess using Context String might be better, but I don't know how to do that (and how to inject the real data into the context if I'm using a makeItem ""). Any ideas?
thanks in advance
paul
-- journal.json
{ "issue": "1/2020"
, "year" : 2020
, "content":
[ {"title": "Editorial", "author":"me", "page":2}
, {"title": "Hakyll Tutorial", "author": "Jasper", "page":4}
]
}
-- templates/journal.html
<h1>$title$</h1>
Issue $issue$
<ul>
$for(content)$
<li>Title=$title$ from $author$ (Page $page$)</li>
$endfor$
</ul>
-- site.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Hakyll
import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as B
import Data.Maybe
main :: IO ()
main = do
hakyll $ do
match "templates/*" $ compile templateBodyCompiler
match "journal.json" $ do
route $ setExtension "html"
compile $ do
res <- getResourceLBS
d <- withItemBody (pure . decode) res :: Compiler (Item (Maybe Journal))
let h = fromJust (itemBody d)
makeItem h
>>= loadAndApplyTemplate "templates/journal.html" journalCtx
>>= loadAndApplyTemplate "templates/default.html" defaultContext
>>= relativizeUrls
data Journal =
Journal { issue :: String
, year :: Int
, pages :: Int
, content :: [Article]
} deriving (Show,Generic,FromJSON,ToJSON)
data Article =
Article { title :: String
, author :: String
, page :: Int
} deriving (Show,Generic,FromJSON,ToJSON)
articleCtx :: Context Article
articleCtx =
field "title" (return . title . itemBody)
<> field "author" (return . author . itemBody)
<> field "page" (return . show . page . itemBody)
journalCtx :: Context Journal
journalCtx =
field "issue" (return . issue . itemBody)
<> field "year" (return . show . year . itemBody)
<> field "pages" (return . show . pages . itemBody)
<> listFieldWith "content" articleCtx (return . (\ j ->
sequence $ Item "article" (content $ itemBody j)))
<> titleField "title"