Provisionally named work in progress.
Generate via CLI a website from a set of three source directories, producing complete HTML files from content, base and partial files, including item templates to be populated with content file values and paginated list templates, and saving to an output directory, with no config files required. Allow for drafts and a beta version, generate content category XML summaries and provide cache busting and live serving.
- recursive insertion, for arbitrarily deep trees, of:
- partials into HTML files using the
<== partial.html [n]syntax - content file values into
.pageand.itemtemplates using the<== keysyntax, with Markdown to HTML conversion, currently ordering items by date descending only
- partials into HTML files using the
- generation of paginated content lists based on
.listtemplates, incl. population with pagination values - one main list per content directory if no override file present plus one for each content file tag used in the directory in a subdirectory named by defaulttags - template reuse via content category mapping for all template types
- provision of project meta data via the base index.html file
- generation of one RSS XML file per content subdirectory
- omission of draft and future-dated content, unless overridden via CLI option
- beta version build
- cache bust suffix insertion for CSS and JS file types
- static file save to default output directory, for variable output file types and an arbitrarily deep static tree
- persistence of site representation as JSON
- live serving - file tree update on change, with page reload
- help text
- further reduce site generation time:
- diff more fully per persisted JSON:
- process decreased subset
- output only required and changed
- memoise completed partial insertions
- diff more fully per persisted JSON:
- revise live serving update check for existing code reuse
- extend functionality:
- allow for content category description line in RSS XML files
- allow use of content file tag value in template file subpath
- extend use of path tag to other nested files
- replace use of subprocess for server and revise live server file to endpoint
- otherwise improve generator source code:
- further refactor
- add docstrings with interactive examples
- extend commenting
- improve this readme
The current code when run from a project directory (see Organisation below) will replicate the structure of the static/ directory in the output directory (public/ by default), with any base HTML files which contain partial inclusion syntax (see Inclusion below) extended using the relevant partial files.
If the site is to include content categories, e.g. blog, docs, with pages populated from Markdown files, the relevant content files are placed in a content/ directory in appropriately named subdirectories, e.g. content/blog/, content/docs/, and the appropriate templates are used (see Templates below).
Default source directory structure:
- static/, for base HTML files marked with the locations at which partials and content head data or body text is to be inserted, with all images stored in static/assets/
- content/, for content files containing head data and body text, organised as an arbitrarily deep tree by type, e.g. blog/, docs/, initially for files written in Markdown, with all images stored in content/images
- partials/, for HTML files to be inserted into other HTML files, including other partial files
Default file inclusion syntax:
- in all HTML files:
<== partial.html [n], i.e. insert partial.html here, once or n times - in HTML
.pageand.itemtemplates:<== key, i.e. insert the given value from the content file here, using the keybodyfor content file body text
For example:
<ul>
<== blog.news.item.li.html 5
</ul>If the content file includes a tags key, this key can be used in place of n to generate one item for each tag. See Additional values below for the values available for use in that template.
Default path inclusion syntax for path parts to root is ==>. For example, the attribute href="==>assets/logo.svg" in a .page template for blog/news/, i.e. for a page two levels deep, becomes in the output file href="../../assets/logo.svg".
Each content file has a meta section of colon-separated key-value pairs demarcated above and below by a single line reading ---. This section is followed by the lines of body text, which can use Markdown.
For example:
---
key_1: value_1
key_2: value_2
---
bodydate- for use in content file sorting
title- for use in RSS index.xmldescription- for use in RSS index.xml
date-YYYY-MM-DD, where a date ahead of the current datetime indicates that the content file is not to be used in generating outputtags-[ "tag 1", ... ]draft-true/false/ ..., wheretrueindicates that the content file is not to be used in generating output
Non-generation of output for future-dated and draft content may be overridden - see Options below.
image- whether the entire key or part of it, any path provided as the corresponding value is assumed to relate to an image file in either assets/ or images/
In addition to values provided in the meta section of the content file, the following are available for use:
- if the
datecontent value is present:date-expanded-uk- that date in expanded UK format, e.g.1970-01-01as1 January 1970datetime-rfc822- that date in RFC 822 datetime format, e.g.1970-01-01asThu, 01 Jan 1970 00:00:00 -0000
Available template types:
.page- a static directory template representing a complete page in a content category, e.g. a blog post, with one page generated per content file in the category.item- a partial directory template representing a component on a page, e.g. a summary of a blog post, with a maximum of one item generated per content file, up to the number requested.list- a static directory template representing one page of a paginated list containing with one.itemtemplate for each content file in a content category, e.g. a list of all blog posts
Specifically:
- any HTML file in static/ with a name of the form type.page.html is a template to be populated with values from the content subdirectory of that type, e.g. blog.news.item.html from files in content/blog/news/; one output file is to be generated per file in the subdirectory, each named for the source content file, e.g. content/blog/news/post1.md becoming blog/news/post1.html
- any HTML file in partials/ with a name of the form type.item.description.html is a template to be populated with values from the content subdirectory of that type, if the type is present, e.g. blog.news.item.li.html from files in content/blog/news/, before being inserted one or more times, e.g. to provide a list in which each
lielement summarises one content item; if no type is present in the name, this is provided in the item inclusion syntax by prefixing the name with the type followed by a colon (':'), e.g.<== type:item.description.html; in a.pagetemplate the final element of the content subpath may betag0to indicate any content file tagged with the first tag (i.e. the tag at index 0) in the list of tags for the current content file - any HTML file in static/ with a name of the form type.list.html is a template to be completed with the content of one
.itemfile in partials/, each.itemgenerated once per file in the content subdirectory of that type, e.g. blog.news.list.html relates to files in content/blog/news/; one output file is to be generated per page of the paginated list, each currently namedpage-plus the page number, e.g. content/blog/news/page-1.html for the first; the main list for a content subdirectory is not generated where an override file - a file named for that content directory - is present in static/, e.g. a list for content/blog/ is not created if blog.html is present; one additional list is generated for each tag used in the content subdirectory, these stored in a further subdirectory named by defaulttags, each in its own<tag name>/subdirectory
Each content type may be mapped to one or more group identifiers by naming the content subdirectory not type but identifier_1[:indentifier_n]:type, e.g. content/feed:blog. Each such identifier can then be used in place of the type in a .list, .page and/or .item template name in order that the given template is used once for each of the mapped types, e.g. feed.list.html for content files in content/feed:blog.
In addition to values provided in the meta section of the content file and available alternatives (see Content file values above), the following are available for use in .item templates:
image- the URL of the first image on its own line in the body of the content fileintro- the first non-heading, non-image line of the body of the content file, converted from Markdown to HTML, with anyaelementhrefvalue removedbody- the body of the content file, converted from Markdown to HTMLhref- the URL of the output file
The following values are available for use in files applying .item templates, excluding .list templates, for the purpose of populating control elements:
.total- the total number of content files of the type, preceded with the dot-separated type, e.g. blog.news.available.total-attr- the total number of content files of the type as the value in an attribute named by defaultdata-type-total, preceded with the dot-separated type, e.g. blog.news.total-attr.extra- the number of content files of the type not used in the file, preceded with the dot-separated type, e.g. blog.news.extra.extra-attr- the number of content files of the type not used in the file as the value in an attribute named by defaultdata-type-extra, preceded with the dot-separated type, e.g. blog.news.extra-attr
The following items are available for use in .item templates inserted with the tags key:
tag-url- the URL of the list page generated for the given tagtag-name- the tag name
The following values are available for use in .list templates for the purpose of populating control elements:
this-list- the spaced subpath of the current list pagefirst-url- the URL of the output file for the first list page of the setlast-url- the URL of the output file for the last list page of the setprev-url- the URL of the output file for the previous list page in the setthis-url- the URL of the output file for the current list pagenext-url- the URL of the output file for the next list page in the setprev-n- the number of the previous list page in the setthis-n- the number of the current list pagenext-n- the number of the next list page in the setprev-extra- the number of list pages beforeprev-nprev-extra-attr- the number of list pages beforeprev-nas the value in an attribute named by defaultdata-page-prev-extranext-extra- the number of list pages afternext-nnext-extra-attr- the number of list pages afternext-nas the value in an attribute named by defaultdata-page-next-extra
Project meta data can be provided as key-value pairs in tino meta tags in the base index.html file. Each is included on its own line, presumably but not necessarily in the head element.
For example, for the pair key and value, with use of the default syntax:
<head>
...
<tino-meta name="key" content="value">
...
</head>Each line with a tino meta tag is omitted from the output file.
The following default values are among those set close to the top of the main file:
-
flow tag -
<== -
path tag -
==> -
output root directory name -
public -
output tags directory name -
tags -
output file cache bust suffix -
_hhmmssddmmyy, whereh,m,s,d,mandyare the relevant digits for the current time (hour, minute and second) and date (day, month, year) -
output attribute prefix -
data- -
content shared media directory name -
images -
static shared media directory name -
assets -
tino meta tag name -
tino-meta -
tino meta tag key attribute -
name -
tino meta tag value attribute -
content -
server port -
8000 -
server loop (seconds) -
1
The following dependencies are used:
- Python 3
- Python-Markdown
- css-html-js-minify
- Pygments
The tino root directory requires the three default source directories - content/, partials/ and static/.
Once complete, all files in the static/ directory are copied into the default output directory public/.
The main file can be run for the default behaviour with the command python3 path/to/tino, or path/to/tino if the python3 executable is located in the /usr/bin/ directory, or tino if python3 is in /usr/bin/ and the main file is in the /bin/ directory.
If python3 is located elsewhere, simply modify the path in the hashbang at the top of the main file accordingly.
A development live server listening by default at localhost:8000 can be run with the command python3 path/to/tino --live, path/to/tino --live or tino --live, optionally using the shorter -l flag, per the above on file location.
-h,--help- show the help text and exit-l,--live- run the development server-p,--port <n>- listen instead on port<n>-b,--bust <suffix>- cache bust instead with<suffix>-B,--beta- build a beta version, making the output directory beta/public/ and including in URLs thebetaleading path part-F,--incl-future- if content files are loaded, generate output also for those with a value fordateahead of the current datetime-D,--incl-draft- if content files are loaded, generate output also for those with a value fordraftoftrue-E,--excl- do not load content files, passing any templates unpopulated to the output directory
- dot-prefixed files are not loaded
- ensure existing site section URLs valid
- ensure existing site images used also by apps remain or are relocated