Welcome to Felix Felicis

Felix Felicis (aka liquidluck) is a static website generator. The name of “Felix Felicis” comes from Harry Porter; It is a magic potion that gives the drinker luck.

If you want to contribute to this project, fork liquidluck and send a pull request for your changes. Have a glance at Development section for details. If you just want to use it, you should watch the project for updates.

User’s Guide

Installation

If you are familiar with Python, it is strongly suggested that you install everything in virtualenv.

If you are a pythoner, and you have no idea about virtualenv, please do search the internet.

Distribute and Pip

If you are on Linux or Mac OS X, you are the lucky one:

$ sudo pip -U install liquidluck

If no pip available, try easy_install:

$ sudo easy_install -U liquidluck

Sorry, I have no knowledge about Windows, but it really works on Windows. Cygwin and MinGW would make a better life with UNIX software on Windows.

Install with GIT

If you prefer git, that is great. You can get the very latest code at GitHub:

$ git clone http://github.com/lepture/liquidluck.git

Mac User Attention

We use misaka (python wrapper for sundown) as the Markdown engine. It requires C compiler, which means you should install Xcode.

Then open Xcode’s preference (command + ,), select Downloads tab, and install Command Line Tools.

I strongly suggest that you install the Command Line Tools, even if you don’t use Felix Felicis. You will need it somewhere else.

Install on Windows

It is strongly suggested that you use Cygwin as the environment.

You should install these packages:

  • python interpreters 2.x (or 3.x)
  • make (Devel – the GNU version of make)
  • gcc (gcc-core and gcc-g++)
  • git (Devel – Fast version control ....)
  • ca-certificates

Then head over to setuptools and install it, you will get easy_install.

Get Started

This section assumes that you already have Felix Felicis (liquidluck) installed. If you do not, header over to the Installation section.

Create a website

Now that you have Felix Felicis installed, let’s create a website:

$ cd ~
$ mkdir website
$ cd website
$ liquidluck init

You will be asked some questions. If the question has a default value, we don’t change it, just hit Enter.

See what happens:

$ ls
content     settings.yml

Create a Post

Create a post with your favorite editor, for example:

$ vim content/hello-world.md
# Hello World

- date: 2012-12-12
- category: life
- tags: python, code

----------------

Hello World. This is a DEMO post.

Build the website

Now that you have written a post, let’s create the website:

$ cd ~/website
$ liquidluck build -v
$ ls
content     deploy      settings.py

That means the website is created, so you can test it now:

$ liquidluck server

Open your browser: http://127.0.0.1:8000.

For more on the Felix Felicis server, see Preview Server.

Write more

You can test more posts yourself.

Learn Commands

Get all commands:

$ liquidluck -h

List all themes:

$ liquidluck search

Install a theme:

$ liquidlcuk install {{name}}

Writing

Markup

Felix Felicis (liquidluck) supports markup of Markdown and reStructuredText. It is suggested that you write in Markdown, it’s easier.

There are three parts in each post:

  • title – Hello World in the example
  • meta – date, category, tags in the example
  • content – everything below the first -------

An example in markdown:

# Felix Felicis                 <-------- this is title

- date: 2012-12-12 12:12        <-------- this is meta
- tags: python, blog, web

Here is the description.

--------------------------      <-------- this seprate meta and content

Hello World! Welcome to the     <-------- this is content
Felix Felicis World.

```                             <-------- this is normal code
a {
    color: black;
}
```

````css                         <-------- if code wrapped with 4 `, the code
a {                                       will be injected to this page
    color: black;
}
````

An example in reStructuredText:

Felix Felicis
================

:date: 2012-12-12 12:12
:tags: python, blog, web


Hello World! Welcome to the Felix Felicis World.

::

    /* normal code */
    a {
        color: black;
    }


.. sourcecode:: css

    /* hightlight code */

    a {
        color: black;
    }

Meta

Metadata that Felix Felicis supports natively:

  • date
  • public – default is true, if set to false, this post won’t be included in archive
  • tags – tags are seprated by comma
  • category
  • summary
  • folder – relative filepath, for example /home/user/blog/content/a/a.md, folder will be a
  • author – see Multiple Authors for detail
  • template – see Template for detail

which means you can access them in template with a shortcut, for example: {{post.tags}}.

Metadata that Felix Felicis created itself:

Page

Page is the same as post, except that post contains date, page doesn’t, post follows permalink, page doesn’t.

A example of page in Markdown:

# Hello Page

- tags: python, web         <----------- page has no date

----------------

Hello Page

```python
def hello():
    print("Hello Page")
```

Page doesn’t have a date, but it may contain some metadata.

Where will the page be rendered? For example, the path of the page:

content/                 <-------- source directory
    page1.md
    a_folder/
        page2.md

and it will be rendered to:

deploy/                  <-------- output directory
    page1.html
    a_folder/
        page2.html

It will ignore the site.prefix, and therefore, if your settings:

site = {
    'name': '...',
    ...
    'prefix': 'blog',
}

and you want to you pages to be rendered to blog folder, you have to:

content/
    blog/               <--------- place your pages under the prefix folder
        page1.md

File

Any file without a valid markup suffix (e.g. .md, .rst, .mkd ...) is a File. It will be copied to the same path:

content/
    robots.txt          <--------- this is a file
    media/
        a_pic.jpg       <--------- this is a file

And the output will be:

deploy/
    robots.txt
    media/
        a_pic.jpg

Hence, I suggest that you have a folder named media, and you can leave your picture resources there:

![alt](/media/a_pic.jpg "title")

Configuration

Felix Felicis support yaml, python and json format config file. You can create the config file with:

$ liquidluck init

Overview

The default python format config file:

# -*- coding: utf-8 -*-
#: settings for liquidluck

#: site information
#: all variables can be accessed in template with ``site`` namespace.
#: for instance: {{site.name}}
site = {
    "name": "Felix Felicis",  # your site name
    "url": "http://lab.lepture.com/liquidluck/",  # your site url
    # "prefix": "blog",
}

#: this config defined information of your site
#: 1. where the resources  2. how should the site be generated
config = {
    "source": "content",
    "output": "deploy",
    "static": "deploy/static",
    "static_prefix": "/static/",
    "permalink": "{{date.year}}/{{filename}}.html",
    "relative_url": False,
    "perpage": 30,
    "feedcount": 20,
    "timezone": "+08:00",
}


author = {
    "default": "nickname",
    "vars": {}
}

#: active readers
reader = {
    "active": [
        "liquidluck.readers.markdown.MarkdownReader",
        # uncomment to activate rST reader
        # "liquidluck.readers.restructuredtext.RestructuredTextReader",
    ],
    "vars": {}
}

#: active writers
writer = {
    "active": [
        "liquidluck.writers.core.PostWriter",
        "liquidluck.writers.core.PageWriter",
        "liquidluck.writers.core.ArchiveWriter",
        "liquidluck.writers.core.ArchiveFeedWriter",
        "liquidluck.writers.core.FileWriter",
        "liquidluck.writers.core.StaticWriter",
        "liquidluck.writers.core.YearWriter",
        "liquidluck.writers.core.CategoryWriter",
        # "liquidluck.writers.core.CategoryFeedWriter",
        # "liquidluck.writers.core.TagWriter",
        # "liquidluck.writers.core.TagCloudWriter",
    ],
    "vars": {
        # uncomment if you want to reset archive page
        # "archive_output": "archive.html",
    }
}

#: theme variables
theme = {
    "name": "default",

    # theme variables are defined by theme creator
    # you can access theme in template with ``theme`` namespace
    # for instance: {{theme.disqus}}
    "vars": {
        #"disqus": "your_short_name",
        #"analytics": "UA-21475122-1",
    }
}

#: template variables
template = {
    "vars": {},
    "filters": {},
}

Multiple Authors

If your site has multiple authors, you can add them to your settings:

author = {
    'default': 'lepture',

    'vars': {
        'lepture': {
            'name': 'Hsiaoming Yang',
            'website': 'http://lepture.com',
            'email': 'lepture@me.com',
        },
        'kitty': {
            'name': 'Hello Kitty',
            'website': 'http://hellokitty.com',
        }
    }
}

And when you write a post, the default author is ‘lepture’, but you can change it by:

# Hello World

- date: 2012-12-12
- author: kitty

--------

content here

Access the author information in template as {{post.author.name}} and {{post.author.website}}.

For more information on template or theme design, head over to Theme section.

The default theme doesn’t show any information of the author, it is designed for personal blogging.

Readers

There are two readers in Felix Felicis, one is Markdown, and the other is reStructuredText.

Customize Reader

Issues that contain information on readers:

Reader Variables

Issues that contain information on readers variables:

Writers

There are many writers in Felix Felicis, and you can add more. If you want to add your own writer to Felix Felics, head over to Development.

Writers Variables

Every writer can define its own variable, for example the archive write, if you set:

writer = {
    'vars': {
        'archive_output': 'archive.html',
    }
}

The archive page will be write to archive.html instead of index.html.

Available writers variables (but you won’t need to change them):

  • post_template (post.html)
  • page_template (page.html)
  • archive_template (archive.html)
  • archive_output (index.html)
  • archive_feed_template (feed.xml)
  • year_template (archive.html)
  • tag_template (archive.html)
  • category_template (archive.html)
  • category_feed_template (feed.xml)

Design Pattern

The design pattern of Felix Felicis contains one significant principle:

Don’t create anything.

That means we didn’t (and will not) add any invalid markup like Jekyll and others do. Everything should be valid in its markup language.

And hence there will be no plugin or extension like:

{% gist id %}

Just like the zen of Python:

Beautiful is better than ugly.

Nothing is better than everything.

Theme

Template engine of Felix Felicis (liquidluck) is Jinja. It would be great if you have a little knowledge on Jinja Template. The basic syntax is simple, you should know them.

You can learn how to design your own theme by demo:

Please create your repo at github with liquidluck-theme- prefix. Remember to submit your theme at Theme Gallery.

Get all themes:

$ liquidluck search

Install a theme:

$ liquidluck install moment

Install a theme to the global theme gallery:

$ liquidluck install moment -g

Structure

A glance of a theme:

your_theme/
    settings.py                <---- theme variables
    filters.py                 <---- filters defined by theme
    static/                    <---- static files
        style.css
        ...
    templates/                 <---- template files
        archive.html
        post.html
        page.html

You don’t need to copy a feed.xml file. Only archive.html, post.html and page.html are required. But you can add more.

Template

Sometimes, you don’t need to create a total new theme, you just want to make some changes.

For example, you are using the default theme, which means in your settings:

theme = {
    'name': 'default'
}

You want to make some changes on the post page (like adding readability), in your blog directory, create a post.html template:

your_blog/
    settings.py
    content/
    _templates/
        post.html

And edit this post.html:

{% extends "layout.html" %}

{% block title %}{{post.title}} - {{site.name}}{% endblock %}

{% block main %}
<div class="hentry">
    <h1 class="entry-title">{{post.title}}</h1>
    <time class="updated" datetime="{{post.date|xmldatetime}}">{{post.date.strftime('%Y-%m-%d')}}</time>
    {% if template.readability %}
    <div class="rdbWrapper" data-show-read="1" data-show-send-to-kindle="1"></div>
    <script type="text/javascript" src="http://www.readability.com/embed.js" async></script>
    {% endif %}

    <div class="entry-content">
        {{post.content}}
    </div>
    <div class="entry-tags">
        {% for tag in post.tags %}
        <a href="{{ content_url(site.prefix, 'tag', tag, 'index.html') }}">{{tag}}</a>
        {% endfor %}
    </div>

    {% if theme.disqus %}
    <div id="disqus_thread"></div>
    <script type="text/javascript">
        var disqus_shortname = '{{theme.disqus}}';
        var disqus_title = '{{post.title}}';
        (function() {
            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
            dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
        })();
    </script>
    {% endif %}
</div>
{% endblock %}

And edit your settings, enable readability:

template = {
    'vars': {
        'readability': True,
    }
}

Variables

There are two levels of variables, global and templatable. Global means that this variable can be accessed in every template, and templatable means that this variable can be accessed in specify template.

Global Variables
  • system, this is all about Felix Felicis:

    {
        'name': 'Felix Felicis',
        'version': '....',
        'homepage': '....',
        'time': '....',
    }
    

    When you create your own theme, you should add copyright of Felix Felicis by:

    Powered by <a href="{{system.homepage}}">{{system.name}}</a> {{system.version}}
    

    {{system.time}} means current utc time.

  • site, you defined in your settings file:

    site = {
        'name': "Kitty's BLog",
        'url': 'http://www.example.com',
    }
    
  • theme, theme variable is defined by theme creator in the theme settings, and users can overwrite theme in blog settings theme_variables.

    For example, in the default theme’s settings, we have:

    navigation = [
        {'title': 'Home', 'link': '/'},
        {'title': 'About', 'link': '/about.html'},
    ]
    

    Users can rewrite it in blog settings:

    theme = {
        'vars': {
            'navigation': [
                {'title': 'Home', 'link': '/'},
                {'title': 'Life', 'link': '/life/'},
                {'title': 'Work', 'link': '/work/'},
            ]
        }
    }
    
  • template, template variable is defined by users in settings with:

    template = {
        'vars': {
            'readability': True,
        }
    }
    

    And it can be access in template by {{template.readability}}, this is very useful.

  • writer, this variable tells you which writer is rendering this page now:

    {
        'class': 'ArchiveWriter',
        'name': 'archive',
        'filepath': 'path/to/file.html',
    }
    
Templatable Variables

Templatable variables are only accessed in specify templates.

  • pagination, available in archive.html
  • post, available in post.html and page.html

Resource Variables

This variable is powerful, for example, {{resource.posts}} contains all your public posts. It is related to a writer.

  • {{resource.posts}}
  • {{resource.pages}}
  • {{resource.year}}: if you enabled YearWriter
  • {{resource.category}}: if you enabled CategoryWriter
  • {{resource.tag}}: if you enabled TagWriter
Functions
  • content_url
  • static_url

Filters

Filter is an important concept in Jinja Template.

Default Filters
  • xmldatetime
  • permalink, {{post|permalink}} to create the permalink of a post
  • tag_url
  • year_url
  • feed_updated
Theme Filters

Contributors

If you have designed a theme, you can submit it to the Theme Gallery

Development

Want to contribute to this project? Have no idea about how to read the code? And this section will tell you how to understand it.

Command line interface

You should start here, it would be much easier to understand the whole things. Take a look at cli.py.

Readers

Writers

Namespace

Utilities

Goodies

Gifts that makes Felix Felicis easy to use.

Preview Server

Preview your blog with:

$ liquidluck server
$ liquidluck server -p 8888
$ liquidluck server -p 8888 -s settings.py

Preview server now support livereload, when you are editing a post, it will auto compile and auto refresh the browser for you. Added in version 1.12

To enable livereload, your should install tornado:

$ pip install tornado

Oh My Zsh Plugin

If you are using oh-my-zsh, there is a plugin for you.

https://github.com/lepture/liquidluck/tree/master/oh-my-zsh-plugins

Copy liquidluck to ~/.oh-my-zsh/plugins:

$ cp -r oh-my-zsh-plugins/liquidluck ~/.oh-my-zsh/plugins/

Then edit your zshrc file:

plugins=(git ... liquidluck)

Now you can tab complete every Felix Felicis command:

$ liquidluck b(tab)
$ liquidluck build (tab)

Webhook

Felix Felicis supports webhook since v1.6. When you push to GitHub or BitBucket, your blog can generate itself.

First, you need to install Felix Felicis on your server:

$ pip install liquidluck

Second, your blog repo on your server:

$ git clone git://path/to/your/repo blog

Then, start webhook daemon in your blog:

$ cd blog
$ liquidluck webhook start -p 9876

Configure webhook on GitHub or BitBucket. We take GitHub as an example.

Head over to your blog source repo admin, select Service Hooks

github service hook

If you prefer BitBucket, you should select the POST service:

bitbucket service hook

If your server ip is 88.88.88.88, you can add a URL:

http://88.88.88.88:9876/webhook

And when you push to GitHub, your server will update the repo and generate the whole site.

Changelog

All history since the new Felix Felicis are listed here:

Version 3.7

Released on Nov 9th, 2012

  • code improvement (not bugfix)
  • add option quiet for liquidluck build
  • add option output for liquidluck build
  • livereload server more reliable

Version 3.6

Released on Nov 2nd, 2012

  • clean_folder is replaced by folder
  • clean_filepath is replaced by relative_filepath
  • delete Post.embed_author
  • livereload server work again
  • add resource.files params

Version 3.5

Released on Oct 31th, 2012

  • fix liquidluck search unicode bug #57
  • add theme.debug vars for preview server

Version 3.4

Released on Sep 20th, 2012

  • ATTENTION: settings.py in themes should be named as theme.py now
  • install and update theme
  • logging improvement

Version 3.3

Released on Sep 17th, 2012

  • support for [[]]
  • updates on default theme

Version 3.2

Released on Sep 13rd, 2012

  • bugfix for relative url
  • support for `

Version 3.1

Released on Sep 12nd, 2012

  • bugfix
  • change server host to 127.0.0.1

Version 3.0

Released on Sep 12nd, 2012

  • new config format: yaml, python, json
  • redesigned

Version 2.0

Released on Sep 7th, 2012

  • support for relative url
  • support for inject html, css, javascript
  • bugfix for server
  • code structure changed
  • github search api changed

Version 1.14

Released on Oct 23th, 2012

  • add render params: writer
  • API changed. liquidluck.readers.base.Post, delete filedir, add clean_filepath
  • force search theme from internet

Version 1.13

Released on Jul 16th, 2012

  • fix markdown meta parser
  • webhook deamon enhancement

Version 1.12

Released on Jul 9th, 2012

  • LiveReload Server
  • GitHub Search API fix
  • docutils is optional

Version 1.11

Released on Jun 20th, 2012

  • fix permalink filter, support {{filename}}/index.html now. #41
  • update default theme
  • improve command line interface. #43

Version 1.10

Released on Jul 17th, 2012

  • improve on feed render #40
  • config feed output tags
  • server bugfix
  • built in filters of tag_url and year_url

Version 1.9

Released on Jul 4th, 2012

  • improve server, can be used as a standalone app with autoindex support
  • default permalink changed to {{date.year}}/{{filename}}
  • timezone fix
  • update theme

Version 1.8

Released on Jul 1st, 2012

  • search theme from github
  • timezone support

Version 1.7

Released on Jun 29th, 2012

  • webhook supports submodule
  • webhook supports hg
  • preview server #35

Version 1.6

Released on Jun 29th, 2012

  • webhook support #33
  • add clean_title #32
  • table support in markdown

Version 1.5

Released on Jun 28th, 2012.

  • bugfix for static_url encoding error
  • command line interface changed #31
  • update the default theme

Version 1.4

Released on Jun 25th, 2012.

  • add TagCloudWriter
  • bugfix #24 #29

Version 1.3

Released on Jun 21th 2012.

  • customize markdown link transform
  • customize post class
  • add filedir property for post

Version 1.2

Released on Jun 19th 2012.

  • site[‘prefix’] configuration

Version 1.1

Released on Jun 19th 2012.

  • search and install theme available
  • bugfix issue#20

Version 1.0

Released on Jun 16th 2012. The new Felix Felicis.

Reporting bugs

We keep an issue tracker at GitHub, where you can report a bug by opening a new issue. If you want any help, please contact lepture@me.com; English and Chinese are accepted.

Felix Felicis

Felix Felicis is a magical potion, also known as liquidluck. It really gives the good luck to you.

Feedback

Feedback is greatly appreciated. If you have any questions, comments, random praise, or anonymous threats, shoot me an email.

Useful Links