al9000 Documentation
Overview
These are my notes on the static site builder that runs al9000.com. I wrote it in Rust with MiniJinja providing the horsepower (MiniJinja being the Rust version of Jinja). The implementation is based of dozens of prior iterations I've built over the past several years.
The overall goal is to remove as much friction as possible from making web pages. And, not just blog posts, but pages with any given structure or content. The three keys that support that are:
-
All content files are templates with the full range of MiniJinja features available for processing.
-
A global
jvariable is available in each template that contains the metadata from every content file as well as the data from every.jsonfile on the site. -
TODO: Images don't require paths. They can be stored anywhere in the content tree and accessed with their filename alone.
Content Processing
-
Every file in the content tree can be used as a template that can be processed to generate its output. This allows the use of all MiniJinja logic, filters, and functions inside each content file.
-
Every file is available to be included in other templates.
-
Files with
.html,.js, and.txtare passed through the transformation engine by default. -
Files with other extensions are copied without transformation by default. (TBD on adding the ability to transform individual files with a config. It's not something I need currently.)
-
Files and with
.incin their names are available to be included but are not copied to the output tree. -
TODO: Use Neopolitan instead of Markdown for non-html content files (Markdown can be used via the filter listed below).
-
TODO: Neopolitan files (i.e.
.neofiles) become.htmlfiles in the output tree. -
All other files keep their file extensions.
-
TODO: Each file can contain an
idvalue defined in its metadata. Other pages can use the id inlink(ID)functions to automatically create a link to the page with its title and a URL that points to the page regardless of where it's moved.
Templates
-
The default MiniJinja tags are converted to make them easier to read/scan:
{% %}becomes[! !]{{ }}becomes[@ @]{# #}becomes[# #] -
MiniJinja line statements are enabled with
==used as the token. For example, instead of creating a block with:[! block main !] content [! endblock !]I can do:
== block main content == endblockwhich is much nicer to look at.
Global Data
-
All .json files are available in the global
jvariable inside each template. For example, give a JSON file at:/path/to/data.jsonwith the content:
{ "alfa": "bravo" }Doing this:
[@ j.path.to.data.alfa @]Outputs:
bravo -
The global data can be used inside control flows inside any content file. For example:
<ul> == for key in j.path.to.data <li>[@ key @]</li> == endfor </ul> -
Page metadata from each page is available as well (see below);
Page Metadata
-
Page metadata is stored in TMOL format.
-
The metadata is stored inside a
tomlblock. e.g.== block toml title = "page title" == endblockThis block can be stored anywhere in the content file.
-
The metadata for each page is added to the global
jvariable. For example, thetitlekey from the toml metadata in the file:/some/content/file.htmlis available in:
[@ j.some.content.file.title @] -
The metadata is available on the page via a
dvariable. For example:[@ d.title @]
Images
-
TODO: Source images can be stored anywhere in the content tree.
-
TODO: A
/site-imagesis automatically generated to house optimized versions of images. -
TODO: Optimized versions of each image are generated in
/site-images/CHAR1/CHAR2/BASENAME/FILENAME-WxH.EXT -
TODO: An
imgfunction takes the basename (i.e. without an extension) of an image and auto generates the img tag with the full proper paths. For example:[@ img("example-image") @] Generates images with source sets pointing to: /site-images/e/x/example-image/example-image-WxH.jpg -
TODO: The
imgfunction takes an optionalaltargument that populates the alt text for the outputimgtag. -
TODO: The
imgfunction takes an optionalclassesargument that populates theclassattribute of the outputimgtag. -
Create function that lets you call images with just their file basename without the extension to output the optimized image set (e.g. calling [@ img("some-img") @]would create the image tag with the path
Filters
-
code("LANGUAGE")
-
returns a syntax highlighted version of the input ready to be placed inside an inline
<code class="code-span">tag. -
Highlighting is done by defining classes on the individual span tags
-
No additional spans are added to supports line numbers (the highlight function does that).
-
-
highlight("LANGUAGE")
-
returns a syntax highlighted version of the input ready to be placed inside a
<pre><code>block. -
The
LANGUAGEdefines which language to use for the highlighting. -
Highlighting is done by defining classes on the individual span tags
-
A span tag that can be used for placing line numbers is prepended to each line.
-
-
highlight_block("LANGUAGE" [, CLASSES])
-
returns a syntax highlighted version of the input including a surrounding
<pre class="code-block"><code>block. -
The
LANGUAGEdefines which language to use for the highlighting. -
Highlighting is done by defining classes on the individual span tags
-
A span tag that can be used for placing line numbers is prepended to each line.
-
-
md
-
Passes the content through a markdown parser and returns the result.
-
The result is a MiniJinja
safevalue so no additional autoescaping is applied.
-
-
output_block([TITLE [, CLASSES]])
-
Outputs a block of text in
<div class="output-block CLASSES"><div class="title">TITLE</div> <pre><code>CONTENTtags.
-
Functions
-
TODO: data(path)
- Returns the json/toml data for the
given path by effectively turning
/some/path/file.htmlintoj.some.path.file
- Returns the json/toml data for the
given path by effectively turning
-
TODO: date(DATE [, FORMAT])
-
Takes an RFC 9557 date and returns a string with the date.
-
The default format is
MONTH, YEAR. -
The optional
FORMATargument can be passed for other formats (the formatting is done with standard date formatting tokens).
-
-
files_in_folder(PATH [, EXT])
-
Takes a string that's the path to a folder.
-
Returns an array with the full paths to all files in the folder.
-
If the optional
EXTarguments is passed, then only files with a matching file extension are returned.
-
-
folders_in_folder(PATH)
-
Takes a string that's the path to a folder.
-
Returns an array with the full paths to all folders in the folder.
-
-
TODO: link(ID, classes="")
-
parent(PATH)
-
Takes a string that's the path to a file or directory.
-
Returns a string with the path to the parent directory.
-
-
TODO: parts(PATH)
-
Takes a string that's the path to a file or directory.
-
Returns an array of strings where each element is a folder in the path.
-
-
stem(PATH)
-
Takes a string that's the path to a file or folder.
-
If the path is a file, then the file stem is returned (e.g.
/some/path/alfa.txtreturnsalfa) -
If the path is a folder, then the folders basename is returned (i.e. parts of the names after dots don't get removed so:
/some/path/bravo.inc/returnsbravo.inc)
-
Local Tools
-
The generator has a built-in preview server.
-
The preview server has hot-reload which triggers a page refresh after a rebuilt of the site.
-
TODO: The preview server includes dynamic tools to aid in production of the site:
-
TODO: link-getter: takes a URL and returns a link tag whose text is pulled from the title of the remote page.
-
TODO: Built-in File Deployer let's individual files and folder be deployed without having to screw around with git. (The backend is still all git based, it's just abstracted away.
-
Standard Metadata
Standard page metadata tags I'm using:
-
created
-
id
-
link_text
-
status
-
subtitle
-
tags
-
title
-
updated