POSTS
Showing a post tree using jekyll
I’ve been playing with jekyll to create my website over the past few days. Primarily, I’m doing it to play with Ruby, but its also nice to have a new website :)
Jekyll produces a static site, but does this using templates and markup. Its remarkably easy to set up a site, and to give it the look and feel that you want. Any dynamic capability can be provided by external services (e.g. I use disqus for comments) and javascript.
One thing that I wanted to do was have a post tree in the sidebar. By Post Tree, I mean a tree showing all my previous posts, broken down by year and month. Have a look to the right here and you should see it. Jekyll doesn’t provide the ability to do it out of the box, but it is very easy to extend, so I thought I’d write a plugin to do it.
Here’s the code I wrote. The first file is the ruby plugin, which would be placed in _plugins/postsintree.rb . Its responsibility is to set up the data in a format that is easy for the template to output:
module Jekyll
# Extends Site to have an field that gives you a map of posts by year.
class Site
def postsbyyear
# Create a tree of the posts by year and then month
tree = {}
self.posts.each do |post|
year = post.date.year
month = post.date.month
if tree[year] == nil
tree[year] = { "number" => year,
"count" => 0,
"months" => {}
}
end
if tree[year]["months"][month] == nil
tree[year]["months"][month] = { "number" => month,
"name"=>Date::ABBR_MONTHNAMES[month],
"count" => 0,
"posts" => []
}
end
tree[year]["months"][month]["posts"] << post
end
# Turn the tree into sorted arrays, so it is easier to interpret
# in liquid
years = tree.values.sort { |x, y| y["number"] <=> x["number"] }
# Calculate counts of posts and sort each of the months as well
years.each do |year|
year["months"] = year["months"].values.sort { |x, y| y["number"] <=> x["number"] }
year["months"].each do |month|
month["count"] = month["posts"].size
month["posts"] = month["posts"].sort {|x,y| y.date <=> x.date }
end
sum = 0
year["months"].each {|month| sum += month["count"] }
year["count"] = sum
end
return years
end
# Redefine site_payload to include our posts by year. This is ugly
# but I don't know how else to do this without changing the jekyll code
# itself. #rubynoob
def site_payload
{"site" => self.config.merge({
"time" => self.time,
"posts" => self.posts.sort { |a,b| b <=> a },
"pages" => self.pages,
"html_pages" => self.pages.reject { |page| !page.html? },
"categories" => post_attr_hash('categories'),
"tags" => post_attr_hash('tags'),
"postsbyyear" => self.postsbyyear
})}
end
end
end
Now that we have the data in the right format, its just a matter of altering our page template to show the tree. This is facilitated by the following HTML:
<ul id="posttree">
{{"{%"}} for year in site.postsbyyear %}
<li>{{ "{{" }} year.number }} ({{ "{{" }} year.count }})
<ul>
{{ "{%" }} for month in year.months %}
<li> {{ "{{" month.name }} ({{ "{{" }} month.count }})
<ul>
{{ "{%" }} for post in month.posts %}
<li><a href="{{ "{{" }} post.url }}">{{ "{{" post.title }}</a></li>
{{ "{%" }} endfor %}
</ul>
</li>
{{"{%" }} endfor %}
</ul>
</li>
{{ "{%" }} endfor %}
</ul>
The List is then translated into a clickable, expandable tree using the JQuery Treeview plugin
$("#posttree").treeview({
collapsed:true
});
All of this is available at the GIT repostiory of my website, available at GitHub