-- | This module provides a simple default configuration which behaves similar
-- to a tool such as the Jekyll static site generator ().
--
-- The idea is that you don't have to write your configuration yourself: you
-- just follow some conventions, and Hakyll does the rest.
--
-- You can generate a site which will serve as a good starting point by running
-- the command-line tool:
--
-- > hakyll-contrib small-blog
--
-- Hakyll will then generate a simple example site for you. The necessary
-- configuration is placed in the @small-blog.hs@ file. Compile and run it to create
-- the demo site:
--
-- > ghc --make small-blog.hs
-- > ./small-blog build
-- > ./small-blog preview
--
-- So, in order to get your site going, you need to follow the conventions for
-- the content on your site.
--
-- Images should be placed in the @images\/@ or @img\/@ folder. The are copied
-- directly. Other static files (but not images) can be placed in @static\/@ or
-- @files\/@. The @favicon.ico@ file is an exception, it is just placed in the
-- top-level directory.
--
-- CSS files should be placed in @css\/@, and JavaScript files in @js\/@.
--
-- Then, we arrive at pages. You can create any number of pages on your site:
-- just create files in one of the documents pandoc supports (@.html@,
-- @.markdown@, @.rst@, @.lhs@...) in the top-level directory.
--
-- These pages may use a number of preconfigured @$key$@'s:
--
-- * @$recentPosts$@: A list of recent posts, displayed from most recent to
-- oldest. By default, 3 posts are shown, altough this can be configured using
-- the 'numberOfRecentPosts' field.
--
-- * @$allPosts$@: A list of all posts, displayed from most recent to oldest.
-- This is very useful for creating an archive page.
--
-- * @$chronologicalPosts$@: Similar to @$allPosts$@, but displays the posts in
-- chronological order.
--
-- For example usage, look at the example site we generated using
-- @hakyll-contrib small-blog@.
--
-- Now, one can wonder where these posts come from. Simple: all pages in the
-- @posts\/@ directory are considered posts. Note that a naming format of
--
-- > posts/year-month-date-title.extension
--
-- is mandatory. An example:
--
-- > posts/2011-06-19-hello-world.markdown
--
-- This allows Hakyll to parse the date easily, among other things. Again, look
-- at the example site for some example posts.
--
-- Additionaly, there is the @templates\/@ folder. This folder holds the
-- templates for your site. For a @small-blog@ configuration, your site should
-- have /exactly/ three templates:
--
-- * @templates\/default.html@: The main template. This should contain your
-- HTML doctype, head, etc.
--
-- * @templates\/post.html@: A template which is applied to every post before
-- it is rendered using the default template.
--
-- * @templates\/post-item.html@: A template which is applied to posts in
-- listings (e.g. @$chronologicalPosts$@).
--
-- Again, the example should clarify things.
--
-- This configuration should be enough to create a small personal website. But,
-- we have only touched the surface of what is possible with Hakyll. For more
-- information, check out the tutorials at:
--
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
module Hakyll.Contrib.SmallBlog
( SmallBlogConfiguration (..)
, defaultSmallBlogConfiguration
, smallBlog
, smallBlogWith
) where
import Control.Arrow ((>>>))
import Text.Pandoc (ParserState, WriterOptions)
import Hakyll
-- | Configuration datatype for the 'smallBlog' ruleset
--
data SmallBlogConfiguration = SmallBlogConfiguration
{ -- | Number of recent posts that are available
numberOfRecentPosts :: Int
, -- | Parser state for pandoc, i.e. read options
parserState :: ParserState
, -- | Writer options for pandoc
writerOptions :: WriterOptions
, -- | Atom feed configuration
atomFeed :: Maybe FeedConfiguration
} deriving (Show)
-- | Defaults for 'SmallBlogConfiguration'
--
defaultSmallBlogConfiguration :: SmallBlogConfiguration
defaultSmallBlogConfiguration = SmallBlogConfiguration
{ numberOfRecentPosts = 3
, parserState = defaultHakyllParserState
, writerOptions = defaultHakyllWriterOptions
, atomFeed = Nothing
}
-- | A default configuration for a small blog
--
smallBlog :: Rules
smallBlog = smallBlogWith defaultSmallBlogConfiguration
-- | Version of 'smallBlog' which allows setting a config
--
smallBlogWith :: SmallBlogConfiguration -> Rules
smallBlogWith conf = do
-- Images and static files
["favicon.ico"] --> copy
["img/**", "images/**"] --> copy
["static/**", "files/**"] --> copy
["js/**", "javascript/**"] --> copy
-- CSS files
["css/*.css", "style/*.css", "stylesheets/*.css"] --> css
-- All templates
["templates/*"] --> template
-- "Dynamic" content
["posts/*"] --> post
-- Top-level pages
["*.markdown", "*.html", "*.rst", "*.lhs"] --> topLevel
-- Rss is optional
case atomFeed conf of
Nothing -> return ()
Just f -> do
match "atom.xml" $ route idRoute
create "atom.xml" $ requireAll_ "posts/*" >>> renderAtom f
return ()
where
-- Useful combinator here
xs --> f = mapM_ (\p -> match p $ f) xs
-- Completely static
copy = route idRoute >> compile copyFileCompiler
-- CSS directories
css = route (setExtension "css") >> compile compressCssCompiler
-- Templates
template = compile templateCompiler
-- Posts
post = do
route $ setExtension "html"
compile $ pageCompilerWith (parserState conf) (writerOptions conf)
>>> applyTemplateCompiler "templates/post.html"
>>> applyTemplateCompiler "templates/default.html"
>>> relativizeUrlsCompiler
-- Top-level pages
topLevel = do
route $ setExtension "html"
compile $ pageCompilerWithFields (parserState conf)
(writerOptions conf) id topLevelFields
>>> applyTemplateCompiler "templates/default.html"
>>> relativizeUrlsCompiler
-- Add the fields we need to top-level pages
topLevelFields = setFieldPostList recentFirst "allPosts"
>>> setFieldPostList (take nRecent . recentFirst) "recentPosts"
>>> setFieldPostList chronological "chronologicalPosts"
-- Create a post list based on ordering/selection
setFieldPostList f k = setFieldPageList f
"templates/post-item.html" k "posts/*"
-- Number of most recent posts to show
nRecent = numberOfRecentPosts conf