yet another site generator using pandoc. This one lets you use the mustache templating language to do some cool magic
Usage:
# prints this documentation
python build.py --help
# prints the default config as yaml (without comments)
python build.py --default-cfg
# builds according to the config
python build.py <config_path>
see the example website
create a config file
First, create a config file example: config.yml
with the following content:
# NOTE: `!join` is a custom directive that will add the elements of the list together. useful for concatenating strings
# base directories
# ==============================
# NOTE: these are all relative to the location of the config file!
# where the script will look for markdown files
content: &CONTENT_DIR "./content/"
# where HTML files will be generated
public: &PUBLIC_DIR "./../docs/"
# referenced only in this yaml file, for now, but could be useful as a global
resources_base: &RESOURCES_BASE "resources/"
resources: &RESOURCES_DIR !join [*CONTENT_DIR, *RESOURCES_BASE]
# global data
# ==============================
# under this key, individual documents can access the data in this file
globals_key: "__globals__"
# json or yaml from which extra data can be loaded to be globally available
extras_path: null
# data from the above will be merged with this data
extras_data:
shuffle_script: "<script>\n var ul = document.querySelector('ul#shuffleme');\n for (var i = ul.children.length;\
\ i >= 0; i--) {ul.appendChild(ul.children[Math.random() * i | 0]);}\n</script>"
# this gets merged into the frontmatter of each document (for mustache only)
frontmatter_defaults:
__into_header__: ""
# other things
# ==============================
# whether to treat files with `index: true` specially
make_index_files: true
# dont worry about this, its for generating temporary files
generated_index_suffix: "._index.md"
# whether to give each HTML file a final pass with the mustache renderer,
# with the frontmatter from the markdown source passed as the context
# you can also set this to an integer if you want to re-render the templates multiple times
mustache_rerender: true
# whether to keep track of when the site was last built
# any file last modified prior to the saved time will not be rebuilt
# this can be overridden by passing `--rebuild` or by deleting the file at `build_time_fname`
smart_rebuild: true
build_time_fname": ".build_time"
# use dotlist hierarchy if true, folder hierarchy if false. this will mess with relative paths in the markdown files
dotlist_hierarchy: true
# pandoc stuff
# ==============================
# these items will be passed as arguments to pandoc
# - `foo: bar` will normally be passed as `--foo bar`
# - items which are "None" will not be passed as an argument, useful for disabling things from the default config
# - items which are a boolean will be passed as `--foo` if true, and not passed if false
# - items which are lists (e.g. `foo: [a, b, c]`) will be passed as `--foo a --foo b --foo c`
__pandoc__:
include-in-header: !join [*RESOURCES_DIR, "header.html"] # passed as '--include-in-header'
include-before-body: !join [*RESOURCES_DIR, "before-body.html"] # passed as '--include-before-body'
include-after-body: !join [*RESOURCES_DIR, "after-body.html"] # passed as '--include-after-body'
# these should be paths to any pandoc filters you'd like to use.
# if you dont have any, just have it be an empty list
filter:
- "../filters/links_md2html.py"
email-obfuscation: 'references' # options: none|javascript|references
html-q-tags: true
writing content
Now, you can create markdown pages in the content
directory, with a dot-separated hierarchy. For example, we can have:
home.md
blog.md
blog.post1.md
blog.post2.md
or a standard folder structure, if you set dotlist_hierarchy: false
index pages
If we want blog.md
to be an index page, put __index__: true
in the frontmatter. The body can then contain mustache syntax
- files matching
blog.*.md
will have their frontmatter read, and their path added to the dictionary as__filename__
- that list of dictionaries will be passed to mustache as
__children__
So, we might have our blog.md
file look like:
---
title: Blog
description: This is the blog index
__index__: true
---
Here all all the blog posts:
{{#__children__}}
- [**{{title}}**]({{__filename__}})
*{{description}}*
{{/__children__}}
{{^__children__}}
No blog posts yet. :(
{{/__children__}}
resources & assets
Won't lie, this part is kind of messy at the moment.
Ideally, you have your assets (such as CSS, images) located in a directory under your content directory -- specified by resources
in the config file. Then, any links to them will be preserved, since the whole directory is copied.
building the website
simply run
python build.py <config-file>
this can be done from anywhere -- python will change it's working directory to the directory containing the config file. Look for your built html pages in the directory you specified as public
in the config file!
Installation
you will need:
- Python 3.8 or later
Pandoc
for rendering markdown to html. make sure it is in your path!PyYAML
, which you can install withpip install PyYAML
chevron
for rendering mustache templates. The version on pypi is broken, so you'll need to install from git:pip install git+https://github.com/noahmorrison/chevron@5e1c12827b7fc3db30cb3b24cae9a7ee3092822b
you can also install via
pip install -r requirements.txt
the script is otherwise standalone. Clone the git repo if you'd like, or just download the file somewhere.
Roadmap
Every feature I originally intended for pandoc-sitegen
has been added, but I'm not fundamentally opposed to more features. pull requests are welcome! Some possible future features I might eventually add:
- allow items to reference global items from the config and external files (see
special.md
in example site) - templating in YAML headers? (rendering with globals now applied to yaml header raw text)
- filter locations and other paths in header are not portable, would be good to fix this
- inheriting pandoc args/config from parent items (mostly for styling different parts of a site differently)
- auto-generate tag pages
- generation of RSS files
I'd like to keep this project as a single-file script of pure python with minimal dependencies, for simplicity and portability.
similar tools/resources:
- https://github.com/brianbuccola/brianbuccola.github.io
- https://runningcrocodile.fi/pandoc_static_site/
- http://pdsite.org/installing/
- https://github.com/locua/pandoc-python-static-site-gen
- https://github.com/lukasschwab/pandoc-blog
- https://github.com/fcanas/bake
if you end up using this script for your site and would me to list it here, email me or submit a PR :)