# tictacs

A painfully simple static site generator.

It is not configurable, relies on a fixed directory structure, and must be run from the root of that structure to work correctly.

## How to install _tictacs_

You can install _tictacs_ using [cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html):

```
cargo install tictacs
```

> There is also a [precompiled binary available online](https://random.valflrt.dev/tictacs_x86_64-unknown-linux-musl), compatible with Alpine Linux in order to be run in an alpine gitlab-ci image.

## How to use _tictacs_

I have made a sample website/blog to demonstrate how _tictacs_ works.

```
example_website/
├── public
│   ├── 404.page.html
│   ├── blog
│   │   ├── 03-01-2026.blogpost.html
│   │   └── 19-11-2678.blogpost.html
│   ├── index.page.html
│   └── style.css
└── templates
    ├── base.html
    ├── blogpost.page.html
    └── page.base.html
```

> [!NOTE]
> In the actual [`example_website/`](example_website/) directory, there is a [`dist/`](example_website/dist/) directory that is not shown here. It contains the compiled version of the website, I included it in case someone wanted to see what it looks like.

### Structuring your files

Your project directory must have two directories in it:

- `public/` contains static files and templated html pages
- `templates/` contains template html files

### Templating

The use of a template is indicated by file names of the form `file_name.template_name.html`. Where `file_name` is the name the file will be renamed to (e.g. `hello.page.html` will become `hello.html`) and template_name is the name of the template used, and that must be present in `templates/` (see warning below for naming convention).

Templates and templated files can contain special comments called blocks that tell _tictacs_ how to copy content from the templated file to the template file; their syntax is `<!---block_type:label_name--->` (note the **three** dashes instead of the usual two).

Here are the three types of blocks you can use:

- `def` block: Defines a block of content associated with the label `label_name`, the content is everything located after the block and before the next `def` block or the end of the file. (see [`public/index.page.html`](example_website/public/index.page.html) for example)

- `put` block: _Only in template files_, this is a part of the template file that will be replaced by the content of the matching definition block in the templated file. The same `put` block can be used several times in a template file. (see [`templates/base.html`](example_website/templates/base.html) for example)

- `pipe` block: _Only in templated template files_, pipes content directly from the definition block to the `put` block of the template. This is equivalent to a `def` block whose content is a `put` block with the same label: `<!---def:label_name---><!---put:label_name--->`. (see [`templates/page.base.html`](example_website/templates/page.base.html) for example)

> [!NOTE]
> A template can be templated. For example, the template [`page.base.html`](example_website/templates/page.base.html) uses the template [`base.html`](example_website/templates/base.html).

> [!WARNING]
> When defining a regular templated file, the name of the template to use is only the part before the first dot in the template file name. For example, when you want to use the template named `page`, i.e. the template file named [`page.base.html`](example_website/templates/page.base.html), use `file_name.page.html` as your templated file name, not `file_name.page.base.html`.

### Templated files

Templated files use a specific structure with a series of `def` blocks.

```html
<!---def:date--->
03/01/2026

<!---def:title--->
First blog post !

<!---def:content--->
<p>Happy new year 2026 !</p>
<p>
  This is my first blogpost of all times, however this is a bit hopeless because
  it is a sample one...
</p>
<p>See you in the next post !</p>
```

This example page is [`public/blog/03-01-2026.blogpost.html`](example_website/public/blog/03-01-2026.blogpost.html). It uses the template named `blogpost`, located at [`templates/blogpost.page.html`](example_website/templates/blogpost.page.html):

```html
<!---def:head--->
<title><!---put:title---> — Blog post from <!---put:date---></title>

<!---def:content--->
<h1><!---put:title---></h1>
<p style="text-align: right; opacity: 0.6">
  published
  <!---put:date--->
</p>
<!---put:content--->
```

When compiling, _tictacs_ will replace all `put` blocks with the content of the associated `def` blocks in the templated file.

Note that here, `blogpost` is a templated templated template (funnily enough), it depends on `page` which itself depends on `base`. Before building `public/`, _tictacs_ compiles (templated) templates. The _compiled_ `blogpost` template will look like this:

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><!---put:title---> — Blog post from <!---put:date---></title>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <main>
      <h1><!---put:title---></h1>
      <p style="text-align: right; opacity: 0.6">
        published
        <!---put:date--->
      </p>
      <!---put:content--->
    </main>
  </body>
</html>
```
