Skip to content

sekunho/puggle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

puggle

image

A simple static site generator for my personal use.

Caution

Is the code in good shape? No. Should you use it for your own stuff? Probably not, but you can. At the moment this is experimental, and things could break at any time without proper versioning or notice.

(Anteater from Im australischen Busch und an den KΓΌsten des Korallenmeeres. Reiseerlebnisse und Beobachtungen eines Naturforschers in Australien, Neu Guinea und den Molukken (1866) - Source)

Examples

Quick start

A puggle project starts with a configuration file puggle.yml. This config file allows us to define the pages we want to have for our static site.

# ./puggle.yml
templates_dir: templates
dest_dir: dist

pages:
  - name: blog
    template_path: layout/blog.html

Here we defined a page called blog, as well as the relative path to the template that it should use. This template will be used to generate the HTML file for our blog page.

We also specified our templates directory. This is the base path of all template_paths. So in our example, the actual relative path puggle will use is ./templates/layout/blog.html.

Next, let's create our blog page's template.

<!-- ./templates/layout/blog.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>

  <body>
    Welcome to my blog.
  </body>
</html>

Running puggle build would create the following:

dist
└─ blog
   └─ index.html

...with an dist/blog/index.html

<!-- ./dist/blog/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>

  <body>Welcome to my blog.</body>
</html>

This is not very interesting though because we want to have posts in our blog. We also want our template to be slightly different from our main blog page. So let's create some entries!

puggle has two ways of sourcing page entries:

  1. Fetch every single markdown file in a specific directory, recursively; and
  2. Referencing the markdown file directly.

Let's update our puggle.yml.

# ./puggle.yml
templates_dir: templates
dest_dir: dist

pages:
  - name: blog
    template_path: layout/blog.html

    entries:
      - source_dir: blog/posts
        template_path: layout/post.html

Here we're defining our source directory for our blog's entries to be ./blog/posts. puggle will search for every single markdown file under that directory.

Then create ./blog/posts/first.md

<!-- ./blog/posts/first.md -->
---
title: First post
summary: For my first blog post, I shall...
cover: "/assets/images/post_cover.jpg"
created_at: 2024-06-29T17:29:00Z
updated_at:
tags: ["hello", "world"]
---

# First post

Hello, world!

πŸ’‘ You'll notice a YAML-style metadata block at the top of the markdown file, and this is what allows you to do some pretty cool things with puggle. For now, just think of it as potentially useful data that we could use.

Here's a quick rundown:

  • title (required): Used to label your page entry's title. You can use this to index a page's entries.
  • created_at (required): UTC timestamp of when the page was created. e.g 2024-06-29T17:29:00Z
  • updated_at (can be left blank): UTC timestamp of when the page was updated. e.g 2024-06-29T17:29:00Z
  • tags (required): A list of strings. You may define this as an empty list. e.g ["nixos", "rust"]

And a template for our blog's entries

<!-- ./templates/layout/post.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog Post</title>
  </head>

  <body>
    {% raw %}{% block content %}{% endblock %}{% endraw %}
  </body>
</html>

The {% raw %}{% block content %}{% endblock %}{% endraw %} defines a block statement for us to inject content into it. puggle requires the content block to be present in the entry template otherwise it would have nowhere to inject the generated HTML file into, and would result in a blank HTML file.

puggle build would then create the following:

dist
└─ blog
   β”œβ”€ first
   β”‚  └─ index.html
   └─ index.html

...with an dist/blog/first/index.html

<!-- ./dist/blog/first/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>

  <body>
    <h1>First post</h1>
    <p>Hello, world!</p>
  </body>
</html>

Page entry metadata

Metadata provides a lot of flexibility for you to inject data into your templates, or markdown files.

Therefore changing our blog entry to

<!-- ./blog/posts/first.md -->
---
title: First post
summary: For my first blog post, I shall...
cover: "/assets/images/post_cover.jpg"
created_at: 2024-06-29T17:29:00Z
updated_at:
tags: ["hello", "world"]
---

# {{ metadata.title }}

Hello, world!

Would give us the same result because puggle understands that we're referencing the title attribute defined in the entry's metadata. puggle also allows you to use all page entries' metadata in other pages.

The entry's template file can also reference the entry's metadata so you could set the title tag to our entry title for example.

<!-- ./templates/layout/post.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>{{ metadata.title }} - Blog</title>
  </head>

  <body>
    {% raw %}{% block content %}{% endblock %}{% endraw %}
  </body>
</html>

You can't reference metadata attributes in a page entry from another entry because each entry can only know about its own metadata.

Let's index our blog's entries in our blog page!

<!-- ./templates/layout/blog.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>

  <body>
    Welcome to my blog.

    {% raw %}{% for page_name, page_entries in sections|items %}
      {% if page_name == "blog" %}
        <ul>
          {% for entry in entries %}
            <li>{{ entry.created_at|dateformat(format="short") }} - {{ entry.title }}</li>
          {% endfor %}
        </ul>
      {% endif %}
    {% endfor %}{% endraw %}
  </body>
</html>

Would result in this HTML page

<!-- ./dist/blog/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Blog</title>
  </head>

  <body>
    Welcome to my blog.

    <ul>
      <li>2024-06-29 - First post</li>
    </ul>
  </body>
</html>