Skip to content

A static site generator library using Jinja2 templates, written in Python

License

Notifications You must be signed in to change notification settings

ryanmphill/shodo-static-gen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shodo Static Site Generator

This is a Python script and framework for building a static site from markdown, Jinja2 templates, and static assets (CSS, JavaScript, images, etc). Edit your site in the src directory, and access the build in the dist directory!

Getting Started

Installing from Github via pip

  1. Create a new project directory and start a virtual environment using your preferred method

  2. Install the shodo_ssg package by running the command:

pip install git+https://github.com/ryanmphill/shodo-static-gen.git
  1. Once the package is installed, you can scaffold a new project using the command
start-shodo-project <name of project directory>

To create the project in the current directory, run

start-shodo-project .
  1. Build the starter site and serve it to localhost by running the following command from the root directory of the project:
python3 serve.py

You should now be able to view the site on localhost and can start by making changes to home.jinja. When you simply want to build the static site, run the following command from the root directory:

python3 site_builder.py

and you can find your static site located in the dist/ directory

Pulling down the repository and installing locally

  1. Start up a virtual environment and install the dependencies using your preferred method after pulling down the repository

  2. Once your virtual environment is activated, in the root of the project directory run pip install -e . (Don't forget the .)

  3. Upon successful install, navigate to an entirely separate directory and run

start-shodo-project <name of new project directory>

Upon success, a new starter project template should have been set up in the specified directory

Start editing by making changes to src/theme/views/home.jinja

  1. Run Python site_builder.py from the main project directory when your ready to generate the site

Find your static site located in the dist/ directory

For development, run Python serve.py from the root project directory. This will build the site in the dist directory with the latest changes from src and serve it on localhost!

How it works

First, there is the main home page template located at src/theme/views/home.jinja that can render partial sub-views, which can either be other Jinja2 templates located in src/theme/views/partials, or markdown files located in src/theme/markdown.

Templates

This project uses Jinja2 as its templating engine, so it would be beneficial to visit the Jinja docs. This project leverages Jinja to integrate with Python and build HTML from templates that have access to functions and variables.

Pages

Any template added to the pages/ directory will be written as an index.html file in its own subfolder within the dist directory. When linking between pages, simply write a backslash followed by the page name, exluding any file extensions. So if you wanted to link to pages/linked-page.jinja from home.jinja, the anchor tag would be

<a href="/linked-page">Click Here!</a>
Nested Pages

You can create nested pages by adding a subdirectory within pages/ with the name of the route. For routes with multiple pages, the index page of that route will need to be on the same level as the route subdirectory with the same name followed by the .jinja extension. For example:

__pages/
____about.jinja (template for '/about')
____nested.jinja (index template for '/nested')
____nested/
______nested-page.jinja (template for '/nested/nested-page')

Markdown

Partial markdown content to include in templates

Any markdown files added to the /markdown/partials directory will be exposed to Jinja templates with a variable name identical to the markdown file name, minus the extension. So, the contents of summary.md can be passed to the Jinja template as {{ summary }}, where it will be converted to HTML upon running the build script.

Prefixed variables for nested markdown directories

In order to avoid any naming conflicts, The articles further nested in directories within "articles/partials/" will have a variable prefix that is the accumulated names of the preceding directories in dot notation (excluding '/partials' and higher).

For example, a markdown file located in markdown/partials/collections/quotes/my_quote.md, will be exposed to all templates with the following variable using the jinja variable syntax:

{{ collections.quotes.my_quote }}
Generating full pages from markdown

In addition to partial variables that can be included in templates, entire new pages can also be automatically be generated from markdown files added to the markdown/articles directory. The url path to the page will match what is defined in the markdown/articles directory.

Articles from the markdown/articles directory are rendered with a reusable template defined in views/articles/ Just add a layout.jinja file under a subdirectory that matches the subdirectory tree used in markdown/articles, or simply define a layout.jinja at the root of views/articles if you want to use a single layout template for all articles. In the layout.jinja file, control where you would like your content to be dynamically inserted by passing in the reserved {{ article }} variable. More below.

The site builder will always match up the layout template that is closest in the tree, so markdown/articles/blog/updates/new-post.md would be matched with views/articles/blog/layout.jinja if no layout is defined for the updates directory.

__markdown/
____articles/
______blog/
________updates/
__________new-post.md
__views/
____articles/
______layout.jinja (default root layout for all markdown 'articles')
______blog/
________layout.jinja (Maps to markdown/articles/blog, overwrites root layout)
________updates/
__________layout.jinja (Maps to markdown/../updates, overwrites other previous layouts in tree)
layout.jinja

The layout.jinja is just a normal jinja template, but the {{ article }} variable has been reserved as a children variable for passing in the content from each page. Simply define whatever repeated layout you would like to wrap the {{ article }} content, such as a header and footer.

Here is an example layout template:

<div class="container">
    <header class="page-header">
        <h1 class="page-header__title">This is the root article layout</h1>
    </header>
    <main>
        {{ article }}
    </main>
    <footer>Thanks for reading</footer>
</div>

Dynamic data

For rendering dynamic data, Jinja Macros can be used for looping through a passed argument. Simply use the macro keyword in the partial template, like the following example:

{% macro loop_template(items) -%}
    <ul>
    {%- for item in items %}
        <li>{{ item }}</li>
    {%- endfor %}
    </ul>
{%- endmacro %}

Then, it can be included in the main template:

{% from 'loop_template.jinja' import loop_template as loop_template %}
    {{ loop_template(['Content', 'to', 'loop', 'through']) }}

Then after running the build, the HTML should look like the following:

<ul>
    <li>Content</li>
    <li>to</li>
    <li>loop</li>
    <li>through</li>
</ul>

JSON data in the /store directory

For easy configuration and keeping repeated values in one place, any property defined in a .json file within the /store directory will be passed to Jinja templates with an identical variable to the property name. Each nested object can be accessed using dot notation in the templates.

For example, to access the title value from /store/config.json:

{
    "metadata": {
        "title": "Shodo - A Static Site Generator",
        "description": "Shodo is a static site generator that uses Markdown and JSON files to generate a static site.",
        "author": "Shodo"
    }
}

in the template, you would use the following syntax:

{{ metadata.title }}

build_settings.json

This is where all source paths and project settings are defined.

NOTE: Any path included in root_template_paths will have all of its children directories recursively added to the search path for Jinja2, so only top level paths should be included in the settings. In most cases, "root_template_paths": [ "src/theme/views/" ] should suffice, but it would be possible to add another path to src/theme/assets/images for example if you wanted to use the templates for working with an SVG but still wanted to maintain separation of concerns.

Project Conventions

Jinja templates

For all jinja templates, use the .jinja file extension. Other extensions such as .j2 or .jinja2 are not fully supported at this time.

Syntax Highlighting

If you're using VSCode, the Better Jinja extension is recommended for full syntax highlighting out of the box using the .jinja extension. Other extensions will work, although you might need to configure the settings to look for the .jinja extension.

For Contributors

Code style: black

This project uses the Black Formatter and follows the current style guide

About

A static site generator library using Jinja2 templates, written in Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published