This post, I think, is important for those who want to re-develop this template on their own site, and especially who has little background of hyde/Django/Python as myself. In this post, I’ll summarize all hacks that I did to the basic hyde template that made this homepage what it looks like now.

Before starting this tutorial, I’d like to thank again Kanglai Qian for his help regarding YAML, Python, and the hyde site structure. This template will be nothing like it is without his help.

This tutorial will be roughly separated into 7 parts. Except the first part which gives a brief but necessary introduction to the directory structure of the default hyde site, each part will introduce a .j2 (the new hyde template file format of my working version 0.8.4) file that I hacked, and how I adjusted the CSS for appearance. I plan to cover in the next tutorial a shortcut on how to make the contents yours and use this template right away.

Let’s start from the basic hyde template by Lakshmi Vyasarajan, the original developer of hyde. To get the basic hyde template, simply type into your Linux console (I used the powerful Cygwin under Windows):

mkdir the-directory-name-you-want-to-store-your-hyde-files
cd the-directory-name-you-want-to-store-your-hyde-files
hyde create

The “hyde create” command creates hyde source files of a website with basic hyde. To see what this basic template looks like, type:

hyde gen
hyde serve

hyde gen” will compile all hyde sources into the “deploy” directory, and “hyde serve” will run a light-weight python web server that enables you to view your site properly at your local machine. The default binding is “http://localhost:8080”. (Hint: it is more practical to run two bash/command-line programs, and always use one as the hyde server.) Note that this hyde server is nothing compared to a real-world one, and should not be used under any circumstance other than local debugging.

The Basic hyde Source Directory Structure

After running “hyde gen”, you should get a directory struture similar to this:

+ content
|- + blog
|- + media
   |- + css
   |- + js
   |- + images
   |- - meta.yaml
|- + portfolio
|- - favicon.ico
|- - index.html
|- - ...
+ layout
|- - analytics.j2
|- - atom.j2
|- - base.j2
|- - blog.j2
|- - devmode.j2
|- - listing.j2
|- - macros.j2
|- - tagged_posts.j2
- README.markdown
- info.yaml
- site.yaml
I did not expand here some directories as they will not be used here. In the layout directory, you’ll find all .j2 files that will be mentioned below.

base.j2

This file determines the basic layout of each generated HTML file on your site. As you open other .j2 files, for example, “blog.j2”, “listing.j2”, or “tagged_posts.j2”, you’ll see that the first line is

{% extends "base.j2" %}
This means that the layout is inherited from “base.j2”. Thus, to change the look of the whole site, “base.j2” should play the most important role.

If you open “base.j2” with text editor, you’ll see familiar HTML-like code. In fact, except for those enclosed with “{% %}“, all the other are HTML code. Thus, you can change the look of it as you usually do with HTMLs. There are also some awesome tricks in the generated basic hyde site. For example, in “content/media/css/site.css”, you’ll find many CSS tricks of round-corner boxes, shadows, and gradients (which consists of most visual effects of my site).

But before you continue, I’d like to introduce a powerful structure in hyde templates: block. Beginning with {% block blockname %} and ending with {% endblock %}, blocks are “slots” for content that can be replaced in future content files or other extending layout files. To replace its content, simply use the same block name in the file or extending layout file, and consider it copy-and-pasted into the slot you left. Here’s a quick example on how I implemented the tag floating on the right (in “base.j2”):

<div class="content-back">
<div class="content-right">
{% block contentright %}{% endblock %}
<div class="right-float"><div id="googletranslate" style="font-size:10px;"></div></div>
</div>
<div class="contentwrapper">
<section class="content">
{% block main %}
{% endblock main %}
</section>
</div>
</div>

Here, the <div class="content-right" /> contains a block named “contentright”, and in “blog.j2”, it’s used as:

{% block contentright %}
{% if resource.meta.tags %}
<div class="right-float">
<span class="lighter">Tags:</span><br/>
<ul class="tags clear">
{% for tag in resource.meta.tags %}
<li>
  <a class="small" href="{{ content_url('blog/tags/'~tag~'.html') }}">
    {{ tag }}
  </a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endblock %}

That’s how the floater with tags of this blog placed on the right of the text.

listing.j2

listing.j2” determines the look of the blog (or other items you like) list ( it’s what you see when you click the “Blog” navi button above). I simply changed the layout from the original floating to list-style. There’s really nothing much to say about it. For details of the layout and coloring, it is strongly recommended that you take some time to hack my source code and the CSS (site.css) on your own. Google Chrome or Firefox will also be of great help if you want to see the actual outcome of hyde gen.

Also, for the non-chronological items such as “Software”, “Research”, and “Misc”, I made a modified copy of listing.j2: listing-no-time.j2.

What? You are saying that you cannot change the appearance of blog excerpts after reading this section? No doubt that would happen. This will be covered in macros.j2. Take a shortcut and see it now!

blog.j2

This file determines how your blog contents are rendered. The greatest change I made to this file are (a) I changed the look of the blog navigation, and (b) I changed the look and position of blog tags. These are essentially basic HTML operations, so I won’t cover them here.

However, the nagivation did involve some hyde tricks. It’s related to plugins called “sorter” and “grouper”, and you must define groups in the “site.yaml” file. The related code pieces in my “site.yaml” are:

...
plugins:
    - hyde.ext.plugins.sorter.SorterPlugin
    - hyde.ext.plugins.grouper.GrouperPlugin
...
meta:
    toc: root
...
sorter:
    reversetime:
        attr:
            - meta.created
        reverse: true
        filters:
            source.kind: html
            meta.listable: true
    time:
        attr:
            - meta.created
        filters:
            source.kind: html
            meta.listable: true
grouper:
    toc:
        sorter: reversetime
        hide_name: True
        groups:
            -
                name: root
                hide_name: True
                groups:
                    -
                        name: Blog
                    -
                        name: Software
                    -
                        name: Research
                    -
                        name: Misc

And in each content directory, for example, “blog”, you should include a corresponding line in the “meta.yaml” file: toc: Blog. After all these are done, you should be able to use the following code to generate a navigation in your “blog.j2”:

<nav class="postnav before">
Previous:
{% if resource.prev_in_toc and resource.prev_in_toc.meta.toc == resource.meta.toc %}
<a href="{{ content_url(resource.prev_in_toc.url) }}">{{ resource.prev_in_toc.meta.title }}</a>
{% else %}
None
{% endif %}
<br/>

Next:
{% if resource.next_in_toc and resource.next_in_toc.meta.toc == resource.meta.toc %}
<a href="{{ content_url(resource.next_in_toc.url) }}">{{ resource.next_in_toc.meta.title }}</a>
{% else %}
None
{% endif %}
</nav>

resource.meta.toc will refer to the toc you defined in the directory’s “meta.yaml” file, this is determined in “site.yaml”. The next_in_toc is the next node, which is determined by the grouper “toc”, which is then determined by the sorter “reversetime”. Since all groups are concatenated here, it will give you the next blog (or whatever) in the current group by time. If that does not exist, it will give you a node in the neighboring group. That is why the {% if %} is necessary.

macros.j2

Here comes the interesting part. “macros.j2” defines how your blog excerpts are rendered, and how your tagged posts are rendered in the tag page. In fact, there’s nothing special. Here’s my version of the macro render_excerpt:

{% macro render_excerpt(res, class=None) %}
{% refer to res.url as post %}
<article {{'class='~class if class }}>
<div class="title"><h3><a href="{{ content_url(res.url) }}">{{ res.meta.title }}</a></h3></div>
{{ post.image|markdown|typogrify }}
{{ post.excerpt|markdown|typogrify }}...
<time datetime="{{ res.meta.created.strftime('%Y-%m-%d') }}">
    Posted: {{ res.meta.created.strftime('%a, %d %b %Y') }}
</time>
</article>
{% endmacro %}

I simply changed the appearance of the excerpt to make it more harmonious with my template. The {{ post.image|markdown|typogrify }} and {{ post.excerpt|markdown|typogrify }} part will refer to { mark image } and { mark excerpt }, respectively, in the actual content file. Here you can use markdown for simplicity. res.meta.title and res.meta.created are also defined in the content file. These parts of this very blog post are like:

---
title: Tutorial 2&#58; The hyde Template Files
description: >
    The second tutorial of the template.
created: !!timestamp '2012-4-10 17:00:00'
tags:
    - tutorial
    - hyde
    - html_css
---
{% block css %}
<link ...
{% endblock %}

{% block scripts %}
<script ...
{% endblock %}

{% mark image -%}
{%- endmark %}
<p>
{% mark excerpt -%}

This post, I think, is important for those who want to re-develop this template on their 
own site, and especially who has little background of hyde/Django/Python as myself. 
In this post, I'll summarize all hacks that I did to the basic hyde template that 
made this homepage what it looks like now.

{%- endmark %}

&#58; is the HTML code for “:”. This is used as “:” is forbidden in titles. So it’s recommended that you use ASCII code for all special marks. A complete list of special HTML ASCII symbols can be found here.

I also wrote a macro named render_news to render the News section on my homepage, and it might be useful to show you how a macro is used.

In layout/macros.j2:

{% macro render_news(res, class=None) %}
{% refer to res as post %}
<ul {{'class='~class if class}}>
{{ post.latest }}
</ul>
{% endmacro %}

In content/index.html:

{% from "macros.j2" import render_news with context  %}
<div class="title"><h3><a href="news.html">News</a></h3></div>
{{ render_news("news.html","news") }}

In content/news.html:

...
{% block main %}
<section>
<div class="title"><h1>News</h1></div>
<ul class="news">
{% mark latest -%}
<li>Apr. 1, 2012 ...</li>
<li>Mar. 29, 2012 ...</li>
<li>Mar. 8, 2012 ...</li>
{%- endmark %}
<li>Nov. 30, 2011 ...</li>
</ul>
</section>
{% endblock %}

tagged_posts.j2

This file determines how the assemble of tagged blogs are rendered. See the “tutorial” page for a quick example. There’s really nothing much to say about this.

analytics.j2

This file is the Google Analytics snippet attached to your site. It’s attached to the “base.j2” file. It’s only enabled in the generated site if the mode of your site is “production”. To enable Google Analytics, configure your “site.yaml”:

mode: production
...
meta:
    analytics:
        id: UA-XXX
...

Remember to replace “UA-XXX” with your property ID.