on master help sign in
Added tagblog example (tutorial coming up).
699bd00Jasper Van der Jeugt
examples/rssblog/hakyll.hs+6
@@ -16,6 +16,12 @@ main = hakyll $ do
16 postPaths <- liftM (reverse . sort) $ getRecursiveContents "posts"
16 postPaths <- liftM (reverse . sort) $ getRecursiveContents "posts"
17 let renderablePosts = map createPagePath postPaths
17 let renderablePosts = map createPagePath postPaths
18
18
19+ -- Render index, including recent posts.
20+ let recentPosts = renderAndConcat "templates/postitem.html" $ take 3 renderablePosts
21+ renderChain ["index.html", "templates/default.html"] $
22+ createCustomPage "index.html" ("templates/postitem.html" : take 3 postPaths)
23+ [("title", Left "Home"), ("posts", Right recentPosts)]
24+
19 -- Render all posts list.
25 -- Render all posts list.
20 let postItems = renderAndConcat "templates/postitem.html" $ renderablePosts
26 let postItems = renderAndConcat "templates/postitem.html" $ renderablePosts
21 renderChain ["posts.html", "templates/default.html"] $
27 renderChain ["posts.html", "templates/default.html"] $
examples/tagblog/css/default.cssnew file+17
@@ -0,0 +1,17 @@
1+body {
2+ width: 600px;
3+ margin: 0px auto 0px auto;
4+}
5+
6+div#navigation {
7+ text-align: center;
8+ border-bottom: 4px solid black;
9+}
10+
11+div#navigation a {
12+ color: white;
13+ text-decoration: none;
14+ background-color: black;
15+ padding: 3px 10px 3px 10px;
16+ margin: 0px 10px 0px 10px;
17+}
examples/tagblog/hakyll.hsnew file+69
@@ -0,0 +1,69 @@
1+module Main where
2+
3+import Text.Hakyll (hakyll)
4+import Text.Hakyll.Render
5+import Text.Hakyll.Tags (readTagMap, renderTagCloud, renderTagLinks)
6+import Text.Hakyll.File (getRecursiveContents, directory, removeSpaces)
7+import Text.Hakyll.Renderables (createPagePath, createCustomPage)
8+import Text.Hakyll.Context (ContextManipulation, renderDate)
9+import Data.List (sort)
10+import Data.Map (toList)
11+import Control.Monad (mapM_, liftM)
12+import Data.Either (Either(..))
13+
14+main = hakyll $ do
15+ -- Static directory.
16+ directory css "css"
17+
18+ -- Find all post paths.
19+ postPaths <- liftM (reverse . sort) $ getRecursiveContents "posts"
20+ let renderablePosts = map createPagePath postPaths
21+
22+ -- Read tag map.
23+ tagMap <- readTagMap postPaths
24+
25+ -- Render all posts list.
26+ renderPostList "posts.html" "All posts" postPaths
27+
28+ -- Render post list per tag
29+ mapM_ (\(tag, posts) -> renderPostList (tagToURL tag) ("Posts tagged " ++ tag) posts)
30+ (toList tagMap)
31+
32+ -- Render index, including recent posts.
33+ let recentPosts = renderAndConcatWith postManipulation
34+ "templates/postitem.html"
35+ (take 3 renderablePosts)
36+ renderChain ["index.html", "templates/default.html"] $
37+ createCustomPage "index.html" ("templates/postitem.html" : take 3 postPaths)
38+ [("title", Left "Home"), ("posts", Right recentPosts)]
39+
40+ -- Render all posts.
41+ mapM_ (renderChainWith postManipulation
42+ ["templates/post.html"
43+ ,"templates/default.html"
44+ ]) renderablePosts
45+
46+ -- Render rss feed
47+ let recentRSSItems = renderAndConcat "templates/rssitem.xml" $ take 3 renderablePosts
48+ let rssPage = createCustomPage "rss.xml"
49+ ("templates/postitem.html" : take 3 postPaths)
50+ [("items", Right recentRSSItems)]
51+ renderChain ["templates/rss.xml"] rssPage
52+
53+ -- Render index.
54+ renderChain ["templates/default.html"] $ createPagePath "index.html"
55+
56+ where postManipulation :: ContextManipulation
57+ postManipulation = renderDate "date" "%B %e, %Y" "Date unknown"
58+ . renderTagLinks tagToURL
59+
60+ tagToURL tag = "/tags/" ++ removeSpaces tag ++ ".html"
61+
62+ renderPostList url title posts = do
63+ let postItems = renderAndConcatWith postManipulation
64+ "templates/postitem.html"
65+ (map createPagePath posts)
66+ customPage = createCustomPage url
67+ ("templates/postitem.html" : posts)
68+ [("title", Left title), ("posts", Right postItems)]
69+ renderChain ["posts.html", "templates/default.html"] customPage
examples/tagblog/index.htmlnew file+14
@@ -0,0 +1,14 @@
1+<div id="posts">
2+ <h1>Recent posts</h1>
3+ <ul>
4+ $posts
5+ </ul>
6+ <a href="/posts.html">All posts...</a>
7+</div>
8+
9+<div class="about">
10+ <h1>About</h1>
11+ <p>
12+ This is a sample blog for educational purposes.
13+ </p>
14+</div>
examples/tagblog/posts.htmlnew file+4
@@ -0,0 +1,4 @@
1+<h1>$title</h1>
2+<ul>
3+ $posts
4+</ul>
examples/tagblog/posts/2009-11-05-a-first-post.markdownnew file+21
@@ -0,0 +1,21 @@
1+---
2+title: A first post
3+author: Julius Caesar
4+tags: caesar, random crap
5+---
6+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pretium leo
7+adipiscing lectus iaculis lobortis. Vivamus scelerisque velit dignissim metus
8+gravida sit amet dapibus ligula tempor. Quisque sit amet viverra nunc.
9+Suspendisse cursus elementum ante, ut venenatis nisi dictum eu. Nulla diam
10+ligula, eleifend in varius quis, malesuada a nibh. Vivamus consequat
11+pellentesque erat non blandit. Nunc sit amet eros vel massa semper ullamcorper
12+quis iaculis magna. Vestibulum ullamcorper urna sit amet est elementum
13+pulvinar. Vestibulum consequat lacus ac quam hendrerit tincidunt. Praesent
14+bibendum vehicula diam, nec sagittis risus tempus a. Nulla quis odio sit amet
15+odio vehicula cursus ut id odio. Curabitur semper magna euismod magna mollis
16+venenatis. Nunc eget eleifend velit. Mauris sed posuere sem. Fusce id nunc
17+nisi, a aliquam orci. Suspendisse laoreet justo non enim laoreet eget consequat
18+velit porttitor. Aenean faucibus sodales metus at tincidunt. Donec vestibulum
19+leo pulvinar erat auctor ac ultrices massa euismod. Phasellus blandit cursus
20+magna, eget lacinia mi lobortis sed. Suspendisse ultricies enim ligula, vel
21+scelerisque mauris.
examples/tagblog/posts/2009-11-10-another-post.markdownnew file+15
@@ -0,0 +1,15 @@
1+---
2+title: Another post
3+author: Marcus Tullius Cicero
4+tags: cicero, random crap
5+---
6+Vestibulum in ultrices urna. Etiam tempor enim dui, nec malesuada elit. Donec
7+tempor ligula et quam volutpat quis fermentum eros congue. Sed ut pulvinar sem.
8+Sed aliquam ipsum id purus sollicitudin vulputate. Cras et mauris dui, vel
9+hendrerit leo. Ut metus ipsum, fermentum ac malesuada id, tempus pharetra quam.
10+Donec diam felis, consequat ac scelerisque cursus, gravida non lectus. Sed
11+faucibus elit dapibus diam elementum id varius nisi tristique. Proin consequat
12+faucibus neque in aliquam. Vestibulum ligula odio, pulvinar vel hendrerit
13+vitae, egestas ut nibh. Praesent ut velit elit, in consequat dolor. Praesent
14+sem enim, commodo in gravida sed, adipiscing vel eros. Lorem ipsum dolor sit
15+amet, consectetur adipiscing elit. Proin non aliquam nunc.
examples/tagblog/posts/2009-11-28-a-third-post.markdownnew file+19
@@ -0,0 +1,19 @@
1+---
2+title: A third post
3+author: Publius Ovidius Naso
4+tags: epic fail, ovidius
5+---
6+Pellentesque tempor blandit elit, vel ultricies arcu congue egestas. Fusce
7+vitae rutrum nisl. Fusce id mauris libero, a venenatis tellus. Fusce iaculis,
8+lorem et ornare molestie, mauris risus mollis nisi, non fermentum lacus lacus
9+sit amet ipsum. Praesent lobortis ullamcorper dolor, eget convallis ligula
10+dignissim a. Suspendisse nulla nisi, congue et pharetra vel, convallis non
11+libero. Ut a nulla ipsum. Phasellus cursus velit id neque viverra ut
12+pellentesque justo posuere. Curabitur laoreet enim et velit tempor consectetur.
13+Donec eu pretium urna. Suspendisse vitae nisi at metus vestibulum aliquam in
14+sit amet nisl. Donec convallis lacinia odio, vestibulum molestie nunc feugiat
15+a. Suspendisse vehicula, sapien id aliquet consectetur, sem sapien ullamcorper
16+arcu, scelerisque porttitor elit ipsum posuere ligula. Nulla at velit eu metus
17+tincidunt auctor ut sit amet enim. Donec placerat dapibus nisi id facilisis.
18+Maecenas pellentesque pulvinar auctor. Curabitur gravida quam sit amet purus
19+consectetur blandit.
examples/tagblog/posts/2009-12-04-this-blog-aint-dead.markdownnew file+12
@@ -0,0 +1,12 @@
1+---
2+title: This blog ain't dead
3+author: Marcus Antonius
4+tags: epic fail, antonius
5+---
6+Etiam non felis aliquet tellus dictum vestibulum. Aliquam accumsan mauris non
7+lacus ultricies nec lacinia enim rhoncus. Curabitur vel tortor massa, elementum
8+tincidunt elit. Maecenas venenatis luctus arcu ut ullamcorper. Donec interdum
9+dolor eu enim tristique vel vehicula risus mollis. Nunc nec tortor quam. Nulla
10+a mauris arcu. Phasellus venenatis tortor vel odio tincidunt consequat. Integer
11+venenatis nibh vitae lectus laoreet eu feugiat nunc pretium. Integer nec turpis
12+metus, in fermentum lorem.
examples/tagblog/posts/2009-12-23-almost-christmas.markdownnew file+13
@@ -0,0 +1,13 @@
1+---
2+title: Almost Christmas!
3+author: Publius Vergilius Maro
4+tags: christmas, random crap
5+---
6+Morbi tincidunt eleifend ante, eu gravida ante rutrum vel. Nunc bibendum nulla
7+tellus, eget egestas sapien. Nam rhoncus interdum libero, eget congue orci
8+imperdiet eu. Quisque pellentesque fringilla urna, ac venenatis ante ultricies
9+et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames
10+ac turpis egestas. Mauris eleifend sagittis ultrices. Quisque ultrices accumsan
11+nisl, sed pellentesque metus porta vitae. Nulla facilisi. In et nibh tincidunt
12+mi volutpat pellentesque vitae nec sapien. Integer massa ipsum, pellentesque in
13+elementum at, cursus sit amet diam.
examples/tagblog/templates/default.htmlnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5+ <head>
6+ <title>SimpleBlog - $title</title>
7+ <link rel="stylesheet" type="text/css" href="/css/default.css" />
8+ <link rel="alternate"
9+ type="application/rss+xml"
10+ title="SimpleBlog"
11+ href="http://example.com/rss.xml" />
12+ </head>
13+ <body>
14+ <h1>SimpleBlog - $title</h1>
15+ <div id="navigation">
16+ <a href="/index.html">Home</a>
17+ <a href="/posts.html">All posts</a>
18+ </div>
19+
20+ $body
21+ </body>
22+</html>
examples/tagblog/templates/post.htmlnew file+5
@@ -0,0 +1,5 @@
1+<h1>$title</h1>
2+by <em>$author</em> on <strong>$date</strong>
3+<div>Tagged as: $tags.</div>
4+
5+$body
examples/tagblog/templates/postitem.htmlnew file+4
@@ -0,0 +1,4 @@
1+<li>
2+ <a href="/$url">$title</a>
3+ - <em>$date</em> - by <em>$author</em>
4+</li>
examples/tagblog/templates/rss.xmlnew file+9
@@ -0,0 +1,9 @@
1+<?xml version="1.0" ?>
2+<rss version="2.0">
3+ <channel>
4+ <title>The SimpleBlog</title>
5+ <link>http://example.com</link>
6+ <description>Simple blog in hakyll</description>
7+ $items
8+ </channel>
9+</rss>
examples/tagblog/templates/rssitem.xmlnew file+5
@@ -0,0 +1,5 @@
1+<item>
2+ <title>$title</title>
3+ <link>http://example.com/$url</link>
4+ <description>$title by $author</description>
5+</item>
src/Text/Hakyll/File.hs+16−2
@@ -4,6 +4,7 @@ module Text.Hakyll.File
4 ( toDestination
4 ( toDestination
5 , toCache
5 , toCache
6 , toURL
6 , toURL
7+ , removeSpaces
7 , makeDirectories
8 , makeDirectories
8 , getRecursiveContents
9 , getRecursiveContents
9 , havingExtension
10 , havingExtension
@@ -15,18 +16,31 @@ import System.Directory
15import System.FilePath
16import System.FilePath
16import Control.Monad
17import Control.Monad
17
18
19+-- | Auxiliary function to remove pathSeparators form the start. We don't deal
20+-- with absolute paths here.
21+removeLeadingSeparator :: FilePath -> FilePath
22+removeLeadingSeparator [] = []
23+removeLeadingSeparator p@(x:xs) | x `elem` pathSeparators = xs
24+ | otherwise = p
25+
18-- | Convert a relative filepath to a filepath in the destination (_site).
26-- | Convert a relative filepath to a filepath in the destination (_site).
19toDestination :: FilePath -> FilePath
27toDestination :: FilePath -> FilePath
20−toDestination path = "_site" </> path
28+toDestination path = "_site" </> (removeLeadingSeparator path)
21
29
22-- | Convert a relative filepath to a filepath in the cache (_cache).
30-- | Convert a relative filepath to a filepath in the cache (_cache).
23toCache :: FilePath -> FilePath
31toCache :: FilePath -> FilePath
24−toCache path = "_cache" </> path
32+toCache path = "_cache" </> (removeLeadingSeparator path)
25
33
26-- | Get the url for a given page.
34-- | Get the url for a given page.
27toURL :: FilePath -> FilePath
35toURL :: FilePath -> FilePath
28toURL = flip addExtension ".html" . dropExtension
36toURL = flip addExtension ".html" . dropExtension
29
37
38+-- | Swaps spaces for '-'.
39+removeSpaces :: FilePath -> FilePath
40+removeSpaces = map swap
41+ where swap ' ' = '-'
42+ swap x = x
43+
30-- | Given a path to a file, try to make the path writable by making
44-- | Given a path to a file, try to make the path writable by making
31-- all directories on the path.
45-- all directories on the path.
32makeDirectories :: FilePath -> IO ()
46makeDirectories :: FilePath -> IO ()
src/Text/Hakyll/Tags.hs+2−1
@@ -56,5 +56,6 @@ renderTagCloud tagMap urlFunction minSize maxSize =
56renderTagLinks :: (String -> String) -- ^ Function that produces an url for a tag.
56renderTagLinks :: (String -> String) -- ^ Function that produces an url for a tag.
57 -> ContextManipulation
57 -> ContextManipulation
58renderTagLinks urlFunction = renderValue "tags" "tags" renderTagLinks'
58renderTagLinks urlFunction = renderValue "tags" "tags" renderTagLinks'
59− where renderTagLinks' = B.pack . intercalate ", " . map urlFunction
59+ where renderTagLinks' = B.pack . intercalate ", "
60+ . map (\t -> link t $ urlFunction t)
60 . map trim . split "," . B.unpack
61 . map trim . split "," . B.unpack