Permalink
Browse files

initial commit: start of hakyll blog

Code is based on jaspervdj's blog and the “small-blog” example in
hakyll-contrib.
  • Loading branch information...
0 parents commit 3506c770443ba2b15853a1bf74710ba7aa806b1c @ehamberg committed Mar 10, 2012
@@ -0,0 +1,2 @@
+_cache
+_site
@@ -0,0 +1,9 @@
+---
+title: Page not found
+---
+
+<h1>Error 404</h1>
+<p>
+ The page you were looking for does not exist. You might want to
+ <a href="/">go back home</a>.
+</p>
@@ -0,0 +1,139 @@
+{-# LANGUAGE OverloadedStrings, Arrows #-}
+module Main where
+
+import Prelude hiding (id)
+import Control.Category (id)
+import Control.Monad (forM_)
+import Control.Arrow (arr, (>>>), (***), second)
+import Data.Monoid (mempty, mconcat)
+import qualified Data.Map as M
+
+import Hakyll
+
+-- | Entry point
+--
+main :: IO ()
+main = hakyllWith config $ do
+ -- Copy images
+ match "images/*" $ do
+ route idRoute
+ compile copyFileCompiler
+
+ match "favicon.ico" $ do
+ route idRoute
+ compile copyFileCompiler
+
+ -- Copy JavaScript
+ match "js/*" $ do
+ route idRoute
+ compile copyFileCompiler
+
+ -- Copy files (deep)
+ match "files/**" $ do
+ route idRoute
+ compile copyFileCompiler
+
+ -- Compress CSS
+ match "css/*" $ do
+ route idRoute
+ compile compressCssCompiler
+
+ -- Render the /tmp index page
+ match "tmp/index.html" $ do
+ route idRoute
+ compile $ readPageCompiler >>> relativizeUrlsCompiler
+
+ -- Render each and every post
+ match "posts/*" $ do
+ route $ setExtension ".html"
+ compile $ pageCompiler
+ >>> arr (renderDateField "date" "%B %e, %Y" "Date unknown")
+ >>> renderTagsField "prettytags" (fromCapture "tags/*")
+ >>> applyTemplateCompiler "templates/post.html"
+ >>> applyTemplateCompiler "templates/default.html"
+ >>> relativizeUrlsCompiler
+
+ -- Post list
+ match "posts.html" $ route idRoute
+ create "posts.html" $ constA mempty
+ >>> arr (setField "title" "Posts")
+ >>> setFieldPageList recentFirst
+ "templates/postitem.html" "posts" "posts/*"
+ >>> applyTemplateCompiler "templates/posts.html"
+ >>> applyTemplateCompiler "templates/default.html"
+ >>> relativizeUrlsCompiler
+
+ -- Index
+ match "index.html" $ route idRoute
+ create "index.html" $ constA mempty
+ >>> arr (setField "title" "Home")
+ >>> requireA "tags" (setFieldA "tags" (renderTagList'))
+ >>> setFieldPageList (take 3 . recentFirst)
+ "templates/postitem.html" "posts" "posts/*"
+ >>> applyTemplateCompiler "templates/index.html"
+ >>> applyTemplateCompiler "templates/default.html"
+ >>> relativizeUrlsCompiler
+
+ -- Tags
+ create "tags" $
+ requireAll "posts/*" (\_ ps -> readTags ps :: Tags String)
+
+ -- Add a tag list compiler for every tag
+ match "tags/*" $ route $ setExtension ".html"
+ metaCompile $ require_ "tags"
+ >>> arr tagsMap
+ >>> arr (map (\(t, p) -> (tagIdentifier t, makeTagList t p)))
+
+ -- Read templates
+ match "templates/*" $ compile templateCompiler
+
+ -- Render some static pages
+ forM_ ["contact.markdown", "cv.markdown", "links.markdown"] $ \p ->
+ match p $ do
+ route $ setExtension ".html"
+ compile $ pageCompiler
+ >>> applyTemplateCompiler "templates/default.html"
+ >>> relativizeUrlsCompiler
+
+ -- Render the 404 page, we don't relativize URL's here.
+ match "404.html" $ do
+ route idRoute
+ compile $ pageCompiler
+ >>> applyTemplateCompiler "templates/default.html"
+
+ -- Render RSS feed
+ match "rss.xml" $ route idRoute
+ create "rss.xml" $ requireAll_ "posts/*" >>> renderRss feedConfiguration
+
+ -- End
+ return ()
+ where
+ renderTagList' :: Compiler (Tags String) String
+ renderTagList' = renderTagList tagIdentifier
+
+ tagIdentifier :: String -> Identifier (Page String)
+ tagIdentifier = fromCapture "tags/*"
+
+makeTagList :: String
+ -> [Page String]
+ -> Compiler () (Page String)
+makeTagList tag posts =
+ constA posts
+ >>> pageListCompiler recentFirst "templates/postitem.html"
+ >>> arr (copyBodyToField "posts" . fromBody)
+ >>> arr (setField "title" ("Posts tagged " ++ tag))
+ >>> applyTemplateCompiler "templates/posts.html"
+ >>> applyTemplateCompiler "templates/default.html"
+
+config :: HakyllConfiguration
+config = defaultHakyllConfiguration
+ { deployCommand = "rsync -cav _site/* ehamberg@hamberg.no:Webdocs/blog/"
+ }
+
+feedConfiguration :: FeedConfiguration
+feedConfiguration = FeedConfiguration
+ { feedTitle = "Erλend's hjem i skyene"
+ , feedDescription = "Personal blog of Erlend Hamberg"
+ , feedAuthorName = "Erlend Hamberg"
+ , feedRoot = "http://hamberg.no/erlend/blog"
+ }
@@ -0,0 +1,9 @@
+---
+title: Contact
+---
+
+# Contact me
+
+To get in touch with me, send me an email at `ehambergαgmail.com`, send me a a
+tweet (I'm [@ehamberg](http://twitter.com/ehamberg)) or ping me on irc
+(`ehamberg` at freenode).
@@ -0,0 +1,17 @@
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+ margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
@@ -0,0 +1,62 @@
+@import url("hk-pyg.css"); /* for syntax highlighting */
+
+html {
+ font-family: 'Helvetica', sans-serif;
+ font-size: 14px;
+ color: black;
+}
+
+body {
+ width: 600px;
+ margin: 10px auto 10px auto;
+}
+
+div#header {
+ font-size: 16px;
+ font-weight: bold;
+}
+
+div#navigation {
+ float: right;
+}
+
+div#navigation a {
+ margin-left: 10px;
+}
+
+div#footer {
+ text-align: center;
+ font-style: italic;
+ font-size: 11px;
+ margin-top: 30px;
+}
+
+h1 {
+ color: rgb(150, 150, 150);
+ border-bottom: 2px solid rgb(150, 150, 150);
+ font-size: 22px;
+ margin-top: 30px;
+}
+
+li {
+ list-style-type: square;
+}
+
+a {
+ color: rgb(30, 30, 130);
+ font-weight: bold;
+ text-decoration: none;
+}
+
+div.figure {
+ text-align: center;
+}
+
+div.figure p.caption {
+ font-style: italic;
+}
+
+code {
+ background-color: #ddd;
+ font-family: monospace;
+}
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,124 @@
+(function($) {
+
+ $.fn.tweet = function(o){
+ var s = {
+ username: ["seaofclouds"], // [string] required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
+ avatar_size: null, // [integer] height and width of avatar if displayed (48px max)
+ count: 3, // [integer] how many tweets to display?
+ intro_text: null, // [string] do you want text BEFORE your your tweets?
+ outro_text: null, // [string] do you want text AFTER your tweets?
+ join_text: null, // [string] optional text in between date and tweet, try setting to "auto"
+ auto_join_text_default: "i said,", // [string] auto text for non verb: "i said" bullocks
+ auto_join_text_ed: "i", // [string] auto text for past tense: "i" surfed
+ auto_join_text_ing: "i am", // [string] auto tense for present tense: "i was" surfing
+ auto_join_text_reply: "i replied to", // [string] auto tense for replies: "i replied to" @someone "with"
+ auto_join_text_url: "i was looking at", // [string] auto tense for urls: "i was looking at" http:...
+ loading_text: null, // [string] optional loading text, displayed while tweets load
+ query: null // [string] optional search query
+ };
+
+ $.fn.extend({
+ linkUrl: function() {
+ var returning = [];
+ var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
+ this.each(function() {
+ returning.push(this.replace(regexp,"<a href=\"$1\">$1</a>"))
+ });
+ return $(returning);
+ },
+ linkUser: function() {
+ var returning = [];
+ var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
+ this.each(function() {
+ returning.push(this.replace(regexp,"<a href=\"http://twitter.com/$1\">@$1</a>"))
+ });
+ return $(returning);
+ },
+ linkHash: function() {
+ var returning = [];
+ var regexp = / [\#]+([A-Za-z0-9-_]+)/gi;
+ this.each(function() {
+ returning.push(this.replace(regexp, ' <a href="http://search.twitter.com/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'">#$1</a>'))
+ });
+ return $(returning);
+ }
+ });
+
+ function relative_time(time_value) {
+ var parsed_date = Date.parse(time_value);
+ var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
+ var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
+ if(delta < 60) {
+ return 'less than a minute ago';
+ } else if(delta < 120) {
+ return 'about a minute ago';
+ } else if(delta < (45*60)) {
+ return (parseInt(delta / 60)).toString() + ' minutes ago';
+ } else if(delta < (90*60)) {
+ return 'about an hour ago';
+ } else if(delta < (24*60*60)) {
+ return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
+ } else if(delta < (48*60*60)) {
+ return '1 day ago';
+ } else {
+ return (parseInt(delta / 86400)).toString() + ' days ago';
+ }
+ }
+
+ if(o) $.extend(s, o);
+ return this.each(function(){
+ var list = $('<ul class="tweet_list">').appendTo(this);
+ var intro = '<p class="tweet_intro">'+s.intro_text+'</p>'
+ var outro = '<p class="tweet_outro">'+s.outro_text+'</p>'
+ var loading = $('<p class="loading">'+s.loading_text+'</p>');
+ if(typeof(s.username) == "string"){
+ s.username = [s.username];
+ }
+ var query = '';
+ if(s.query) {
+ query += 'q='+s.query;
+ }
+ query += '&q=from:'+s.username.join('%20OR%20from:');
+ var url = 'http://search.twitter.com/search.json?&'+query+'&rpp='+s.count+'&callback=?';
+ if (s.loading_text) $(this).append(loading);
+ $.getJSON(url, function(data){
+ if (s.loading_text) loading.remove();
+ if (s.intro_text) list.before(intro);
+ $.each(data.results, function(i,item){
+ // auto join text based on verb tense and content
+ if (s.join_text == "auto") {
+ if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
+ var join_text = s.auto_join_text_reply;
+ } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
+ var join_text = s.auto_join_text_url;
+ } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
+ var join_text = s.auto_join_text_ed;
+ } else if (item.text.match(/^(\w*ing) .*/i)) {
+ var join_text = s.auto_join_text_ing;
+ } else {
+ var join_text = s.auto_join_text_default;
+ }
+ } else {
+ var join_text = s.join_text;
+ };
+
+ var join_template = '<span class="tweet_join"> '+join_text+' </span>';
+ var join = ((s.join_text) ? join_template : ' ')
+ var avatar_template = '<a class="tweet_avatar" href="http://twitter.com/'+ item.from_user+'"><img src="'+item.profile_image_url+'" height="'+s.avatar_size+'" width="'+s.avatar_size+'" alt="'+item.from_user+'\'s avatar" border="0"/></a>';
+ var avatar = (s.avatar_size ? avatar_template : '')
+ var date = '<a href="http://twitter.com/'+item.from_user+'/statuses/'+item.id+'" title="view tweet on twitter">'+relative_time(item.created_at)+'</a>';
+ var text = '<span class="tweet_text">' +$([item.text]).linkUrl().linkUser().linkHash()[0]+ '</span>';
+
+ // until we create a template option, arrange the items below to alter a tweet's display.
+ list.append('<li>' + avatar + date + join + text + '</li>');
+
+ list.children('li:first').addClass('tweet_first');
+ list.children('li:odd').addClass('tweet_even');
+ list.children('li:even').addClass('tweet_odd');
+ });
+ if (s.outro_text) list.after(outro);
+ });
+
+ });
+ };
+})(jQuery);
@@ -0,0 +1,8 @@
+---
+title: Archive
+---
+
+<h1>All posts</h1>
+<ul>
+ $allPosts$
+</ul>
@@ -0,0 +1,15 @@
+---
+title: An example post
+description: Just a test
+tags: testtag, testtag2
+---
+
+# Test post
+
+This is a test post[^1].
+
+~~~{.haskell}
+map id [1..10]
+~~~
+
+[^1]: It really is.
Oops, something went wrong.

0 comments on commit 3506c77

Please sign in to comment.