on master help sign in
Added a category tutorial.
340b878Jasper Van der Jeugt
examples/categoryblog/hakyll.hs+4−4
@@ -2,12 +2,11 @@ module Main where
2
2
3import Text.Hakyll (hakyll)
3import Text.Hakyll (hakyll)
4import Text.Hakyll.Render
4import Text.Hakyll.Render
5−import Text.Hakyll.Tags (readCategoryMap)
5+import Text.Hakyll.Tags (TagMap, readCategoryMap)
6−import Text.Hakyll.File (getRecursiveContents, directory, removeSpaces)
6+import Text.Hakyll.File (getRecursiveContents, directory, removeSpaces, sortByBaseName)
7import Text.Hakyll.Renderables (createPagePath, createCustomPage, createListingWith, createListing)
7import Text.Hakyll.Renderables (createPagePath, createCustomPage, createListingWith, createListing)
8import Text.Hakyll.Context (ContextManipulation, renderDate)
8import Text.Hakyll.Context (ContextManipulation, renderDate)
9import Text.Hakyll.Util (link)
9import Text.Hakyll.Util (link)
10−import Data.List (sort)
11import Data.Map (toList)
10import Data.Map (toList)
12import Control.Monad (mapM_, liftM, (<=<))
11import Control.Monad (mapM_, liftM, (<=<))
13import Data.Either (Either(..))
12import Data.Either (Either(..))
@@ -17,7 +16,7 @@ main = hakyll $ do
17 directory css "css"
16 directory css "css"
18
17
19 -- Find all post paths.
18 -- Find all post paths.
20− postPaths <- liftM (reverse . sort) $ getRecursiveContents "posts"
19+ postPaths <- liftM (reverse . sortByBaseName) $ getRecursiveContents "posts"
21 let renderablePosts = map createPagePath postPaths
20 let renderablePosts = map createPagePath postPaths
22
21
23 -- Read category map.
22 -- Read category map.
@@ -54,6 +53,7 @@ main = hakyll $ do
54
53
55 categoryToURL category = "$root/categories/" ++ removeSpaces category ++ ".html"
54 categoryToURL category = "$root/categories/" ++ removeSpaces category ++ ".html"
56
55
56+ categoryList :: TagMap -> String
57 categoryList = uncurry categoryListItem <=< toList
57 categoryList = uncurry categoryListItem <=< toList
58
58
59 categoryListItem category posts = "<li>" ++ link category (categoryToURL category)
59 categoryListItem category posts = "<li>" ++ link category (categoryToURL category)
examples/hakyll/css/default.css+6
@@ -83,6 +83,12 @@ div.column p {
83 padding-right: 15px;
83 padding-right: 15px;
84}
84}
85
85
86+img {
87+ display: block;
88+ margin: 10px auto 10px auto;
89+ border: none;
90+}
91+
86ul {
92ul {
87 list-style-type: square;
93 list-style-type: square;
88 padding-left: 1em;
94 padding-left: 1em;
examples/hakyll/images/tutorial6-categories.pngnew file

Binary file not shown.

examples/hakyll/images/tutorial6-tags.pngnew file

Binary file not shown.

examples/hakyll/tutorial6.markdownnew file+87
@@ -0,0 +1,87 @@
1+---
2+title: Tutorial (Part VI)
3+what: explains how to use categories instead of tags
4+---
5+
6+## Categories
7+
8+Most people familiar with "tags" will also know the concept "categories".
9+
10+![Tags illustration]($root/images/tutorial6-tags.png)
11+
12+In fact, tags are harder to implement because they have to be represented as a
13+many-to-many relation, and categories are a simple 1-to-many relation.
14+
15+![Tags illustration]($root/images/tutorial6-categories.png)
16+
17+This is also the reason you can "simulate" categories using tags. In this
18+tutorial we will adapt the blog to use categories instead of tags. Here is
19+[a zip file](examples/categoryblog.zip) containing the files used in this
20+tutorial.
21+
22+## Reading Categories
23+
24+Tags are located in the `tags` metadata field. Since one post can only belong
25+in one category, a different approach was chosen here. The category of a post
26+is determined by the subfolder it is in. Here you see the directory layout for
27+our posts using categories:
28+
29+ posts
30+ |-- coding
31+ | |-- 2009-11-05-a-first-post.markdown
32+ | |-- 2009-11-28-a-third-post.markdown
33+ | `-- 2009-12-04-this-blog-aint-dead.markdown
34+ `-- random
35+ |-- 2009-11-10-another-post.markdown
36+ `-- 2009-12-23-almost-christmas.markdown
37+
38+Because we find all our posts in different subdirectories, sorting them is a
39+little harder: we still want them sorted by date, so it boils down to sorting
40+them by "base name". I hope it does not surprise you Hakyll provides a function
41+for that:
42+
43+~~~~~{.haskell}
44+postPaths <- liftM (reverse . sortByBaseName)
45+ (getRecursiveContents "posts")
46+~~~~~
47+
48+Now, we can use the `readCategoryMap` function instead of `readTagMap`, which
49+has the same signature, but assigns categories based on the folders the posts
50+are in.
51+
52+~~~~~{.haskell}
53+categoryMap <- readCategoryMap "categoryMap" renderablePosts
54+~~~~~
55+
56+The rest of the `hakyll.hs` is very similar to the one in the previous
57+tutorial, except we want to render a category list instead of a tag cloud.
58+
59+## Rendering a category list
60+
61+Because rendering a category list is quite easy, and it would be hard to
62+write a "general" function for this, hakyll does not provide such a function -
63+but it is not hard to write. First, we write an auxiliary function that produces
64+a list item for one category:
65+
66+~~~~~{.haskell}
67+categoryListItem category posts =
68+ "<li>" ++ link category (categoryToURL category)
69+ ++ " - " ++ show (length posts) ++ " items.</li>"
70+~~~~~
71+
72+This is nothing more that some string concatenation. The function that applies
73+this on every element in the `TagMap` is more interesting:
74+
75+~~~~~{.haskell}
76+categoryList :: TagMap -> String
77+categoryList = uncurry categoryListItem <=< toList
78+~~~~~
79+
80+This function might seem a little harder to understand, and figuring out how it
81+works is left as an exercise for the reader[^1].
82+
83+[^1]: Hint: `>>=` is `concatMap` in the list monad.
84+
85+We then add this to our index page, and we are done. Feel free to hack around
86+with the source code. If you still have questions, feel free to ask them at the
87+[google discussion group](http://groups.google.com/group/hakyll).