Static site generators can be complex. Trakai makes it simple to get a blog up and running without harming other static content.
There's plenty of static site generators out there. Most of them are focused on building sites for the Next Big Thing with hundreds of pages. But what if you've got a few HTML files with your resumé on them, and you want to create a blog article on the latest programming trend?
When designing my own blog, I wanted something simple - that did just what I needed it to. I found the excellent Makesite by Sunaina Pai, but that was too focused on general site-making, and not blog-posting. So I adapted his work and added a bit of my bad code, with the goal of making it more powerful and effective. And it still can't do the fancy stuff. But it does what I need.
Trakai is currently in alpha. Code is still incomplete and unpolished, and features may change. It's primarily made for my own use, so I can't guarantee that it'll ever be in a better state.
Requires Python 3.6+, Python-Markdown, and Jinja 2.
Usage
Install using pip: pip install trakai
...and run as a command-line tool. trakai path/to/your/site
Trakai operates on the assumption that you have a bunch of static files already created - and a blog that you want to dynamically generate. Rather than editing all your files in the main site directory, and then uploading a build
directory, Trakai content is stored in a resources
directory that is exempt from upload, and generates content directly in a folder of the main site directory.
This approach means that using Trakai requires a bit more caution than most SSGs. Ensure that you don't have any pre-existing content that is at risk of being overwritten.
Writing Content
Blog content is written as individual Markdown files. All content in the posts_path
directory of your site (default: resources/content
) is transformed into a blog post, sorted by newest first, with the same file name as the Markdown file.
Metadata
Metadata is written like below, with the date being highly recommended (if not provided, the last modified date will be used, which isn't recommended, as you may want to correct something). The blank line separates metadata from the content.
title: My Blog Post summary: This is a post that I'm writing. date: 2020-1-31 Blog content lorem ipsum dolor amet...
Tags (enabled with the has_tags
configuration item) allow you to categorise your posts. Any page without a tags
item has no tags.
tags: Lithium, Rhodonite, Prismarine
For exact Markdown details, see the Python-Markdown documentation (metadata is handled by its meta
extension). And for advanced Markdown functionality, you can install more extensions by modifying the markdown_extensions
configuration item.
Ensure that metadata names don't conflict with pre-defined variables or configuration items (see below).
Templating
Rather than letting you define millions of your own templates, Trakai limits the range to four, all stored in the templates_path
directory (default: resources/templates
). If you don't define any of your own, it provides sensible defaults.
-
post.html
- An individual blog post.site_path/output_path/posts/
post name.html
-
list.html
- A list of posts. Used for all list pages, including tags and archives; these can be displayed differently using template logic.site_path/index.html
; plussite_path/
page number.html
ifhas_pagination
enabled.- Tag indexes:
.../tags/
tag name.html
. Ifhas_tag_pagination
enabled,.../tags/
tag name/index.html
or.../tags/
tag name/pages/
n.html
instead. - Archive:
.../archive.html
- Tag indexes:
-
feed.xml
- A separate template that is designed to output as a feed; only enabled with thehas_feed
configuration item. The example template produces an Atom feed, but it is trivial to configure this for RSS instead.site_path/output_path/feed.xml
-
excerpt.html
- A preview of the latest page inserted on the homepage; only enabled with thehas_preview
configuration item.site_path/index.html
Any (or all) of these templates can inherit from additional files of your own making as long as they are in the same directory. The default templates inherit from a page.html
template; allowing you to define your site's design and let Trakai subsitute in the {{ content }}
.
Templates are written in Jinja 2. For a lot of templating tasks, you'll find it best to work off the included templates (in the example
folder of the repo) and customise them to your own liking. For more advanced tasks, Jinja has its own templating reference. Of course, this doesn't cover blog content...
Post Variables
These are accessible directly from post.html
, and inside a list of dictionary posts
from listings.
- Metadata
- The metadata of each post is accessible via the same names as their definitions. This allows you to define custom variables, and use them on both post and listing pages. Using advanced Jinja template functionality, you can do some neat stuff with them.
prose
-
The content of the post, outputted into HTML. This can easily be used to generate a summary as well:
{% for item in posts %}{{ item.prose | striptags | truncate(230) }}{% endfor %}
neat_date
- The
date
metadata printed in a more human-readable fashion - e.g.2 January, 2020
. Currently, this cannot be customised. rfc822_date
- The
date
metadata printed in the RFC 822/2822 format. Handy for RSS. rfc3399_date
- The
date
metadata printed in the RFC 3399 format. Handy for Atom. Asdate
doesn't include time, it is set to midnight. preview
-
Only extant if you place an
<!-- nvpr -->
comment on a line of your post. Contains any content before it verbatim, so you can place a preview of it in your listing.
It's a good idea to make a fallback in your template in case you forget (or can't be bothered) to add a comment:{%- if item.preview -%}{{ item.preview }}{%- else -%}...
Global Variables
These are accessible from every template.
- Configuration variables
- The configuration settings as detailed in Configuration.
page_mode
-
If you want tag or archive listings displayed differently, this allows you to use Jinja conditionals with them. Is
regular
for standard listings,archive
for archives,tags
for tag listings,feed
for feeds, andposts
for individual posts. all_tags
-
Requires the
has_tags
configuration item to be enabled. A listing of all tags as strings. path
- The output path of the current item, relative to the site root.
name
- Intended as a unique name for CSS styling and such. Based on the file path for index pages, and the page's file name for blog posts.
Listing Variables
These are accessible from every listing, including feed.xml
.
posts
-
A listing of each post displayed on that page, represented as a dictionary of their post variables. When
has_pagination
orhas_tag_pagination
is disabled, this is every post on the main index page and every tag page respectively; otherwise it is each post on that page as dictated bypage_limit
. For archive and feed pages, it is always every post. Sorted by newest first. pages
-
Requires
has_pagination
orhas_tag_pagination
; only applicable for paginated pages. A list comprising the series of pages, represented by file path, that the current page is included in. page_count
-
Requires
has_pagination
orhas_tag_pagination
; only applicable for paginated pages. The total amount of pages in the series that the current page is included in. pagenum
-
Requires
has_pagination
orhas_tag_pagination
; only applicable for paginated pages. The current page's position (or page number) in the series that it is included in.
Internal Variables
These are intended for internal/debugging usage. Like global variables, these are accessible from every template.
site_path
- The path of the site on your disk.
__silent
- Whether informational output is enabled for Trakai.
Configuration
Configuration is achieved via a trakai.json
file in the resources
folder of your site.
posts_path
- The path to a folder containing blog posts in Markdown format.
resources/content
templates_path
- The path to a folder containing Jinja templates.
resources/templates
backup_path
- The path to a folder containing backups of the
index.html
page; only required ifhas_preview
is enabled.resources/backup
output_path
- A path indicating the output folder of blog content, relative to
site_path
.blog
site_url
- The URI/URL that visitors use to access your site's content.
https://www.example.com
feed_description
- The description for Atom (or other) feeds.
Placeholder Description
current_year
- A value for templating designed to indicate the current year.The current year.
has_pagination
- Whether index pages are "paginated" - i.e. divided into multiple pages that the user has to navigate to.
False
has_tag_pagination
- Whether tag pages are paginated; requires
has_tags
.False
page_limit
- How many articles are on each page when
has_tags
and/orhas_tag_pagination
are enabled.5
markdown_extensions
-
A list of extensions that Python-Markdown loads. Using this can provide lots of additional Markdown functionality with the correct extensions; for more information, see Python-Markdown's extensions page.
['def_list','admonition','tables']
The built-in extension
meta
is always loaded regardless of these settings, as Trakai requires it to retrieve page information. has_preview
-
If true, replaces content on the main page with a blog preview derived from the
excerpt.html
template. The first element withpreview_class
is modified to have the template's contents.False
Needless to say, this should only be used with extreme caution. Ensure that page content is properly backed up before making major changes; never, if possible, rely solely on
backup_path
. has_archive
-
If true, generate a separate
archive.html
page in the blog directoryoutput_path
, which is always devoid of pagination.False
has_tags
-
Whether to include tags. Tags are specified by a
tags
metadata entry, which contains a list of comma-separated values representing each tag. An individual listing for each tag is generated in the blog directoryoutput_path
.False
has_feed
-
Whether to build a syndication feed (e.g. RSS or Atom) of all posts using the
feed.xml
template.True
has_caching
-
Whether to build a cache to avoid generating pages whose content hasn't changed. This only affects posts, and does not monitor external files (e.g. CSS) that pages depend on.
False
Since caching maintains the contents of previous builds, its usage can result in the accretion of old or malformed content unless care is taken.
cache_path
-
The location where the post cache is stored.
resources/backup/trakai_cache.json
- Custom values
- Since configuration settings are exposed to templates, you can define custom flags here and use them for debugging, among other purposes.
Command Line
When running trakai
from your favourite terminal, there are a few options to customise things.
path
(positional argument)- The path of the site that is being operated upon. The current directory.
-h
,--help
- Show a help message and exit.
-v
,--version
- Output the installed version and exit.
-s
,--silent
- Run Trakai without outputting informational messages to
stdout
. -a
,--cache
- Always use the cache to avoid generating pages whose content hasn't changed, regardless of configured settings.
-n
,--nocache
- Never use the cache, and always generate pages whose content hasn't changed regardless of configured settings.
-c
path,--config
path- Use an alternate JSON file specified by path to load configuration data.
resources/trakai.json
API
Trakai can also be imported into a Python project as a module. Said functionality is currently experimental and undocumented.