Creating a Theme

Nikola is a static site and blog generator. So is Jekyll. While I like what we have done with Nikola, I do admit that Jekyll (and others!) have many more, and nicer themes than Nikola does.

This document is an attempt at making it easier for 3rd parties (that means you people! ;-) to create themes. Since I suck at designing websites, I asked for opinions on themes to port, and got some feedback. Since this is Not So Hard™, I will try to make time to port a few and see what happens.

If you are looking for a reference, check out Theming reference and Template variables.

Today’s theme is Lanyon which is written by @mdo and released under a MIT license, which is liberal enough.

So, let’s get started.

Checking It Out

The first step in porting a theme is making the original theme work. Lanyon is awesome in that its GitHub project is a full site!

So:

# Get jekyll
sudo apt-get install jekyll

# Get Lanyon
git clone git@github.com:poole/lanyon.git

# Build it
cd lanyon && jekyll build

# Look at it
jekyll serve & google-chrome http://localhost:4000

If you do not want to install Jekyll, you can also see it in action at http://lanyon.getpoole.com/

Some things jump to my mind:

  1. This is one fine looking theme

  2. Very clear and readable

  3. Nice hidden navigation-thingy

Also, from looking at the project’s README it supports some nice configuration options:

  1. Color schemes

  2. Reverse layout

  3. Sidebar overlay instead of push

  4. Open the sidebar by default, or on a per-page basis by using its metadata

Let’s try to make all those nice things survive the porting.

Starting From Somewhere

Nikola has a nice, clean, base theme from which you can start when writing your own theme. Why start from that instead of from a clean slate? Because theme inheritance is going to save you a ton of work, that’s why. If you start from scratch you won’t be able to build anything until you have a bunch of templates written. Starting from base, you just need to hack on the things you need to change.

First, we create a site with some content in it. We’ll use the nikola init wizard (with the --demo option) for that:

$ nikola init --demo lanyon-port
Creating Nikola Site
====================

This is Nikola v7.8.0.  We will now ask you a few easy questions about your new site.
If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter.
--- Questions about the site ---
Site title [My Nikola Site]:
Site author [Nikola Tesla]:
Site author's e-mail [n.tesla@example.com]:
Site description [This is a demo site for Nikola.]:
Site URL [https://example.com/]:
--- Questions about languages and locales ---
We will now ask you to provide the list of languages you want to use.
Please list all the desired languages, comma-separated, using ISO 639-1 codes.  The first language will be used as the default.
Type '?' (a question mark, sans quotes) to list available languages.
Language(s) to use [en]:

Please choose the correct time zone for your blog. Nikola uses the tz database.
You can find your time zone here:
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

Time zone [UTC]:
    Current time in UTC: 16:02:07
Use this time zone? [Y/n]
--- Questions about comments ---
You can configure comments now.  Type '?' (a question mark, sans quotes) to list available comment systems.  If you do not want any comments, just leave the field blank.
Comment system:

That's it, Nikola is now configured.  Make sure to edit conf.py to your liking.
If you are looking for themes and addons, check out https://themes.getnikola.com/ and https://plugins.getnikola.com/.
Have fun!
[2015-05-28T16:02:08Z] INFO: init: A new site with example data has been created at lanyon-port.
[2015-05-28T16:02:08Z] INFO: init: See README.txt in that folder for more information.

Then, we create an empty theme inheriting from base. This theme will use Mako templates. If you prefer Jinja2, then you should use base-jinja as a parent and jinja as engine instead:

$ cd lanyon-port/
$ nikola theme -n lanyon --parent base --engine mako

Edit conf.py and set THEME = 'lanyon'. Also set USE_BUNDLES = False (just do it for now, we’ll get to bundles later). Also, if you intend to publish your theme on the Index, or want to use it with older versions (v7.8.5 or older), use the --legacy-meta option for nikola theme -n.

You can now build that site using nikola build and it will look like this:

https://getnikola.com/images/lanyon-0.thumbnail.png

This is just the base theme.

Basic CSS

The next step is to know exactly how Lanyon’s pages work. To do this, we read its HTML. First let’s look at the head element:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">

<head>
<link href="http://gmpg.org/xfn/11" rel="profile">
<meta http-equiv="content-type" content="text/html; charset=utf-8">

<!-- Enable responsiveness on mobile devices-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">

<title>
    Lanyon &middot; A Jekyll theme
</title>

<!-- CSS -->
<link rel="stylesheet" href="/public/css/poole.css">
<link rel="stylesheet" href="/public/css/syntax.css">
<link rel="stylesheet" href="/public/css/lanyon.css">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=PT+Serif:400,400italic,700|PT+Sans:400">

<!-- Icons -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/public/apple-touch-icon-144-precomposed.thumbnail.png">
<link rel="shortcut icon" href="/public/favicon.ico">

<!-- RSS -->
<link rel="alternate" type="application/rss+xml" title="RSS" href="/atom.xml">

<!-- Google Analytics -->
[...]
</head>

The interesting part there is that it loads a few CSS files. If you check the source of your Nikola site, you will see something fairly similar:

<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article# " vocab="http://ogp.me/ns" lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="This is a demo site for Nikola.">
<meta name="viewport" content="width=device-width">
<title>My Nikola Site | My Nikola Site</title>

<link href="assets/css/rst_base.css" rel="stylesheet" type="text/css">
<link href="assets/css/code.css" rel="stylesheet" type="text/css">
<link href="assets/css/theme.css" rel="stylesheet" type="text/css">

<link rel="alternate" type="application/rss+xml" title="RSS" href="rss.xml">
<link rel="canonical" href="https://example.com/index.html">
<!--[if lt IE 9]><script src="assets/js/html5.js"></script><![endif]--><link rel="prefetch" href="posts/welcome-to-nikola.html" type="text/html">
</head>

Luckily, since this is all under a very liberal license, we can just copy these CSS files into Nikola, adapting the paths a little so that they follow our conventions:

$ mkdir -p themes/lanyon/assets/css
$ cp ../lanyon/public/css/poole.css themes/lanyon/assets/css/
$ cp ../lanyon/public/css/lanyon.css themes/lanyon/assets/css/

Notice I am not copying syntax.css? That’s because Nikola handles that styles for syntax highlighting in a particular way, using a setting called CODE_COLOR_SCHEME where you can configure what color scheme the syntax highlighter uses. You can use your own assets/css/code.css if you don’t like the provided ones.

Nikola requires assets/css/rst_base.css and assets/css/code.css to function properly. We will also add themes for Jupyter (assets/css/ipython.min.css and assets/css/nikola_ipython.css) into the template; note that they are activated only if you configured your POSTS/PAGES with ipynb support. There’s also assets/css/nikola_rst.css, which adds Bootstrap 3-style reST notes etc.

But how do I tell our lanyon theme to use those CSS files instead of whatever it’s using now? By giving our theme its own base_helper.tmpl.

That file is a template used to generate parts of the pages. It’s large and complicated but we don’t need to change a lot of it. First, make a copy in your theme (note this command requires setting your THEME in conf.py to lanyon):

$ nikola theme -c base_helper.tmpl

The part we want to change is this:

<%def name="html_stylesheets()">
    %if use_bundles:
        %if use_cdn:
            <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
        %else:
            <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
        %endif
    %else:
        <link href="/assets/css/rst_base.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/nikola_rst.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
        %if has_custom_css:
            <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
        %endif
    %endif
    % if needs_ipython_css:
        <link href="/assets/css/ipython.min.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/nikola_ipython.css" rel="stylesheet" type="text/css">
    % endif
</%def>

And we will change it so it uses the lanyon styles instead of theme.css (again, ignore the bundles for now!):

<%def name="html_stylesheets()">
    %if use_bundles:
        <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
    %else:
        <link href="/assets/css/rst_base.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/nikola_rst.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/poole.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/lanyon.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
        %if has_custom_css:
            <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
        %endif
    %endif
    % if needs_ipython_css:
        <link href="/assets/css/ipython.min.css" rel="stylesheet" type="text/css">
        <link href="/assets/css/nikola_ipython.css" rel="stylesheet" type="text/css">
    % endif
    <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=PT+Serif:400,400italic,700|PT+Sans:400">
</%def>
https://getnikola.com/images/lanyon-1.thumbnail.png

You may say this looks like crap. Don’t worry, we are just starting :-)

Page Layout

This is trickier but should be no problem for people with a basic understanding of HTML and a desire to make a theme!

Lanyon’s content is split in two parts: a sidebar and the rest. The sidebar looks like this (shortened for comprehension):

<body>
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
     styles, `#sidebar-checkbox` for behavior. -->
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">

<!-- Toggleable sidebar -->
<div class="sidebar" id="sidebar">
    <div class="sidebar-item">
        <p>A reserved <a href="http://jekyllrb.com" target="_blank">Jekyll</a> theme that places the utmost gravity on content with a hidden drawer. Made by <a href="https://twitter.com/mdo" target="_blank">@mdo</a>.</p>
    </div>

    <nav class="sidebar-nav">
        <a class="sidebar-nav-item active" href="/">Home</a>
        <a class="sidebar-nav-item" href="/about/">About</a>
        [...]
    </nav>
</div>

So, a plain body, with an input element that controls the sidebar, a div which is the sidebar itself. Inside that, div.sidebar-item for items, and a nav with "navigational links". This is followed by the "masthead" and the content itself, which we will look at in a bit.

If we look for the equivalent code in Nikola’s side, we see this:

<body>
<a href="#content" class="sr-only sr-only-focusable">Skip to main content</a>
<div id="container">
<header id="header" role="banner">
<h1 id="brand"><a href="https://example.com/" title="My Nikola Site" rel="home"> <span id="blog-title">My Nikola Site</span> </a></h1>
<nav id="menu" role="navigation"><ul>
<li><a href="../archive.html">Archive</a></li>
                <li><a href="../categories/index.html">Tags</a></li>
                <li><a href="../rss.xml">RSS feed</a></li>

So Nikola has the "masthead" above the nav element, and uses list elements in nav instead of bare links. Not all that different is it?

Let’s make it lanyon-like! We will need 2 more templates: base.tmpl and base_header.tmpl. Get them and put them in your themes/lanyon/templates folder.

Let’s look at base.tmpl first. It’s short and nice, it looks like a webpage without all the interesting stuff:

## -*- coding: utf-8 -*-
<%namespace name="base" file="base_helper.tmpl" import="*"/>
<%namespace name="header" file="base_header.tmpl" import="*"/>
<%namespace name="footer" file="base_footer.tmpl" import="*"/>
${set_locale(lang)}
${base.html_headstart()}
<%block name="extra_head">
### Leave this block alone.
</%block>
${template_hooks['extra_head']()}
</head>
<body>
<a href="#content" class="sr-only sr-only-focusable">${messages("Skip to main content")}</a>
    <div id="container">
        ${header.html_header()}
        <main id="content" role="main">
            <%block name="content"></%block>
        </main>
        ${footer.html_footer()}
    </div>
    ${body_end}
    ${template_hooks['body_end']()}
    ${base.late_load_js()}
</body>
</html>

That link which says "Skip to main content" is very important for accessibility, so we will leave it in place. But below, you can see how it creates the "container" div we see in the Nikola page, and the content is created by html_header() which is defined in base_header.tmpl The actual nav element is done by the html_navigation_links function out of the NAVIGATION_LINKS and NAVIGATION_ALT_LINKS options. (Let's put the alt links after regular ones; Bootstrap puts it on the right side, for example.)

So, first, lets change that base template to be more lanyon-like:

## -*- coding: utf-8 -*-
<%namespace name="base" file="base_helper.tmpl" import="*"/>
<%namespace name="header" file="base_header.tmpl" import="*"/>
<%namespace name="footer" file="base_footer.tmpl" import="*"/>
${set_locale(lang)}
${base.html_headstart()}
<%block name="extra_head">
### Leave this block alone.
</%block>
${template_hooks['extra_head']()}
</head>
<body>
    <a href="#content" class="sr-only sr-only-focusable">${messages("Skip to main content")}</a>
    <!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
            styles, `#sidebar-checkbox` for behavior. -->
    <input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">

    <!-- Toggleable sidebar -->
    <div class="sidebar" id="sidebar">
        <div class="sidebar-item">
            <p>A reserved <a href="http://getnikola.com" target="_blank">Nikola</a> theme that places the utmost gravity on content with a hidden drawer. Made by <a href="https://twitter.com/mdo" target="_blank">@mdo</a> for Jekyll,
            ported to Nikola by <a href="https://twitter.com/ralsina" target="_blank">@ralsina</a>.</p>
        </div>
        ${header.html_navigation_links()}
    </div>

    <main id="content" role="main">
        <%block name="content"></%block>
    </main>
    ${footer.html_footer()}
    ${body_end}
    ${template_hooks['body_end']()}
    ${base.late_load_js()}
</body>
</html>
https://getnikola.com/images/lanyon-2.thumbnail.png

And that’s after I exposed the sidebar by clicking on an invisible widget!

One problem, which causes that yellow color in the sidebar is a CSS conflict. We are loading rst_base.css which specifies the background color of div.sidebar which is more specific than lanyon.css, which specifies for .sidebar alone.

There are many ways to fix this, I chose to change lanyon.css to also use div.sidebar:

div.sidebar,.sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: -14rem;
    width: 14rem;
    [...]

This is annoying but it will happen when you just grab CSS from different places. The "Inspect Element" feature of your web browser is your best friend for these situations.

Another problem is that the contents of the nav element are wrong. They are not bare links. We will fix that in base_header.html, like this:

<%def name="html_navigation_links()">
    <nav id="menu" role="navigation" class="sidebar-nav">
    %for url, text in navigation_links[lang]:
        <a class="sidebar-nav-item" href="${url}">${text}</a>
    %endfor
    ${template_hooks['menu']()}

    %for url, text in navigation_alt_links[lang]:
        <a class="sidebar-nav-item" href="${url}">${text}</a>
    %endfor
    ${template_hooks['menu_alt']()}
    </nav>
</%def>

Note: this means this theme will not support submenus in navigation. If you want that, I’ll happily take a patch.

https://getnikola.com/images/lanyon-3.thumbnail.png

Starting to see a resemblance?

Now let’s look at the content. In Lanyon, this is how the "main" content looks:

<!-- Wrap is the content to shift when toggling the sidebar. We wrap the
     content to avoid any CSS collisions with our real content. -->
<div class="wrap">
  <div class="masthead">
    <div class="container">
      <h3 class="masthead-title">
        <a href="/" title="Home">Lanyon</a>
        <small>A Jekyll theme</small>
      </h3>
    </div>
  </div>

  <div class="container content">
    <div class="post">
        <h1 class="post-title">Introducing Lanyon</h1>
        <span class="post-date">02 Jan 2014</span>
        <p>Lanyon is an unassuming <a href="http://jekyllrb.com">Jekyll</a> theme [...]
    </div>
  </div>
</div>
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
</body>
</html>

Everything inside the "container content" div is… the content. The rest is a masthead with the site title and at the bottom a label for the sidebar toggle. Easy to do in base.tmpl (only showing the relevant part):

    <!-- Wrap is the content to shift when toggling the sidebar. We wrap the
        content to avoid any CSS collisions with our real content. -->
    <div class="wrap">
    <div class="masthead">
        <div class="container">
        <h3 class="masthead-title">
            <a href="/" title="Home">Lanyon</a>
            <small>A Jekyll theme</small>
        </h3>
        </div>
    </div>

    <div class="container content" id="content">
        <%block name="content"></%block>
    </div>
    </div>
    <label for="sidebar-checkbox" class="sidebar-toggle"></label>
    ${footer.html_footer()}
    ${body_end}
    ${template_hooks['body_end']()}
    ${base.late_load_js()}
</body>
</html>
https://getnikola.com/images/lanyon-4.thumbnail.png

Getting there!

The sidebar looks bad because of yet more CSS conflicts with rst_base.css. By adding some extra styling in lanyon.css, it will look better.

/* Style and "hide" the sidebar */
div.sidebar, .sidebar {
  position: fixed;
  top: 0;
  bottom: 0;
  left: -14rem;
  width: 14rem;
  visibility: hidden;
  overflow-y: auto;
  padding: 0;
  margin: 0;
  border: none;
  font-family: "PT Sans", Helvetica, Arial, sans-serif;
  font-size: .875rem; /* 15px */
  color: rgba(255,255,255,.6);
  background-color: #202020;
  -webkit-transition: all .3s ease-in-out;
          transition: all .3s ease-in-out;
}

Also, the accessibility link on top is visible when it should not. That’s because we removed theme.css from the base theme, and with it, we lost a couple of classes. We can add them in lanyon.css, along with others used by other pieces of the site:

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.sr-only-focusable:active,
.sr-only-focusable:focus {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
}

.breadcrumb {
  padding: 8px 15px;
  margin-bottom: 20px;
  list-style: none;
}

.breadcrumb > li {
  display: inline-block;
  margin-right: 0;
  margin-left: 0;
}

.breadcrumb > li:after {
  content: ' / ';
  color: #888;
}

.breadcrumb > li:last-of-type:after {
  content: '';
  margin-left: 0;
}

.thumbnails > li {
  display: inline-block;
  margin-right: 10px;
}

.thumbnails > li:last-of-type {
  margin-right: 0;
}
https://getnikola.com/images/lanyon-5.thumbnail.png

Little by little, things look better.

One clear problem is that the title "Lanyon · A Jekyll theme" is set in the theme itself. We don’t do that sort of thing in Nikola, we have settings for that. So, let’s use them. There is a html_site_title function in base_helper.tmpl which is just the thing. So we change base.tmpl to use it:

<div class="wrap">
  <div class="masthead">
    <div class="container">
      ${header.html_site_title()}
    </div>
  </div>

That’s a <h1> instead of a <h3> like Lanyon does, but hey, it’s the right thing to do. If you want to go with an <h3>, just change html_site_title itself.

And now we more or less have the correct page layout and styles. Except for a rather large thing…

Typography

You can see in the previous screenshot that text still looks quite different in our port: Serif versus Sans-Serif content, and the titles have different colors!

Let’s start with the titles. Here’s how they look in Lanyon:

<h3 class="masthead-title">
  <a href="/" title="Home">Lanyon</a>
  <small>A Jekyll theme</small>
</h3>

Versus our port:

<h1 id="brand"><a href="https://example.com/" title="My Nikola Site" rel="home">

So, it looks like we will have to fix html_site_title after all:

<%def name="html_site_title()">
    <h3 id="brand" class="masthead-title">
    <a href="${abs_link(_link("root", None, lang))}" title="${blog_title}" rel="home">${blog_title}</a>
    </h3>
</%def>

As for the actual content, that’s not in any of the templates we have seen so far. The page you see is an "index.tmpl" page, which means it’s a list of blog posts shown one below the other. Obviously it’s not doing things in the way the Lanyon CSS expects it to. Here’s the original, which you can find in Nikola’s source code:

## -*- coding: utf-8 -*-
<%namespace name="helper" file="index_helper.tmpl"/>
<%namespace name="comments" file="comments_helper.tmpl"/>
<%inherit file="base.tmpl"/>

<%block name="extra_head">
    ${parent.extra_head()}
    % if posts and (permalink == '/' or permalink == '/' + index_file):
        <link rel="prefetch" href="${posts[0].permalink()}" type="text/html">
    % endif
</%block>

<%block name="content">
<%block name="content_header"></%block>
<div class="postindex">
% for post in posts:
    <article class="h-entry post-${post.meta('type')}">
    <header>
        <h1 class="p-name entry-title"><a href="${post.permalink()}" class="u-url">${post.title()|h}</a></h1>
        <div class="metadata">
            <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
            <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.date.isoformat()}" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></a></p>
            % if not post.meta('nocomments') and site_has_comments:
                <p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
            % endif
        </div>
    </header>
    %if index_teasers:
    <div class="p-summary entry-summary">
    ${post.text(teaser_only=True)}
    %else:
    <div class="e-content entry-content">
    ${post.text(teaser_only=False)}
    %endif
    </div>
    </article>
% endfor
</div>
${helper.html_pager()}
${comments.comment_link_script()}
${helper.mathjax_script(posts)}
</%block>

And this is how it looks after I played with it for a while, making it generate code that looks closer to the Lanyon original:

<%block name="content">
<%block name="content_header"></%block>
<div class="posts">
% for post in posts:
    <article class="post h-entry post-${post.meta('type')}">
    <header>
        <h1 class="post-title p-name"><a href="${post.permalink()}" class="u-url">${post.title()|h}</a></h1>
        <div class="metadata">
            <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
            <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="post-date published dt-published" datetime="${post.date.isoformat()}" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></a></p>
            % if not post.meta('nocomments') and site_has_comments:
                <p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
            % endif
        </div>
    </header>
    %if index_teasers:
    <div class="p-summary entry-summary">
    ${post.text(teaser_only=True)}
    %else:
    <div class="e-content entry-content">
    ${post.text(teaser_only=False)}
    %endif
    </div>
    </article>
% endfor
</div>
${helper.html_pager()}
${comments.comment_link_script()}
${helper.mathjax_script(posts)}
</%block>

With these changes, it looks… similar?

https://getnikola.com/images/lanyon-6.thumbnail.png

It does!

Similar changes (basically adding class names to elements) needed to be done in post_header.tmpl:

<%def name="html_post_header()">
    <header>
        ${html_title()}
        <div class="metadata">
            <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
            <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="post-date published dt-published" datetime="${post.date.isoformat()}" itemprop="datePublished" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></a></p>
            % if not post.meta('nocomments') and site_has_comments:
                <p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
            % endif
            %if post.description():
                <meta name="description" itemprop="description" content="${post.description()}">
            %endif
        </div>
        ${html_translations(post)}
    </header>
</%def>

Customization

The original Lanyon theme supports some personalization options. It suggests you do them by tweaking the templates, and you can also do that in the Nikola port. But we prefer to use options for that, so that you can get a later, better version of the theme and it will still "just work".

Let’s see the color schemes first. They apply easily, just tweak your body element like this:

<body class="theme-base-08">
...
</body>

We can tweak base.tmpl to do just that:

% if lanyon_subtheme:
<body class="${lanyon_subtheme}">
%else:
<body>
%endif

And then we can put the options in conf.py’s GLOBAL_CONTEXT:

GLOBAL_CONTEXT = {
    "lanyon_subtheme": "theme-base-08"
}
https://getnikola.com/images/lanyon-7.thumbnail.png

Look at it, all themed up.

Doing the same for layout-reverse, sidebar-overlay and the rest is left as an exercise for the reader.

Bundles

If the USE_BUNDLES option set to True, Nikola can put several CSS or JS files together in a larger file, which can makes site load faster for some deployments. To do this, your theme needs a bundles file. The file format is a modified config file with no defined section; the basic syntax is:

outputfile1.js=
    thing1.js,
    thing2.js,
    ...
outputfile2.css=
    thing1.css,
    thing2.css,
    ...

For the Lanyon theme, it should look like this:

assets/css/all.css=
    rst_base.css,
    nikola_rst.css,
    code.css,
    poole.css,
    lanyon.css,
    custom.css,

Note: trailing commas are optional

Note: Some themes also support the USE_CDN option meaning that in some cases it will load one bundle with all CSS and in other will load some CSS files from a CDN and others from a bundle. This is complicated and probably not worth the effort.

The End

And that’s it, that’s a whole theme. Eventually, once people start using it, they will notice small broken details, which will need handling one at a time.

This theme should be available in http://themes.getnikola.com/v7/lanyon/ and you can see it in action at https://themes.getnikola.com/v7/lanyon/demo/ .

What if you want to extend other parts of the theme? Check out the Theming reference. You can also contribute your improvements to the nikola-themes <https://github.com/getnikola/nikola> repository on GitHub.

Charts

If you are using reStructuredText and install pygal, Nikola has support for rather nice charts with little effort, and i's even semi-interactive (hover your pointer over the legend!):

.. chart:: StackedLine
   :title: 'Browser usage evolution (in %)'
   :fill: True
   :x_labels: ['2002','2003','2004','2005','2006','2007','2008','2009','2010','2011','2012']
   :width: 600
   :height: 400
   :explicit_size: True
   :style: BlueStyle

   ('Others',  [14.2, 15.4, 15.3,  8.9,    9, 10.4,  8.9,  5.8,  6.7,  6.8,  7.5])
   ('IE',      [85.8, 84.6, 84.7, 74.5,   66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
   ('Firefox', [None, None, None, 16.6,   25,   31, 36.4, 45.5, 46.3, 42.8, 37.1])
   ('Chrome',  [None, None, None, None, None, None,    0,  3.9, 10.8, 23.8, 35.3])
Browser usage evolution (in %) 10102020303040405050606070708080909010010020022003200420052006200720082009201020112012Browser usage evolution (in %)14.28.676923076923076281.03846153846155200215.452.06153846153847277.1923076923077200315.395.44615384615383277.512820512820520048.9138.83076923076922298.02564102564120059182.21538461538464297.7051282051282200610.4225.6293.2179487179487320078.9268.9846153846153298.02564102564120085.8312.36923076923074307.9615384615384520096.7355.75384615384615305.076923076923120106.8399.1384615384615304.756410256410320117.5442.52307692307687302.51282051282052012100 (+85.8)8.6769230769230766.0384615384615472002100 (+84.6)52.061538461538476.0384615384615472003100 (+84.7)95.446153846153836.038461538461547200483.4 (+74.5)138.8307692307692259.24358974358972200575 (+66)182.2153846153846486.16666666666669200669 (+58.6)225.6105.39743589743591200763.6 (+54.7)268.9846153846153122.7051282051282200850.6 (+44.8)312.36923076923074164.3717948717949200942.9 (+36.2)355.75384615384615189.05128205128204201033.4 (+26.6)399.1384615384615219.5201127.6 (+20.1)442.52307692307687238.08974358974362012100 (+0)8.6769230769230766.0384615384615472002100 (+0)52.061538461538476.0384615384615472003100 (+0)95.446153846153836.0384615384615472004100 (+16.6)138.830769230769226.0384615384615472005100 (+25)182.215384615384646.0384615384615472006100 (+31)225.66.0384615384615472007100 (+36.4)268.98461538461536.038461538461547200896.1 (+45.5)312.3692307692307418.538461538461547200989.2 (+46.3)355.7538461538461540.65384615384613201076.2 (+42.8)399.138461538461582.32051282051287201164.7 (+37.1)442.52307692307687119.179487179487152012100 (+0)8.6769230769230766.0384615384615472002100 (+0)52.061538461538476.0384615384615472003100 (+0)95.446153846153836.0384615384615472004100 (+0)138.830769230769226.0384615384615472005100 (+0)182.215384615384646.0384615384615472006100 (+0)225.66.0384615384615472007100 (+0)268.98461538461536.0384615384615472008100 (+3.9)312.369230769230746.0384615384615472009100 (+10.8)355.753846153846156.0384615384615472010100 (+23.8)399.13846153846156.0384615384616042011100 (+35.3)442.523076923076876.0384615384615472012OthersIEFirefoxChrome

Here's how it works:

  • Next to the directive, use the chart type you want

  • Any option you can set in a chart? Use it like :title: in this example. Syntax on the value is just like in the pygal examples.

  • For each data series do it like the line that says Firefox in this example. The first element is the label, then comes the data.

Easy, right? Please explore the pygal site for more information, and just take this example and tweak stuff.

Using Alternative Social Buttons with Nikola

Version
8.0.1

The Default

By Default, the themes provided with Nikola will add to your pages a "slide in" widget at the bottom right of the page, provided by Addthis. This is the HTML code for that:

<!-- Social buttons -->
<div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style
    addthis_default_style addthis_label_style addthis_32x32_style">
<a class="addthis_button_more">Share</a>
<ul><li><a class="addthis_button_facebook"></a>
<li><a class="addthis_button_google_plusone_share"></a>
<li><a class="addthis_button_linkedin"></a>
<li><a class="addthis_button_twitter"></a>
</ul>
</div>
<script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
<!-- End of social buttons -->
"""

You can change that using the SOCIAL_BUTTONS_CODE option in your conf.py. In some cases, just doing that will be enough but in others, it won't. This document tries to describe all the bits involved in making this work correctly.

Part 1: SOCIAL_BUTTONS_CODE

Social sharing services like addthis and others will provide you a HTML snippet. If it is self-contained, then just setting SOCIAL_BUTTONS_CODE may be enough. Try :-)

Part 2: The theme

The SOCIAL_BUTTONS_CODE HTML fragment will be embedded somewhere by the theme. Whether that is the correct place or not is not something the theme author can truly know, so it is possible that you may have to tweak the base.html template to make it look good.

Part 3: BODY_END and EXTRA_HEAD_DATA

Some social sharing code requires JS execution that depends on JQuery being available (example: SocialSharePrivacy). It's good practice (and often, the only way that will work) to put those at the end of <BODY>, and one easy way to do that is to put them in BODY_END

On the other hand, it's possible that it requires you to load some CSS files. The right place for that is in the document's <HEAD> so they should be added in EXTRA_HEAD_DATA

Part 4: assets

For sharing code that doesn't rely on a social sharing service, you may need to add CSS, Image, or JS files to your site

ShareNice

Sharenice is "written in order to provide social sharing features to web developers and website administrators who wish to maintain and protect their users' privacy" which sounds cool to me.

Let's go step by step into integrating the hosted version of ShareNice into a Nikola site.

For testing purposes, let's do it on a demo site:

$ nikola init --demo sharenice_test
A new site with example data has been created at sharenice_test.
See README.txt in that folder for more information.
$ cd sharenice_test/

To see what's going on, let's start Nikola in "auto mode". This should build the site and open a web browser showing the default configuration, with the AddThis widget:

$ nikola auto -b

First, let's add the HTML snippet that will show the sharing options. In your conf.py, set this, which is the HTML code suggested by ShareNice:

SOCIAL_BUTTONS_CODE = """<div id="shareNice" data-share-label="Share"
    data-color-scheme="black" data-icon-size="32" data-panel-bottom="plain"
    data-services="plus.google.com,facebook.com,digg.com,email,delicious.com,twitter.com"
    style="float:right"></div>"""

BODY_END = """<script src="http://graingert.co.uk/shareNice/code.js"></script>"""

And you should now see a sharing box at the bottom right of the page.

Main problem remaining is that it doesn't really look good and integrated in the page layout. I suggest changing the code to this which looks nicer, but still has some placement issues:

SOCIAL_BUTTONS_CODE = """<div id="shareNice" data-share-label="Share"
    data-color-scheme="black" data-icon-size="32" data-panel-bottom="plain"
    data-services="plus.google.com,facebook.com,email,twitter.com"
    style="position: absolute; left: 20px; top: 60px;"></div>"""

If anyone comes up with a better idea of styling/placement, just let me know ;-)

One bad bit of this so far is that you are now using a script from another site, and that doesn't let Nikola perform as many optimizations to your page as it could. So, if you really want to go the extra mile to save a few KB and round trips, you could install your own copy from the github repo and use that instead of the copy at sharenice.org.

Then, you can create your own theme inheriting from the one you are using and add the CSS and JS files from ShareNice into your bundles configuration so they are combined and minified.

SocialSharePrivacy

The Hard Way

SocialSharePrivacy is "a jQuery plugin that lets you add social share buttons to your website that don't allow the social sites to track your users." Nice!

Let's go step-by-step into integrating SocialSharePrivacy into a Nikola site. To improve privacy, they recommend you not use the hosted service so we'll do it the hard way, by getting and distributing everything in our own site.

https://github.com/panzi/SocialSharePrivacy

For testing purposes, let's do it on a demo site:

$ nikola init --demo ssp_test
A new site with example data has been created at ssp_test.
See README.txt in that folder for more information.
$ cd ssp_test/

To see what's going on, let's start Nikola in "auto mode". This should build the site and open a web browser showing the default configuration, with the AddThis widget:

$ nikola auto -b

Now, download the current version and unzip it. You will have a SocialSharePrivacy-master folder with lots of stuff in it.

First, we need to build it (this requires a working and modern uglifyjs, this may not be easy):

$ cd SocialSharePrivacy-master
$ sh build.sh -m gplus,twitter,facebook,mail -s "/assets/css/socialshareprivacy.css" -a off

You will now have several files in a build folder. We need to bring them into the site:

$ cp -Rv SocialSharePrivacy-master/build/* files/
$ cp -R SocialSharePrivacy-master/images/ files/assets/

Edit your conf.py:

BODY_END = """
<script src="/javascripts/jquery.socialshareprivacy.min.js"></script>
<script>
$(document).ready(function () {
    $('.share').socialSharePrivacy();
});
</script>
"""

SOCIAL_BUTTONS_CODE = """<div class="share"></div>"""

In my experience this produces a broken, duplicate, semi-working thing. YMMV and if you make it work correctly, let me know how :-)

The Easy Way

Go to http://panzi.github.io/SocialSharePrivacy/ and use the provided form to get the code. Make sure you check "I already use JQuery" if you are using one of the themes that require it, like site or default, select the services you want, and use your disqus name if you have one.

It will give you 3 code snippets:

"Insert this once in the head of your page"

Put it in BODY_END

"Insert this wherever you want a share widget displayed"

Put it in SOCIAL_BUTTONS_CODE

"Insert this once anywhere after the other code"

Put it in BODY_END

That should give you a working integration (not tested)

A BID FOR FORTUNE OR; DR. NIKOLA'S VENDETTA

By GUY ­BOOTH­BY

Au­thor of “Dr. Niko­la,” “The Beau­ti­ful White Dev­il,” etc., etc.

/images/frontispiece.jpg

The Project Guten­berg EBook of A Bid for For­tune, by Guy ­Booth­by

This eBook is for the use of any­one any­where at no cost and with­ al­most no re­stric­tions what­so­ev­er. You may copy it, give it away or re-use it un­der the terms of the Project Guten­berg Li­cense in­clud­ed with this eBook or on­line at www.guten­berg.org

Ti­tle: A Bid for For­tune or Dr. Niko­la’s Ven­det­ta

Au­thor: Guy ­Booth­by

Re­lease Date: May 29, 2007 [E­Book #21640]

Lan­guage: English

Pro­duced by Mar­i­lyn­da Fraser-­Cun­lif­fe, Mary Mee­han and the On­line Dis­trib­uted Proof­read­ing Team at http://www.pgdp.net

Orig­i­nal­ly pub­lished by:

WARD, LOCK & CO., LIM­IT­ED LON­­DON, MEL­BOURNE AND TORON­­TO 1918

/images/illus_001.jpg

PART I

PROLOGUE

The man­ag­er of the new Im­pe­ri­al Restau­rant on the Thames Em­bank­­ment wen­t in­­to his lux­u­ri­ous pri­­vate of­­fice and shut the door. Hav­ing done so, he ­­first scratched his chin re­flec­­tive­­ly, and then took a let­ter from the ­­draw­er in which it had re­­posed for more than two months and pe­rused it ­­care­­ful­­ly. Though he was not aware of it, this was the thir­ti­eth time he had read it since break­­fast that morn­ing. And yet he was not a whit n­ear­er un­der­­s­tand­ing it than he had been at the be­gin­n­ing. He turned it over and scru­ti­nized the back, where not a sign of writ­ing was to be seen; he held it up to the win­­dow, as if he might hope to dis­­­cov­­er ­­some­thing from the wa­ter-­­mark; but there was noth­ing in ei­ther of the­se ­­places of a na­­ture cal­cu­lat­ed to set his trou­bled mind at rest. Then he ­­took a mag­nif­i­­cent re­­peater watch from his waist­­coat pock­­et and glanced at the di­al; the hands stood at half-­­past sev­en. He im­me­di­ate­­ly threw the let­ter on the table, and as he did so his anx­i­e­ty found re­lief in­­ ­­word­s.

It’s re­al­­ly the most ex­­tra­or­di­­nary af­­fair I ev­er had to do with­­,” he re­­marked. “And as I’ve been in the busi­­ness just three­­-and-thir­­ty years at eleven a.m. next Mon­­day morn­ing, I ought to know some­thing about it. I on­­ly hope I’ve done right, that’s al­l.”

As he spoke, the chief book­keep­er, who had the tre­ble ad­van­tage of be­ing ­tal­l, pret­ty, and just eight-and-twen­ty years of age, en­tered the room. She no­ticed the open let­ter and the look up­on her chief’s face, and her cu­rios­i­ty was pro­por­tion­ate­ly ex­cit­ed.

You seem wor­ried, Mr. McPher­­son­,” she said ten­der­­ly, as she put down the pa­pers she had brought in for his sig­­na­­ture.

You have just hit it, Miss O’­­Sul­li­­van,” he an­swered, push­ing them ­­far­ther on to the ta­ble. “I am wor­ried about many things, but ­­par­tic­u­lar­­ly about this let­ter.”

He hand­ed the epis­tle to her, and she, be­ing de­sirous of im­press­ing him with her busi­ness ca­pa­bil­i­ties, read it with os­ten­ta­tious care. But it was no­tice­able that when she reached the sig­na­ture she too turned back­ ­to the be­gin­ning, and then de­lib­er­ate­ly read it over again. The man­ager rose, crossed to the man­tel­piece, and rang for the head wait­er. Hav­ing re­lieved his feel­ings in this way, he seat­ed him­self again at his writ­ing-table, put on his glass­es, and stared at his com­pan­ion, while wait­ing for her to s­peak.

It’s very fun­ny,” she said. “Very fun­ny in­deed!”

It’s the most ex­­tra­or­di­­nary com­­mu­ni­­ca­­tion I have ev­er re­­ceived,” he replied with con­vic­­tion. “Y­ou see it is writ­ten from Cuyaba, Brazil. The ­­date is three months ago to a day. Now I have tak­en the trou­ble to find­­ out where and what Cuyaba is.”

He made this con­fes­sion with an air of con­scious pride, and hav­ing done ­so, laid him­self back in his chair, stuck his thumbs in­to the arm­holes of his waist­coat, and looked at his fair sub­or­di­nate for ap­proval. Nor was he des­tined to be dis­ap­point­ed. He was a bach­e­lor in pos­ses­sion of a s­nug in­come, and she, be­sides be­ing pret­ty, was a la­dy with a keen eye­ ­to the main chance.

And where is Cuyaba?” she asked humbly.

Cuyaba,” he replied, rolling his tongue with con­sid­er­able rel­ish round his un­­con­s­cious mis­­pro­­nun­­ci­a­­tion of the name, “is a town al­­most on the west­­ern or Bo­li­­vian bor­der of Brazil. It is of mod­­er­ate size, is si­t­u­at­ed on the banks of the riv­er Cuyaba, and is con­sid­er­ably con­nec­t­ed with the fa­­mous Brazil­ian Di­a­­mond ­­Field­­s.”

And does the writ­er of this let­ter live there?”

I can­not say. He writes from there—that is enough for us.”

And he or­ders din­n­er for four—here, in a pri­­vate room over­look­ing the river, three months ahead­­—punc­­tu­al­­ly at eight o’­­clock, gives you a list of the things he wants, and even ar­ranges the dec­o­ra­­tion of the ta­ble. Says he has nev­er seen ei­ther of his three friends be­­fore; that one of them hails from (here she con­­sult­ed the let­ter again) Hang-­­chow, an­oth­er from Bloem­­fontein, while the third re­­sides, at pre­sen­t, in En­g­­land. Each one is to present an or­di­­nary vis­it­ing card with a red dot on it to the ­­porter in the hal­l, and to be shown to the room at once. I don’t un­der­­s­tand it at al­l.”

The man­ag­er paused for a mo­men­t, and then said de­lib­er­ate­ly,—”Hang-­chow is in Chi­na, Bloem­fontein is in South Africa.”

What a won­der­­ful man you are, to be sure, Mr. McPher­­son! I nev­er can think how you man­age to car­ry so much in your ­head­.”

There spoke the true wom­an. And it was a move in the right di­rec­tion, ­for the man­ag­er was sus­cep­ti­ble to her gen­tle in­flu­ence, as she had oc­ca­sion to ­know.

At this junc­ture the head wait­er ap­peared up­on the scene, and took up a ­po­si­tion just in­side the door­way, as if he were afraid of in­jur­ing the ­car­pet by com­ing ­far­ther.

Is No. 22 ready, Williams?”

Quite ready, sir. The wine is on the ice, and cook tells me he’ll be ready to dish punc­­tu­al to the ­­mo­­men­t.”

The let­ter says, ‘no elec­tric light; can­­dles with red shades.’ Have you put on those shades I got this ­­morn­ing?”

Just seen it done this very min­ute, sir.”

And let me see, there was one oth­­er thing.” He took the let­ter from the chief book­­keep­­er’s hand and glanced at it. “Ah, yes, a porce­lain saucer, and a small jug of new milk up­­on the man­tel­­piece. An ex­­traor­di­­nary re­quest, but has it been at­­tend­ed ­­to?”

I put it there my­­self, sir.”

Who wait­­?”

Jones, Ed­­mund­s, Brook­s, and ­­Tomk­in­s.”

Very good. Then I think that will do. Stay! You had bet­ter tell the hall porter to look out for three gen­tle­­men pre­sen­t­ing plain vis­it­ing ­­cards with a lit­­tle red spot on them. Let Brooks wait in the hal­l, and when they ar­rive tell him to show them straight up to the ­­room.”

It shall be done, sir.”

The head wait­er left the room, and the man­ag­er stretched him­self in his chair, yawned by way of show­ing his im­por­tance, and then said ­solemn­ly,—

I don’t be­lieve they’ll any of them turn up; but if they do, this Dr. Niko­la, who­ev­er he may be, won’t be able to find fault with my ar­range­­ments.”

Then, leav­ing the dusty high road of Busi­ness, he and his com­pan­ion wan­dered in the shady bri­dle-­paths of Love—­to the end that when the chief book­keep­er re­turned to her own de­part­ment she had for­got­ten the s­trange din­ner par­ty about to take place up­stairs, and was busi­ly en­gaged up­on a cal­cu­la­tion as to how she would look in white satin and o­r­ange blos­som­s, and, that set­tled, fell to won­der­ing whether it was true, as Miss Joyce, a sub­or­di­nate, had been heard to de­clare, that the ­man­ag­er had once shown him­self par­tial to a cer­tain wid­ow with re­put­ed sav­ings and a share in an ex­ten­sive egg and dairy busi­ness.

At ten min­utes to eight pre­cise­ly a han­som drew up at the steps of the ho­tel. As soon as it stopped, an un­der­sized gen­tle­man, with a clean shaven coun­te­nance, a canon­i­cal cor­po­ra­tion, and bow legs, dressed in a de­cid­ed­ly cler­i­cal gar­b, alight­ed. He paid and dis­charged his cab­man, and then took from his tick­et pock­et an or­di­nary white vis­it­ing card, which he pre­sent­ed to the gold-laced in­di­vid­u­al who had opened the apron. The lat­ter, hav­ing not­ed the red spot, called a wait­er, and the rev­erend gen­tle­man was im­me­di­ate­ly es­cort­ed up­stairs.

Hard­ly had the at­ten­dant time to re­turn to his sta­tion in the hal­l, be­fore a sec­ond cab made its ap­pear­ance, close­ly fol­lowed by a third. Out of the sec­ond jumped a tal­l, ac­tive, well-built man of about thir­ty years of age. He was dressed in evening dress of the lat­est fash­ion, and ­to con­ceal it from the vul­gar gaze, wore a large In­ver­ness cape of heavy ­tex­ture. He al­so in his turn hand­ed a white card to the porter, and, hav­ing done so, pro­ceed­ed in­to the hal­l, fol­lowed by the oc­cu­pant of the last cab, who had close­ly copied his ex­am­ple. This in­di­vid­u­al was al­so in evening dress, but it was of a dif­fer­ent stam­p. It was old-­fash­ioned and had seen much use. The wear­er, too, was taller than the or­di­nary run of men, while it was no­tice­able that his hair was snow-white, and that his face was deeply pit­ted with small­pox. Af­ter dis­pos­ing of their hat­s and coats in an an­te-­room, they reached room No. 22, where they found the gen­tle­man in cler­i­cal cos­tume pac­ing im­pa­tient­ly up and ­down.

Left alone, the tallest of the tri­o, who for want of a bet­ter ti­tle we ­may call the Best Dressed Man, took out his watch, and hav­ing glanced at it, looked at his com­pan­ion­s. “Gentle­men,” he said, with a slight Amer­i­can ac­cen­t, “it is three min­utes to eight o’­clock. My name is Eas­t­over!”

I’m glad to hear it, for I’m most un­­com­­mon­­ly hun­­gry,” said the nex­t ­­tallest, whom I have al­ready de­scribed as be­ing so marked by dis­­ease. “My name is Pren­der­­gast!”

We on­­ly wait for our friend and host,” re­­marked the cler­i­­cal gen­tle­­man, as if he felt he ought to take a share in the con­ver­sa­­tion, and then, as an af­terthought, he con­t­in­ued, “My name is Bax­ter!”

They shook hands all round with marked cor­dial­i­ty, seat­ed them­selves a­gain, and took it in turns to ex­am­ine the ­clock.

Have you ev­er had the plea­­sure of meet­ing our host be­­fore?” asked Mr. Bax­ter of Mr. Pren­der­­gast.

Nev­er,” replied that gen­tle­­man, with a shake of his head. “Per­haps Mr. Eas­t­over has been more ­­for­­tu­­nate?”

Not I,” was the brief re­join­der. “I’ve had to do with him off and on ­­for longer than I care to reck­­on, but I’ve nev­er set eyes on him up to ­­date.”

And where may he have been the first time you heard from him?”

In Nashville, Ten­­nessee,” said Eas­t­over. “After that, Tahu­­pa­­pa, New Zealand; af­ter that, Pa­peete, in the So­­ci­e­ty Is­­land­s; then Pekin, Chi­­na. And y­ou?”

First time, Brus­sel­s; sec­ond, Monte Video; third, Man­­dalay, and then the Gold Coast, Africa. It’s your turn, Mr. Bax­ter.”

The cler­gy­man glanced at the time­piece. It was ex­act­ly eight o’­clock­. “­First time, Cab­ul, Afghanistan; sec­ond, Ni­jni Nov­gorod, Rus­si­a; third, Wilcan­ni­a, Dar­ling River, Aus­trali­a; fourth, Val­paraiso, Chili; fifth, ­Na­gasak­i, ­Japan.”

He is ev­i­­den­t­­ly a great trav­eller and a most mys­te­ri­ous per­­son­.”

He is more than that,” said Eas­t­over with con­vic­­tion; “he is late for d­in­n­er!”

Pren­der­gast looked at his watch.

That clock is two min­utes fast. Hark, there goes Big Ben! Eight ex­ac­t­­ly.”

As he spoke the door was thrown open and a voice an­nounced “Dr. Niko­la.”

The three men sprang to their feet si­mul­ta­ne­ous­ly, with ex­cla­ma­tions of as­ton­ish­men­t, as the man they had been dis­cussing made his ap­pear­ance.

It would take more time than I can spare the sub­ject to give you an ad­e­quate and in­clu­sive de­scrip­tion of the per­son who en­tered the room at that mo­men­t. In stature he was slight­ly above the or­di­nary, his shoul­ders were broad, his limbs per­fect­ly shaped and plain­ly mus­cu­lar, but very slim. His head, which was mag­nif­i­cent­ly set up­on his shoul­der­s, was adorned with a pro­fu­sion of glossy black hair; his face was des­ti­tute of beard or mous­tache, and was of oval shape and hand­some ­mould­ing; while his skin was of a dark olive hue, a colour which har­mo­nized well with his pierc­ing black eyes and pearly teeth. His hand­s and feet were smal­l, and the great­est dandy must have ad­mit­ted that he was ir­re­proach­ably dressed, with a neat­ness that bor­dered on the pu­ri­tan­i­cal. In age he might have been any­thing from eight-and-twen­ty to ­forty; in re­al­i­ty he was thir­ty-three. He ad­vanced in­to the room and walked with out­-stretched hand di­rect­ly across to where Eas­t­over was ­s­tand­ing by the ­fire­place.

Mr. Eas­t­over, I feel cer­­tain,” he said, fix­ing his glit­ter­ing eyes up­­on the man he ad­­dressed, and al­low­ing a cu­ri­ous smile to play up­­on his ­­face.

That is my name, Dr. Niko­la,” the oth­­er an­swered with ev­i­­dent sur­prise. “But how on earth can you dis­­t­in­guish me from your oth­­er guest­s?”

Ah! it would sur­prise you if you knew. And Mr. Pren­der­­gast, and Mr. Bax­ter. This is de­­light­­ful; I hope I am not late. We had a col­li­­sion in­­ the Chan­nel this morn­ing, and I was al­­most afraid I might not be up to ­­time. Din­n­er seems ready; shall we sit down to it?” They seat­ed them­­selves, and the meal com­­menced. The Im­pe­ri­al Restau­rant has earned an en­vi­able rep­u­­ta­­tion for do­ing things well, and the din­n­er that night ­­did not in any way de­­tract from its lus­tre. But, de­­light­­ful as it al­l was, it was no­tice­able that the three guests paid more at­ten­­tion to their host than to his ex­cel­­lent menu. As they had said be­fore his ar­rival, they had all had deal­ings with him for sev­er­al years, but what those deal­ings were they were care­ful not to de­scribe. It was more than ­pos­si­ble that they hard­ly liked to re­mem­ber them them­selves.

When cof­fee had been served and the ser­vants had with­drawn, Dr. Niko­la rose from the table, and went across to the mas­sive side­board. On it s­tood a bas­ket of very cu­ri­ous shape and work­man­ship. This he opened, and as he did so, to the as­ton­ish­ment of his guest­s, an enor­mous cat, as black as his mas­ter’s coat, leaped out on to the floor. The rea­son for the saucer and jug of milk be­came ev­i­den­t.

Seat­ing him­self at the ta­ble again, the host fol­lowed the ex­am­ple of his guests and lit a cigar, blow­ing a cloud of smoke lux­u­ri­ous­ly through his del­i­cate­ly chis­elled nos­tril­s. His eyes wan­dered round the cor­nice of the room, took in the pic­tures and dec­o­ra­tions, and then came down to meet the faces of his com­pan­ion­s. As they did so, the black cat, hav­ing fin­ished its meal, sprang on to his shoul­der to crouch there, watch­ing the three men through the curl­ing smoke drift with its green blink­ing, ­fiendish eye­s. Dr. Niko­la smiled as he no­ticed the ef­fect the an­i­mal had upon his guest­s.

Now shall we get to busi­­ness?” he said briskly.

The oth­ers al­most si­mul­ta­ne­ous­ly knocked the ash­es off their cigars and brought them­selves to at­ten­tion. Dr. Niko­la’s dain­ty, lan­guid man­ner seemed to drop from him like a cloak, his eyes bright­ened, and his voice, when he spoke, was clean cut as chis­elled sil­ver.

You are doubt­­less anx­ious to be in­­­formed why I sum­­moned you from al­l ­­parts of the globe to meet me here to-night? And it is very nat­u­ral you should be. But then, from what you know of me, you should not be ­­sur­prised at any­thing I ­­do.”

His voice dropped back in­to its old tone of gen­tle lan­guor. He drew in a ­great breath of smoke and then sent it slow­ly out from his lips again. His eyes were half closed, and he drummed with one fin­ger on the table edge. The cat looked through the smoke at the three men, and it seemed ­to them that he grew ev­ery mo­ment larg­er and more fe­ro­cious. Present­ly his own­er took him from his per­ch, and seat­ing him on his knee fell to stroking his fur, from head to tail, with his long slim fin­ger­s. It was as if he were draw­ing in­spi­ra­tion for some dead­ly mis­chief from the un­can­ny beast.

To pre­f­ace what I have to say to you, let me tell you that this is by ­­far the most im­­por­­tant busi­­ness for which I have ev­er re­quired your help. (Three slow strokes down the cen­tre of the back, and one round each ear.) When it first came in­­­to my mind I was at a loss who to trust in the mat­ter. I thought of Ven­­don, but I found Ven­­don was dead. I thought of Brown­low, but Brown­low was no longer faith­­ful. (T­­wo strokes ­­down the back and two on the throat.) Then bit by bit I re­mem­bered you. I was in Brazil at the time. So I sent for you. You came. So far so ­­good.”

He rose, and crossed over to the fire­place. As he went the cat crawled back to its orig­i­nal po­si­tion on his shoul­der. Then his voice changed once more to its for­mer busi­ness-­like ­tone.

I am not go­ing to tell you very much about it. But from what I do tel­l y­ou, you will be able to gath­­er a great deal and imag­ine the rest. To be­­gin with, there is a man liv­ing in this world to-­­day who has done me a ­­great and last­ing in­­jury. What that in­­jury is is no con­cern of yours. Y­ou would not un­der­­s­tand if I told you. So we’ll leave that out of the ques­­tion. He is im­­mense­­ly rich. His cheque for £300,000 would be honoured by his bank at any minute. Ob­vi­ous­­ly he is a pow­er. He has had rea­­son to know that I am pit­t­ing my wits against his, and he flat­ter­s him­­self that so far he has got the bet­ter of me. That is be­­cause I am ­­draw­ing him on. I am ma­­tur­ing a plan which will make him a poor and a very mis­­er­able man at one and the same time. If that scheme suc­ceed­s, and I am sat­is­­fied with the way you three men have per­­formed the parts I shall call on you to play in it, I shall pay to each of you the sum of £10,000. If it does­n’t suc­ceed, then you will each re­­ceive a thou­sand and your ex­pen­s­es. Do you fol­low me?”

It was ev­i­dent from their faces that they hung up­on his ev­ery ­word.

But, re­mem­ber, I de­­mand from you your whole and en­tire labour. While y­ou are serv­ing me you are mine body and soul. I know you are trust­­wor­thy. I have had good proof that you are—­­par­­don the ­ex­pres­­sion—un­scrupu­lous, and I flat­ter my­­self you are silen­t. What is ­­more, I shall tell you noth­ing be­yond what is nec­es­sary for the car­ry­ing out of my scheme, so that you could not be­­tray me if you would. Now for my ­­plan­s!”

He sat down again and took a pa­per from his pock­et. Hav­ing pe­rused it, he turned to Eas­t­over.

You will leave at on­ce—that is to say, by the boat on Wednes­­day—­­for Sy­d­ney. You will book your pas­sage to-­­mor­row morn­ing, first thing, and join her in Ply­­mouth. You will meet me to-­­mor­row evening at an ad­­dress I will send you, and re­­ceive your fi­­nal in­­struc­­tion­s. ­­Good-night.”

See­ing that he was ex­pect­ed to go, Eas­t­over rose, shook hand­s, and left­ the room with­out a word. He was too as­ton­ished to hes­i­tate or to say any­thing.

Niko­la took an­oth­er let­ter from his pock­et and turned to Pren­der­gast. “You will go down to Dover to-night, cross to Paris to-­mor­row morn­ing, and leave this let­ter per­son­al­ly at the ad­dress you will find writ­ten on it. On Thurs­day, at half-­past two pre­cise­ly, you will de­liv­er me an an­swer in the porch at Char­ing Cross. You will find suf­fi­cient mon­ey in­ that en­ve­lope to pay all your ex­pens­es. Now ­go!”

At half-­­past two you shall have your an­swer. ­­Good-night.”

Good-night.”

When Pren­der­gast had left the room, Dr. Niko­la lit an­oth­er cigar and ­turned his at­ten­tions to Mr. Bax­ter.

Six months ago, Mr. Bax­ter, I found for you a sit­u­a­­tion as tu­­tor to the y­oung Mar­quis of Beck­­en­ham. You still hold it, I ­­sup­­pose?”

I ­­do.”

Is the fa­ther well dis­­­posed to­ward­s y­ou?”

In ev­ery way. I have done my best to in­­­gra­ti­ate my­­self with him. That was one of your in­struc­­tion­s.”

Yes, yes! But I was not cer­­tain that you would suc­ceed. If the old man is any­thing like what he was when I last met him he must still be a d­if­­fi­cult per­­son to deal with. Does the boy like y­ou?”

I hope ­­so.”

Have you brought me his pho­­to­­graph as I di­rec­t­ed?”

I have. Here it is.”

Bax­ter took a pho­to­graph from his pock­et and hand­ed it across the table.

Good. You have done very well, Mr. Bax­ter. I am pleased with you. ­­To-­­mor­row morn­ing you will go back to Y­ork­shire——”

I beg your par­­don, Bournemouth. His Grace owns a house near Bournemouth, which he oc­cu­pies dur­ing the sum­mer ­­mon­th­s.”

Very well—then to-­­mor­row morn­ing you will go back to Bournemouth and ­­con­t­in­ue to in­­­gra­ti­ate your­­self with fa­ther and son. You will al­­so be­gin ­­to im­­plant in the boy’s mind a de­sire for trav­el. Don’t let him be­­come aware that his de­sire has its source in you—but do not fail to fos­­ter it all you can. I will com­­mu­ni­­cate with you fur­ther in a day or two. Now ­­go.”

Bax­ter in his turn left the room. The door closed. Dr. Niko­la picked up­ the pho­to­graph and stud­ied it.

The like­­ness is un­mis­­tak­able—or it ought to be. My friend, my very dear friend, Wetherel­l, my toils are clos­ing on you. My ar­range­­ments are per­­fec­t­ing them­­selves ad­mirably. Pre­sen­t­­ly, when all is com­­plete, I shall press the lev­­er, the ma­ch­in­ery will be set in mo­­tion, and you will find your­­self be­ing slow­­ly but sure­­ly ground in­­­to pow­der. Then you will ­­hand over what I wan­t, and be sor­ry you thought fit to baulk Dr. Niko­la!”

He rang the bell and or­dered his bil­l. This du­ty dis­charged, he placed the cat back in its pris­on, shut the lid, de­scend­ed with the bas­ket to the hal­l, and called a han­som. The porter in­quired to what ad­dress he should or­der the cab­man to drive. Dr. Niko­la did not re­ply for a mo­men­t, then he said, as if he had been think­ing some­thing out: “The Green ­Sailor pub­lic-­house, East In­dia Dock­ Road­.”


You can read the rest of “A Bid For For­tune; Or, Dr. Niko­la’s Vendet­ta” at Open Li­brary

Path Handlers for Nikola

Nikola supports special links with the syntax link://kind/name. In templates you can also use _link(kind, name). You can add query strings (?key=value) for extra arguments, or pass keyword arguments to _link in templates (support and behavior depends on path handlers themselves). Fragments (#anchor) will be appended to the transformed link.

Here are the descriptions for all the supported kinds.

archive

Link to archive path, name is the year.

Example:

link://archive/2013 => /archives/2013/index.html

author

Link to an author's page.

Example:

link://author/joe => /authors/joe.html

author_atom

Link to an author's Atom feed.

Example:

link://author_atom/joe => /authors/joe.atom

author_index

Link to the authors index.

Example:

link://authors/ => /authors/index.html

author_rss

Link to an author's RSS feed.

Example:

link://author_rss/joe => /authors/joe.xml

category

A link to a category. Takes page number as optional keyword argument.

Example:

link://category/dogs => /categories/dogs.html

category_atom

A link to a category's Atom feed.

Example:

link://category_atom/dogs => /categories/dogs.atom

category_index

A link to the category index.

Example:

link://category_index => /categories/index.html

category_rss

A link to a category's RSS feed.

Example:

link://category_rss/dogs => /categories/dogs.xml

filename

Link to post or page by source filename.

Example:

link://filename/manual.txt => /docs/handbook.html

gallery

Link to an image gallery's path.

It will try to find a gallery with that name if it's not ambiguous or with that path. For example:

link://gallery/london => /galleries/trips/london/index.html

link://gallery/trips/london => /galleries/trips/london/index.html

gallery_global

Link to the global gallery path, which contains all the images in galleries.

There is only one copy of an image on multilingual blogs, in the site root.

link://gallery_global/london => /galleries/trips/london/index.html

link://gallery_global/trips/london => /galleries/trips/london/index.html

(a gallery link could lead to eg. /en/galleries/trips/london/index.html)

gallery_rss

Link to an image gallery's RSS feed.

It will try to find a gallery with that name if it's not ambiguous or with that path. For example:

link://gallery_rss/london => /galleries/trips/london/rss.xml

link://gallery_rss/trips/london => /galleries/trips/london/rss.xml

index

Link to a numbered index.

Example:

link://index/3 => /index-3.html

index_atom

Link to a numbered Atom index.

Example:

link://index_atom/3 => /index-3.atom

index_rss

A link to the RSS feed path.

Example:

link://rss => /blog/rss.xml

listing

Return a link to a listing.

It will try to use the file name if it's not ambiguous, or the file path.

Example:

link://listing/hello.py => /listings/tutorial/hello.py.html

link://listing/tutorial/hello.py => /listings/tutorial/hello.py.html

listing_source

Return a link to the source code for a listing.

It will try to use the file name if it's not ambiguous, or the file path.

Example:

link://listing_source/hello.py => /listings/tutorial/hello.py

link://listing_source/tutorial/hello.py => /listings/tutorial/hello.py

post_path

Link to the destination of an element in the POSTS/PAGES settings.

Example:

link://post_path/posts => /blog

root

Link to the current language's root.

Example:

link://root_path => /

link://root_path => /translations/spanish/

rss

A link to the RSS feed path.

Example:

link://rss => /blog/rss.xml

slug

Return a link to a post with given slug, if not ambiguous.

Example:

link://slug/yellow-camaro => /posts/cars/awful/yellow-camaro/index.html

tag

A link to a tag's page. Takes page number as optional keyword argument.

Example:

link://tag/cats => /tags/cats.html

tag_atom

A link to a tag's Atom feed.

Example:

link://tag_atom/cats => /tags/cats.atom

tag_index

A link to the tag index.

Example:

link://tag_index => /tags/index.html

tag_rss

A link to a tag's RSS feed.

Example:

link://tag_rss/cats => /tags/cats.xml

A reStructuredText Primer

The text below contains links that look like "(quickref)". These are relative links that point to the Quick reStructuredText user reference. If these links don't work, please refer to the master quick reference document.

Note

This document is an informal introduction to reStructuredText. The What Next? section below has links to further resources, including a formal reference.

Structure

From the outset, let me say that "Structured Text" is probably a bit of a misnomer. It's more like "Relaxed Text" that uses certain consistent patterns. These patterns are interpreted by a HTML converter to produce "Very Structured Text" that can be used by a web browser.

The most basic pattern recognised is a paragraph (quickref). That's a chunk of text that is separated by blank lines (one is enough). Paragraphs must have the same indentation -- that is, line up at their left edge. Paragraphs that start indented will result in indented quote paragraphs. For example:

This is a paragraph.  It's quite
short.

   This paragraph will result in an indented block of
   text, typically used for quoting other text.

This is another one.

Results in:

This is a paragraph. It's quite short.

This paragraph will result in an indented block of text, typically used for quoting other text.

This is another one.

Text styles

(quickref)

Inside paragraphs and other bodies of text, you may additionally mark text for italics with "*italics*" or bold with "**bold**". This is called "inline markup".

If you want something to appear as a fixed-space literal, use "``double back-quotes``". Note that no further fiddling is done inside the double back-quotes -- so asterisks "*" etc. are left alone.

If you find that you want to use one of the "special" characters in text, it will generally be OK -- reStructuredText is pretty smart. For example, this lone asterisk * is handled just fine, as is the asterisk in this equation: 5*6=30. If you actually want text *surrounded by asterisks* to not be italicised, then you need to indicate that the asterisk is not special. You do this by placing a backslash just before it, like so "\*" (quickref), or by enclosing it in double back-quotes (inline literals), like this:

``*``

Tip

Think of inline markup as a form of (parentheses) and use it the same way: immediately before and after the text being marked up. Inline markup by itself (surrounded by whitespace) or in the middle of a word won't be recognized. See the markup spec for full details.

Lists

Lists of items come in three main flavours: enumerated, bulleted and definitions. In all list cases, you may have as many paragraphs, sublists, etc. as you want, as long as the left-hand side of the paragraph or whatever aligns with the first line of text in the list item.

Lists must always start a new paragraph -- that is, they must appear after a blank line.

enumerated lists (numbers, letters or roman numerals; quickref)

Start a line off with a number or letter followed by a period ".", right bracket ")" or surrounded by brackets "( )" -- whatever you're comfortable with. All of the following forms are recognised:

1. numbers

A. upper-case letters
   and it goes over many lines

   with two paragraphs and all!

a. lower-case letters

   3. with a sub-list starting at a different number
   4. make sure the numbers are in the correct sequence though!

I. upper-case roman numerals

i. lower-case roman numerals

(1) numbers again

1) and again

Results in (note: the different enumerated list styles are not always supported by every web browser, so you may not get the full effect here):

  1. numbers

  1. upper-case letters and it goes over many lines

    with two paragraphs and all!

  1. lower-case letters

    1. with a sub-list starting at a different number

    2. make sure the numbers are in the correct sequence though!

  1. upper-case roman numerals

  1. lower-case roman numerals

  1. numbers again

  1. and again

bulleted lists (quickref)

Just like enumerated lists, start the line off with a bullet point character - either "-", "+" or "*":

* a bullet point using "*"

  - a sub-list using "-"

    + yet another sub-list

  - another item

Results in:

  • a bullet point using "*"

    • a sub-list using "-"

      • yet another sub-list

    • another item

definition lists (quickref)

Unlike the other two, the definition lists consist of a term, and the definition of that term. The format of a definition list is:

what
  Definition lists associate a term with a definition.

*how*
  The term is a one-line phrase, and the definition is one or more
  paragraphs or body elements, indented relative to the term.
  Blank lines are not allowed between term and definition.

Results in:

what

Definition lists associate a term with a definition.

how

The term is a one-line phrase, and the definition is one or more paragraphs or body elements, indented relative to the term. Blank lines are not allowed between term and definition.

Preformatting (code samples)

(quickref)

To just include a chunk of preformatted, never-to-be-fiddled-with text, finish the prior paragraph with "::". The preformatted block is finished when the text falls back to the same indentation level as a paragraph prior to the preformatted block. For example:

An example::

    Whitespace, newlines, blank lines, and all kinds of markup
      (like *this* or \this) is preserved by literal blocks.
  Lookie here, I've dropped an indentation level
  (but not far enough)

no more example

Results in:

An example:

  Whitespace, newlines, blank lines, and all kinds of markup
    (like *this* or \this) is preserved by literal blocks.
Lookie here, I've dropped an indentation level
(but not far enough)

no more example

Note that if a paragraph consists only of "::", then it's removed from the output:

::

    This is preformatted text, and the
    last "::" paragraph is removed

Results in:

This is preformatted text, and the
last "::" paragraph is removed

Sections

(quickref)

To break longer text up into sections, you use section headers. These are a single line of text (one or more words) with adornment: an underline alone, or an underline and an overline together, in dashes "-----", equals "======", tildes "~~~~~~" or any of the non-alphanumeric characters = - ` : ' " ~ ^ _ * + # < > that you feel comfortable with. An underline-only adornment is distinct from an overline-and-underline adornment using the same character. The underline/overline must be at least as long as the title text. Be consistent, since all sections marked with the same adornment style are deemed to be at the same level:

Chapter 1 Title
===============

Section 1.1 Title
-----------------

Subsection 1.1.1 Title
~~~~~~~~~~~~~~~~~~~~~~

Section 1.2 Title
-----------------

Chapter 2 Title
===============

This results in the following structure, illustrated by simplified pseudo-XML:

<section>
    <title>
        Chapter 1 Title
    <section>
        <title>
            Section 1.1 Title
        <section>
            <title>
                Subsection 1.1.1 Title
    <section>
        <title>
            Section 1.2 Title
<section>
    <title>
        Chapter 2 Title

(Pseudo-XML uses indentation for nesting and has no end-tags. It's not possible to show actual processed output, as in the other examples, because sections cannot exist inside block quotes. For a concrete example, compare the section structure of this document's source text and processed output.)

Note that section headers are available as link targets, just using their name. To link to the Lists heading, I write "Lists_". If the heading has a space in it like text styles, we need to quote the heading "`text styles`_".

Document Title / Subtitle

The title of the whole document is distinct from section titles and may be formatted somewhat differently (e.g. the HTML writer by default shows it as a centered heading).

To indicate the document title in reStructuredText, use a unique adornment style at the beginning of the document. To indicate the document subtitle, use another unique adornment style immediately after the document title. For example:

================
 Document Title
================
----------
 Subtitle
----------

Section Title
=============

...

Note that "Document Title" and "Section Title" above both use equals signs, but are distinct and unrelated styles. The text of overline-and-underlined titles (but not underlined-only) may be inset for aesthetics.

Images

(quickref)

To include an image in your document, you use the the image directive. For example:

.. image:: /images/nikola.png

results in:

/images/nikola.png

The /images/nikola.png part indicates the filename of the image you wish to appear in the document. There's no restriction placed on the image (format, size etc). If the image is to appear in HTML and you wish to supply additional information, you may:

.. image:: /images/nikola.png
   :height: 100
   :width: 200
   :scale: 50
   :alt: alternate text

See the full image directive documentation for more info.

What Next?

This primer introduces the most common features of reStructuredText, but there are a lot more to explore. The Quick reStructuredText user reference is a good place to go next. For complete details, the reStructuredText Markup Specification is the place to go 1.

Users who have questions or need assistance with Docutils or reStructuredText should post a message to the Docutils-users mailing list.

1

If that relative link doesn't work, try the master document: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html.