packages feed

pencil-1.0.0: examples/Blog/src/Main.hs

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Pencil
import qualified Data.HashMap.Strict as H
import qualified Data.Text as T

websiteTitle :: T.Text
websiteTitle = "My Blog"

config :: Config
config =
  (updateEnv (insertText "title" websiteTitle) .
   setSourceDir "examples/Blog/site/" .
   setOutputDir "examples/Blog/out/"
  ) defaultConfig

website :: PencilApp ()
website = do
  loadAndRender "assets/style.scss"

  layout <- load "layout.html"
  postLayout <- load "post-layout.html"

  -- Load all our blog posts into `posts`, which is of type [Page]
  posts <- loadPosts "blog/"

  -- Build tag index pages. This is a map of a Tag (which is just Text)
  -- to a Page which has the environment stuffed with blog posts that has that
  -- tag.
  tagPages <- buildTagPages "tag-list.html" posts

  -- Render all our blog posts. So for each post in posts, we:
  --
  -- - injectTitle - This generates a `title` variable in our env that has the
  --   format of "post title - My Blog"
  --
  -- - injectTags - This injects some environment variables so that our blog
  --   post page knows what tags it has (via `tags` variable), AND a reference to
  --   the tag index page that we built above (via `this.url`). Look through
  --   post-layout.html to see how to use these tag variables.
  --
  -- - (layout <|| postLayout <|) - We push the generated post Page into this
  --   Structure, so that all blog posts share the same postLayout.
  --
  -- - render - Finally we render all of our blog posts into files.
  --
  render $ fmap ((layout <|| postLayout <|) . injectTags tagPages . injectTitle websiteTitle)
                posts

  -- Load our index page.
  index <- load "index.html"

  -- Build our index page.
  --
  -- - coll "posts" posts - Creates a collection of pages inside the Structure.
  --   The entire structure has access to these pages, via the "posts" variable.
  --
  -- - a <<| c - pushes the collection node c into Structure a.
  --
  render (layout <|| index <<| coll "posts" posts)

  -- Render tag list pages. This is so that we can go to /blog/tags/awesome to
  -- see all the blog posts tagged with "awesome".
  render $ fmap (layout <||) (H.elems tagPages)

  -- Load RSS layout.
  rssLayout <- load "rss.xml"

  -- Build RSS feed of the last 10 posts.
  --
  -- - `struct` converts the Page into a Struct
  --
  -- - `escapeXml` sets the Page to escape the XML/HTML tags in our blog
  --   content, since we're going to render this inside the RSS <description>
  --   tag.
  --
  -- - `coll "posts" ...` creates a collection of pages inside the Structure.
  --   See rss.xml file to see how that's used.
  --
  let rssFeedStruct = struct rssLayout <<| coll "posts" (fmap escapeXml (take 10 posts))

  -- Render the RSS feed. We need to render inside a modified environment, where
  -- @toTextRss@ is used as the render function, so that dates are rendered in
  -- the RFC 822 format, per the RSS specification.
  local (setDisplayValue toTextRss)
        (render rssFeedStruct)

main :: IO ()
main = run website config