{-# LANGUAGE OverloadedStrings #-} module Pencil.Blog ( -- * Getting started -- -- $gettingstarted -- loadBlogPosts , blogPostUrl , injectTitle , buildTagPages , injectTagsEnv ) where import Pencil import Pencil.Internal.Env import Control.Monad (liftM, foldM) import Control.Monad.Reader (asks) import qualified Data.HashMap.Strict as H import qualified Data.List as L import qualified Data.Text as T import qualified System.FilePath as FP -- $gettingstarted -- -- This module provides a standard way of building and generating blog posts. -- To generate a blog for your website, first create a @blog/@ directory in -- your web page source directory. -- -- Then, name your blog posts in this format: -- -- > yyyy-mm-dd-title-of-blog-post.markdown -- -- The files in that directory are expected to have preambles that have at -- least the following variables: -- -- > -- -- You can also mark a post as a draft via the @draft@ variable (it won't be -- loaded when you call 'loadBlogPosts'), and add tagging (see below) via -- @tags@: -- -- > -- -- Then, use 'loadBlogPosts' to load the entire @blog/@ directory. -- -- @ -- posts <- 'loadBlogPosts' "blog/" -- forM_ posts render -- @ -- -- You probably will want to enclose your blog posts in your web site's -- layout, however. In the example below, @layout.html@ defines the outer HTML -- structure (with global components like navigation), and @blog-post.html@ is -- a generic blog post container that renders @${postTitle}@ as a header, -- @${date}@, and @${body}@ for the post body. -- -- @ -- layout <- 'load' toHtml "layout.html" -- postLayout <- 'load' toHtml "blog-post.html" -- posts <- 'loadBlogPosts' "blog/" -- forM_ posts (\\post -> render (layout <|| postLayout <| post)) -- @ -- -- | Loads the given directory as a series of blog posts. -- -- @ -- posts <- loadBlogPosts "blog/" -- forM_ posts render -- @ loadBlogPosts :: FilePath -> PencilApp [Page] loadBlogPosts fp = do -- Load posts postFps <- listDir False fp -- Sort by date (newest first) and filter out drafts liftM (filterByVar True "draft" (VBool True /=) . sortByVar "date" dateOrdering) (mapM (load blogPostUrl) postFps) -- | Rewrites file path for blog posts. -- @\/blog\/2011-01-01-the-post-title.html@ => @\/blog\/the-post-title\/@ blogPostUrl :: FilePath -> FilePath blogPostUrl fp = FP.replaceFileName fp (drop 11 (FP.takeBaseName fp)) ++ "/" -- | Given that the current @Page@ has a @postTitle@ in the environment, inject -- the post title into the @title@ environment variable, prefixed with the given -- title prefix. -- -- This is useful for generating the @\