Pinaclj (pronounced "pinnacle")
Pinaclj is a simple content system for the web written in Clojure, currently under active development.
Note: This is still early-stage software but explorers are welcome.
In its current state it is a capable static website generator that takes a set of Markdown files together with a set of templates (a theme) and transforms it into your generated site.
- File-based YAML source files
- Markdown support
- HTML5 data attribute based templating
- Incremental builds
- Page categories
- RSS feeds
- Punctuation transformations
- Extensible template functions
Pinaclj's aims are to be:
- beautifully minimal: this is reflected in the choice of language (Clojure) and the choice of templating engine (Enlive).
- simple to design: you can create themes with just basic HTML. No programming knowledge is required.
- simple to use: features that support and aid productive and creative writing.
The GitHub issue tracker lists all features currently planned for the first release, but here's a short summary:
- Support for media
- Post series
- Moving and deleting pages
- Git integration
- Role-based, multi-user support with workflow
- Web UI with a focus on aiding writing
- iPhone and Android apps
I welcome contributions of all types. The issues list is up-to-date: pull requests are welcome.
You will need Leiningen 2.0.0 or above installed.
Building your first post
Right now you'll need to run from source.
Clone the repository using
gendirectory where your site will be generated in.
postsdirectory where you want your posts to be stored. This could be another Git repo if you wish.
postsdirectory, create a new file called
first.mdwith the following content:
title: First post --- Hello, world!
Change to the
pinacljdirectory and run the following command.
lein publish <posts directory>\first.md
Take a look at the contents of the file. You'll see that a
published-atheader has been written. This is the cue to Pinaclj that the post is ready for publication. Without this header, Pinaclj will not generate your page.
Run the following command.
lein generate -s <posts directory> -d <target directory> -t sample_themes/diary
Change to the
gendirectory. You'll find the following files:
index.html first.html category/post/index.html
Explore the content of the files and compare to how it matches up with the theme located in
Your next step, most likely, will be to build your own theme.
A theme directory should have at least two files:
index.htmlwhich is the page list.
post.htmlwhich is the template used for individual posts.
There are example pages here: https://github.com/dirv/pinaclj/tree/master/sample_themes
Posts are written in Markdown. Each post begins with a header section. The following are valid headers:
published-at(optional; but the presence of this field determines if the page is published or not. Example:
url(optional; if not provided the filename will be used. See below)
category(optional; default is 'post')
You can add any other headers you wish. Headers can be accessed from within your theme's template files.
You can use the
url header to generate posts as
index.html files within their own directories, e.g.
Will generate the file www.example.com/my-site/index.html.
Understanding themes and posts
If the name of your post file matches the name of a theme template file, then that post will be rendered with that template. The upshot of this is that you can use your post files to provide data to your templates.
So for example, if you have an
index.md file with a header of
blog-title: My Amazing Blog
index.html theme template can reference
blog-title within a
data-id attribute to retrieve the values.
What's more, each page has an implicit parent and templates can access headers set on parent pages. The default parent hierwachy is that each post's parent is its category page, and each category page has a parent of
The upshot of this is that headers set in your
index.md post will be accessible to all template files. The same is true for posts belonging to particular categories.
Overriding page values works as you might expect, so a post can override
blog-title if desired.
You can also explicitly set a page parent by setting the
parent header. Thr value should be set to the destination page name and not the post file name. So for example: