Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

This guide walks you through installing Blogatto and building your first static blog.

Prerequisites

Installation

Blogatto is available on Hex. Add it as a dependency to your project:

gleam add blogatto

Project structure

A typical Blogatto project looks like this:

my-blog/
  src/
    my_blog.gleam        # Your build script
  blog/
    hello-world/
      index.md           # Blog post (default language)
      cover.jpg          # Post assets
    second-post/
      index.md
      index-it.md        # Italian variant
    djot-post/
      index.djot         # Djot source (also `.dj`)
  static/
    css/
      style.css          # Static assets copied to output
    images/
      logo.png
  gleam.toml

Minimal example

The simplest Blogatto setup parses post source files (Markdown or Djot) and writes HTML:

import blogatto
import blogatto/config
import blogatto/config/post

pub fn main() {
  let md =
    post.default()
    |> post.path("./blog")

  let cfg =
    config.new("https://example.com")
    |> config.output_dir("./dist")
    |> config.static_dir("./static")
    |> config.post(md)

  let assert Ok(Nil) = blogatto.build(cfg)
}

Run the build:

gleam run

This produces:

dist/
  css/
    style.css
  images/
    logo.png
  hello-world/
    index.html
    cover.jpg
  second-post/
    index.html
    index-it.html

Adding a homepage

Most blogs need a landing page that lists articles. Add a route with a view function that receives the full list of parsed posts:

import blogatto
import blogatto/config
import blogatto/config/post
import blogatto/post.{type Post}
import gleam/list
import gleam/time/timestamp
import lustre/attribute
import lustre/element.{type Element}
import lustre/element/html

pub fn main() {
  let md =
    post.default()
    |> post.path("./blog")
    |> post.route_prefix("blog")

  let cfg =
    config.new("https://example.com")
    |> config.output_dir("./dist")
    |> config.static_dir("./static")
    |> config.post(md)
    |> config.route("/", home_view)

  let assert Ok(Nil) = blogatto.build(cfg)
}

fn home_view(posts: List(Post(Nil))) -> Element(Nil) {
  let sorted =
    list.sort(posts, fn(a, b) { timestamp.compare(b.date, a.date) })

  html.html([attribute.lang("en")], [
    html.head([], [
      html.title([], "My Blog"),
      html.link([
        attribute.rel("stylesheet"),
        attribute.href("/css/style.css"),
      ]),
    ]),
    html.body([], [
      html.h1([], [element.text("My Blog")]),
      html.ul(
        [],
        list.map(sorted, fn(p) {
          html.li([], [
            html.a([attribute.href("/blog/" <> p.slug)], [
              element.text(p.title),
            ]),
          ])
        }),
      ),
    ]),
  ])
}

Full example

See the simple_blog example for a complete project with homepage, blog post template, RSS feed, sitemap, and robots.txt.

Next steps