summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--blog.cabal5
-rw-r--r--blog.nix4
-rw-r--r--lists/default.md.do41
l---------lists/dirty-haskell/0011
l---------lists/dirty-haskell/0021
-rw-r--r--lists/dirty-haskell/title1
l---------lists/zz_all/0011
l---------lists/zz_all/0021
l---------lists/zz_all/0031
-rw-r--r--lists/zz_all/title1
-rw-r--r--provider/css/default.css40
-rw-r--r--provider/index.html8
-rw-r--r--provider/index.md3
-rw-r--r--provider/posts/blog-documentation.md (renamed from posts/blog-documentation.md)8
-rw-r--r--provider/posts/blog-rss.md (renamed from posts/blog-rss.md)6
-rw-r--r--provider/posts/pwutil.md (renamed from posts/pwutil.md)5
-rw-r--r--provider/templates/default.html22
-rw-r--r--provider/templates/index.html9
-rw-r--r--provider/templates/post-list.html7
-rw-r--r--provider/templates/tag.html2
-rw-r--r--src/Site.hs123
-rw-r--r--templates/default.html55
23 files changed, 234 insertions, 113 deletions
diff --git a/.gitignore b/.gitignore
index c4a847d..f36f933 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
1/result 1/result
2/_cache/
3/_site/
diff --git a/blog.cabal b/blog.cabal
index b8daa19..c014a21 100644
--- a/blog.cabal
+++ b/blog.cabal
@@ -17,7 +17,12 @@ build-type: Simple
17cabal-version: >=1.10 17cabal-version: >=1.10
18 18
19executable site 19executable site
20 default-language: Haskell2010
20 hs-source-dirs: src 21 hs-source-dirs: src
21 main-is: Site.hs 22 main-is: Site.hs
22 build-depends: base >=4.7 && <4.8 23 build-depends: base >=4.7 && <4.8
23 , hakyll >=4.6 && <5 24 , hakyll >=4.6 && <5
25 , containers >=0.5 && <0.6
26 , pandoc >=1.13 && <2
27 , data-default >=0.5 && <0.6
28 , filepath >=1.3 && <2
diff --git a/blog.nix b/blog.nix
index 52e23ca..a4c5d8c 100644
--- a/blog.nix
+++ b/blog.nix
@@ -1,7 +1,7 @@
1# This file was auto-generated by cabal2nix. Please do NOT edit manually! 1# This file was auto-generated by cabal2nix. Please do NOT edit manually!
2 2
3{ mkDerivation, stdenv 3{ mkDerivation, stdenv
4, hakyll 4, hakyll, containers, pandoc, data-default, filepath
5}: 5}:
6 6
7mkDerivation { 7mkDerivation {
@@ -11,7 +11,7 @@ mkDerivation {
11 isExecutable = true; 11 isExecutable = true;
12 isLibrary = false; 12 isLibrary = false;
13 buildDepends = [ 13 buildDepends = [
14 hakyll 14 hakyll containers pandoc data-default filepath
15 ]; 15 ];
16 license = stdenv.lib.licenses.publicDomain; 16 license = stdenv.lib.licenses.publicDomain;
17} 17}
diff --git a/lists/default.md.do b/lists/default.md.do
deleted file mode 100644
index 55abe6f..0000000
--- a/lists/default.md.do
+++ /dev/null
@@ -1,41 +0,0 @@
1#!/usr/bin/env bash
2redo-ifchange "$2/title"
3
4POSTS=()
5while read -r -d $'\0'; do
6 post=$(realpath --relative-to=. "$REPLY")
7 POSTS+=("$post")
8done < <(find "$2" -maxdepth 1 -mindepth 1 -not -name 'title' -not -name 'preview' -print0 | sort -z)
9
10for x in "${POSTS[@]}"; do
11 printf "%s\0%s\0" "$x" "${x%.md}.html"
12done | xargs -r -0 redo-ifchange
13
14TITLE=$(< $2/title)
15
16cat <<EOF
17% $(< "$2/title")
18
19EOF
20
21POST_TITLES=()
22for x in "${POSTS[@]}"; do
23 title=$(pandoc -t json "$x" | ../build/extract-title.hs)
24 POST_TITLES+=("$title")
25done
26
27for n in $(seq 0 $((${#POSTS[@]}-1))); do
28 printf "* [%s](%s)\n" "${POST_TITLES[$n]}" "${POSTS[$n]%.md}.html"
29done
30
31>"$2/preview"
32prev_no=3
33if [[ ${#POSTS[@]} -gt $prev_no ]]; then
34 printf "* …\n" >> "$2/preview"
35else
36 prev_no=${#POSTS[@]}
37fi
38
39for n in $(seq $prev_no -1 1); do
40 printf "* [%s](%s)\n" "${POST_TITLES[-$n]}" "${POSTS[-$n]%.md}.html" >>"$2/preview"
41done
diff --git a/lists/dirty-haskell/001 b/lists/dirty-haskell/001
deleted file mode 120000
index 92c240d..0000000
--- a/lists/dirty-haskell/001
+++ /dev/null
@@ -1 +0,0 @@
1../../posts/blog-documentation.md \ No newline at end of file
diff --git a/lists/dirty-haskell/002 b/lists/dirty-haskell/002
deleted file mode 120000
index ed24126..0000000
--- a/lists/dirty-haskell/002
+++ /dev/null
@@ -1 +0,0 @@
1../../posts/blog-rss.md \ No newline at end of file
diff --git a/lists/dirty-haskell/title b/lists/dirty-haskell/title
deleted file mode 100644
index e40f49c..0000000
--- a/lists/dirty-haskell/title
+++ /dev/null
@@ -1 +0,0 @@
1Blog Software
diff --git a/lists/zz_all/001 b/lists/zz_all/001
deleted file mode 120000
index 92c240d..0000000
--- a/lists/zz_all/001
+++ /dev/null
@@ -1 +0,0 @@
1../../posts/blog-documentation.md \ No newline at end of file
diff --git a/lists/zz_all/002 b/lists/zz_all/002
deleted file mode 120000
index ed24126..0000000
--- a/lists/zz_all/002
+++ /dev/null
@@ -1 +0,0 @@
1../../posts/blog-rss.md \ No newline at end of file
diff --git a/lists/zz_all/003 b/lists/zz_all/003
deleted file mode 120000
index 1057f2c..0000000
--- a/lists/zz_all/003
+++ /dev/null
@@ -1 +0,0 @@
1../../posts/pwutil.md \ No newline at end of file
diff --git a/lists/zz_all/title b/lists/zz_all/title
deleted file mode 100644
index 73a5267..0000000
--- a/lists/zz_all/title
+++ /dev/null
@@ -1 +0,0 @@
1All Posts
diff --git a/provider/css/default.css b/provider/css/default.css
new file mode 100644
index 0000000..7b89107
--- /dev/null
+++ b/provider/css/default.css
@@ -0,0 +1,40 @@
1body {
2 margin: auto;
3 padding-right: 1em;
4 padding-left: 1em;
5 font: normal 1.1em monospace;
6 max-width: 60em;
7 text-align: justify;
8}
9
10.display-math {
11 display: block;
12 margin-top: 0.2em;
13 margin-bottm: 0.2em;
14 text-align: center;
15}
16
17.inline-math {
18 display: inline;
19}
20
21a {
22 color: inherit;
23}
24
25p {
26 margin-bottom: 0
27}
28
29p + p {
30 text-indent: 1.5em;
31 margin-top: 0;
32}
33
34pre {
35 margin-left: 1.5em;
36}
37
38p code {
39 font-style:italic;
40} \ No newline at end of file
diff --git a/provider/index.html b/provider/index.html
new file mode 100644
index 0000000..8eb184f
--- /dev/null
+++ b/provider/index.html
@@ -0,0 +1,8 @@
1$body$
2<ul>
3 $for(tags)$
4 <li>
5 $body$
6 </li>
7 $endfor$
8</ul>
diff --git a/provider/index.md b/provider/index.md
new file mode 100644
index 0000000..53a06bc
--- /dev/null
+++ b/provider/index.md
@@ -0,0 +1,3 @@
1This is a blog.
2It contains things.
3Send other things to <blog@dirty-haskell.org> if you so choose.
diff --git a/posts/blog-documentation.md b/provider/posts/blog-documentation.md
index 7db843d..b0d4af6 100644
--- a/posts/blog-documentation.md
+++ b/provider/posts/blog-documentation.md
@@ -1,5 +1,9 @@
1% On the Origin of dirty-haskell.org 1---
2title: On the Origin of dirty-haskell.org
3published: 2015-03-12
4tags: Blog Software
5---
2 6
3The software used is a trivially modified version of the one powering [math.kleen.org](http://math.kleen.org/lists/blog.html). 7The software used is a trivially modified version of the one powering [math.kleen.org](http://math.kleen.org/lists/blog.html).
4 8
5The title is without deeper meaning. \ No newline at end of file 9The title is without deeper meaning.
diff --git a/posts/blog-rss.md b/provider/posts/blog-rss.md
index 4e8cb24..095ff56 100644
--- a/posts/blog-rss.md
+++ b/provider/posts/blog-rss.md
@@ -1,4 +1,8 @@
1% dirty-haskell.org´s rss feeds 1---
2title: dirty-haskell.org´s rss feeds
3published: 2015-03-29
4tags: Blog Software
5---
2 6
3I extended the software suite inherited from [math.kleen.org](http://math.kleen.org) to include support for rss feeds. 7I extended the software suite inherited from [math.kleen.org](http://math.kleen.org) to include support for rss feeds.
4The heart of the issue is a ~80 line haskell script I chose to call, in a bout of creativity, "generate-rss.hs". 8The heart of the issue is a ~80 line haskell script I chose to call, in a bout of creativity, "generate-rss.hs".
diff --git a/posts/pwutil.md b/provider/posts/pwutil.md
index 176ffdc..a4b3757 100644
--- a/posts/pwutil.md
+++ b/provider/posts/pwutil.md
@@ -1,4 +1,7 @@
1% A Tool to Manage a Set of YAML Objects Representing Account Information — pwutil 1---
2title: A Tool to Manage a Set of YAML Objects Representing Account Information — pwutil
3published: 2015-04-07
4---
2 5
3A long time ago I wrote a bunch of scripts (first in bash, then zsh, and later perl) to manage a, sometimes encrypted, file containing account information I get asked to create and remember on a daily basis—accounts for shopping websites spring to mind. 6A long time ago I wrote a bunch of scripts (first in bash, then zsh, and later perl) to manage a, sometimes encrypted, file containing account information I get asked to create and remember on a daily basis—accounts for shopping websites spring to mind.
4 7
diff --git a/provider/templates/default.html b/provider/templates/default.html
new file mode 100644
index 0000000..14497b2
--- /dev/null
+++ b/provider/templates/default.html
@@ -0,0 +1,22 @@
1<!DOCTYPE html>
2<html$if(lang)$ lang="$lang$"$endif$>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>$if(title)$$title$$endif$</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="/css/default.css">
13</head>
14<body>
15$if(title)$
16<header>
17 <h1 class="title"><a href="/" title="dirty-haskell.org">dirty-haskell.org</a>: $title$</h1>
18</header>
19$endif$
20$body$
21</body>
22</html>
diff --git a/provider/templates/index.html b/provider/templates/index.html
new file mode 100644
index 0000000..0eea806
--- /dev/null
+++ b/provider/templates/index.html
@@ -0,0 +1,9 @@
1$body$
2
3<ul>
4 $for(tags)$
5 <li>
6 $body$
7 </li>
8 $endfor$
9</ul>
diff --git a/provider/templates/post-list.html b/provider/templates/post-list.html
new file mode 100644
index 0000000..4d50d4d
--- /dev/null
+++ b/provider/templates/post-list.html
@@ -0,0 +1,7 @@
1<ul>
2 $for(posts)$
3 <li>
4 $if(ellipsis)$…$else$<a href="$url$">$title$</a>$endif$
5 </li>
6 $endfor$
7</ul>
diff --git a/provider/templates/tag.html b/provider/templates/tag.html
new file mode 100644
index 0000000..8854cdd
--- /dev/null
+++ b/provider/templates/tag.html
@@ -0,0 +1,2 @@
1<a href="$url$">$title$</a>$if(rss)$ (<a href="$rss$">RSS</a>)$endif$
2$body$
diff --git a/src/Site.hs b/src/Site.hs
index d1afbce..dde7047 100644
--- a/src/Site.hs
+++ b/src/Site.hs
@@ -1,16 +1,131 @@
1{-# LANGUAGE OverloadedStrings #-} 1{-# LANGUAGE OverloadedStrings, RankNTypes, StandaloneDeriving, FlexibleInstances #-}
2 2
3import Hakyll 3import Hakyll
4 4
5import Data.Monoid (Monoid(..), mconcat, (<>))
6import Control.Monad (liftM)
7import Data.Char (toLower, isSpace, isAlphaNum)
8import Data.Maybe (mapMaybe, fromMaybe)
9import Data.Map (Map)
10import qualified Data.Map as Map
11import Data.List (take, reverse)
12import Data.Default
13import Text.Pandoc.Options (WriterOptions(..), ObfuscationMethod(..))
14import Control.Applicative (Alternative(..), Applicative(..))
15
16import System.FilePath (replaceExtension)
17
5main :: IO () 18main :: IO ()
6main = hakyllWith config $ do 19main = hakyllWith config $ do
7 match "/posts/*" $ do 20 match "templates/*" $ compile templateCompiler
21
22 match "css/*" $ do
23 route idRoute
24 compile copyFileCompiler
25
26 match "posts/*" $ do
8 route $ setExtension ".html" 27 route $ setExtension ".html"
9 compile $ do 28 compile $ do
29 getResourceBody >>= saveSnapshot "content"
10 pandocCompiler 30 pandocCompiler
11 >>= saveSnapshot "content"
12 >>= loadAndApplyTemplate "templates/default.html" defaultContext 31 >>= loadAndApplyTemplate "templates/default.html" defaultContext
13 >>= relativizeUrls 32 >>= relativizeUrls
14 33
34 tags <- buildTags "posts/*" tagTranslation' >>= addTag "All Posts" "posts/*"
35
36 tagsRules tags $ \tag pattern -> do
37 route idRoute
38 compile $ do
39 let ctx = mconcat [ constField "title" tag
40 , listField "posts" defaultContext $ chronological =<< loadAll pattern
41 , defaultContext
42 ]
43 makeItem ""
44 >>= loadAndApplyTemplate "templates/post-list.html" ctx
45 >>= loadAndApplyTemplate "templates/default.html" ctx
46 >>= relativizeUrls
47
48 let
49 tags' = tags { tagsMakeId = fromFilePath . (`replaceExtension` "rss") . toFilePath . tagsMakeId tags}
50
51 tagsRules tags' $ \tag pattern -> do
52 route idRoute
53 compile $ do
54 let
55 feedCtx = mconcat [ bodyField "description"
56 , defaultContext
57 ]
58 renderRss (feedConfig tag) feedCtx =<< loadAllSnapshots pattern "content"
59
60 match "index.md" $ do
61 route $ setExtension ".html"
62 compile $ do
63 let ctx = mconcat [ listField "tags" defaultContext $ mapM (\(k, _) -> renderTag k tags) $ tagsMap tags
64 , constField "title" "Index"
65 , defaultContext
66 ]
67 item <- getResourceBody
68 pandocCompilerWith def (def { writerEmailObfuscation = NoObfuscation })
69 >>= loadAndApplyTemplate "templates/index.html" ctx
70 >>= loadAndApplyTemplate "templates/default.html" ctx
71 >>= relativizeUrls
72
73deriving instance Eq (Item String)
74
75feedConfig :: String -> FeedConfiguration
76feedConfig tagName = FeedConfiguration { feedTitle = "dirty-haskell.org: " ++ tagName
77 , feedDescription = "dirty-haskell.org — A Blog."
78 , feedAuthorName = "G. Kleen"
79 , feedAuthorEmail = "blog@dirty-haskell.org"
80 , feedRoot = "https://dirty-haskell.org"
81 }
82
83renderTag :: String -- ^ Tag name
84 -> Tags
85 -> Compiler (Item String)
86renderTag tag tags = do
87 ellipsisItem <- makeItem ""
88 let
89 ids = fromMaybe [] $ lookup tag $ tagsMap tags
90 postCtx = mconcat [ listField "posts" (ellipsisContext ellipsisItem) $ liftM (withEllipsis ellipsisItem) $ chronological =<< mapM load ids
91 , constField "title" tag
92 , constField "rss" ("tags/" ++ tagTranslation tag ++ ".rss")
93 , constField "url" ("tags/" ++ tagTranslation tag ++ ".html")
94 , defaultContext
95 ]
96 makeItem ""
97 >>= loadAndApplyTemplate "templates/post-list.html" postCtx
98 >>= loadAndApplyTemplate "templates/tag.html" postCtx
99 where
100 ellipsisContext item = mconcat [ boolField "ellipsis" (== item)
101 , defaultContext
102 ]
103 boolField name f = field name (\i -> if f i
104 then pure (error $ unwords ["no string value for bool field:",name])
105 else empty)
106 withEllipsis ellipsisItem xs
107 | length xs > max = [ellipsisItem] ++ takeEnd (max - 1) xs
108 | otherwise = xs
109 takeEnd i = reverse . take i . reverse
110 max = 4
111
112tagTranslation' :: String -> Identifier
113tagTranslation' = fromCapture "tags/*.html" . tagTranslation
114
115tagTranslation :: String -> String
116tagTranslation = mapMaybe charTrans
117 where
118 charTrans c
119 | isSpace c = Just $ '-'
120 | isAlphaNum c = Just $ toLower c
121 | otherwise = Nothing
122
123addTag :: MonadMetadata m => String -> Pattern -> Tags -> m Tags
124addTag name pattern tags = do
125 ids <- getMatches pattern
126 return $ tags { tagsMap = tagsMap tags ++ [(name, ids)] }
127
15config :: Configuration 128config :: Configuration
16config = defaultConfiguration 129config = defaultConfiguration { providerDirectory = "provider"
130 , deployCommand = "rsync -av --progress -c --delete-delay -m _site/ gkleen@surtr.yggdrasil.li:/var/www/dirty-haskell.org/"
131 }
diff --git a/templates/default.html b/templates/default.html
deleted file mode 100644
index 970848f..0000000
--- a/templates/default.html
+++ /dev/null
@@ -1,55 +0,0 @@
1<!DOCTYPE html>
2<html$if(lang)$ lang="$lang$"$endif$>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7$for(author-meta)$
8 <meta name="author" content="$author-meta$">
9$endfor$
10$if(date-meta)$
11 <meta name="dcterms.date" content="$date-meta$">
12$endif$
13 <title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
14 <style type="text/css">code{white-space: pre;}</style>
15 <!--[if lt IE 9]>
16 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
17 <![endif]-->
18$if(quotes)$
19 <style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
20$endif$
21$if(highlighting-css)$
22 <style type="text/css">
23$highlighting-css$
24 </style>
25$endif$
26$for(css)$
27 <link rel="stylesheet" href="$css$">
28$endfor$
29$if(math)$
30 $math$
31$endif$
32$for(header-includes)$
33 $header-includes$
34$endfor$
35</head>
36<body>
37$for(include-before)$
38$include-before$
39$endfor$
40$if(title)$
41<header>
42 <h1 class="title"><a href="/" title="dirty-haskell.org">dirty-haskell.org</a>: $title$</h1>
43</header>
44$endif$
45$if(toc)$
46<nav id="$idprefix$TOC">
47$toc$
48</nav>
49$endif$
50$body$
51$for(include-after)$
52$include-after$
53$endfor$
54</body>
55</html>