Architecture

Personal website for Joost van der Borg (joostvanderborg.nl), built with Eleventy (11ty v3) and deployed on Netlify.

Overview

Static site generator setup. Content is stored as Markdown with YAML frontmatter, Eleventy transforms it into HTML, and Netlify serves it. Pinboard bookmarks tagged "publish" are automatically pulled in as quicklink posts at build time.

Directory structure

.
├── .eleventy.js          # Eleventy config (ESM)
├── index.js              # Build entry point (runs Pinboard sync, then Eleventy)
├── index.html            # Home page (paginated post list)
├── posts.md              # /posts index page
├── tags.njk              # Auto-generates /tags/<tag>/ pages
├── quicklinks.js         # Pinboard API integration
├── book_list.js          # Bulk book post generator (via Open Library API)
├── book_details.js       # Single-book post generator (legacy, by ISBN)
├── book_search.js        # Book search utility
├── robots.txt
├── netlify.toml          # Netlify build config + cache plugin
├── .pages.yml            # Pages CMS config (Git-based CMS UI)
│
├── _includes/            # Eleventy layouts
│   ├── template.html     # Base layout (head, nav, body wrapper)
│   ├── post.html         # Blog post layout (gallery support, prev/next nav)
│   ├── book.html         # Book review layout (author, ISBN, star rating)
│   └── post-p5.html      # Post layout + p5.js for interactive/generative posts
│
├── posts/                # All content (Markdown + YAML frontmatter)
│   ├── posts.json        # Sets tags: ["post"] for all posts
│   ├── 2008/ … 2025/     # Blog posts by year/month subdirectories
│   └── quicklinks/       # Auto-generated Pinboard quicklinks (ISO timestamp filenames)
│
├── styles/
│   └── main.css          # Single stylesheet (CSS custom properties, dark mode, responsive grid)
│
├── js/
│   └── p5.min.js         # p5.js library (used by post-p5.html posts)
│
├── uploads/              # Media files (images), organised by year
│   └── 2012/ … 2025/
│
└── netlify/
    └── functions/
        └── scheduled-deploy.js  # Cron function: triggers rebuild 3× per day

Build process

node index.js
  1. grab_pinboard_data()   → fetches Pinboard bookmarks (tag: publish)
                              → writes Markdown files to posts/quicklinks/
  2. Eleventy.write()       → builds everything to _site/

The npm run build / yarn build script calls node index.js. PINBOARD_TOKEN must be set in the environment (via .env locally, Netlify env vars in CI).

Content model

All content lives under posts/ as Markdown with YAML frontmatter. The posts/posts.json file applies tags: ["post"] to everything in the directory tree, making all posts part of the collections.post collection used for the home feed, feeds, and pagination.

Post types

Layout Used for Key frontmatter fields
post.html Blog posts, photo sets, quicklinks title, date, tags, featured, photos[], href (quicklinks)
book.html Book reviews title, author, isbn, rating (1–3), tags
post-p5.html Interactive / generative art posts same as post + postname (used to load <postname>.js)

Photo gallery posts: set featured (single image path) for OG image and photos array (each with url, alt, orientation: landscape|portrait) to render a gallery.

Quicklinks: auto-generated with href pointing to the linked URL; the post.html template renders an outbound link.

Books: rating is 1–3 stars; displayed as ★/☆ in book.html. ISBN links to Open Library.

Frontmatter reference

---
title: "Post title"
date: "2024-06-15"
layout: "post.html"          # post.html | book.html | post-p5.html
tags: ["fotos"]              # "post" is added by posts/posts.json
postname: "my-post-slug"     # used for p5.js script loading; also in book posts
description: "..."           # OG/meta description
featured: "/uploads/2024/01/image.jpg"   # OG image + inline image
photos:                      # gallery
  - url: "/uploads/..."
    alt: "..."
    orientation: landscape   # landscape | portrait
href: "https://..."          # quicklinks only: external URL
# Book-specific:
author: "Author Name"
isbn: "9781234567890"
rating: 3
---

Templates and rendering

All layouts chain via layout: frontmatter. The rendering stack:

post.html / book.html / post-p5.html
  └── template.html   (base: <html>, <head>, <nav>, <main>)

Templates use Liquid (.html files) and Nunjucks (.njk files). Eleventy supports both. Liquid is used for the main layouts; tags.njk uses Nunjucks explicitly.

Eleventy configuration (.eleventy.js)

Feeds

Styling

Single file: styles/main.css. Approach:

Automated deploys (Netlify)

netlify/functions/scheduled-deploy.js is a Netlify scheduled function that fires at 11:06, 16:06, and 21:06 UTC daily. It POSTs to a Netlify deploy hook (env var DEPLOY_HOOK), triggering a rebuild to pull in new Pinboard quicklinks.

netlify.toml enables the netlify-plugin-cache plugin to persist:

Content management

.pages.yml configures Pages CMS, a Git-based headless CMS. It exposes the posts/ directory as a collection with fields for all frontmatter keys, a layout selector (book.html / post.html), and image upload to uploads/.

Utility scripts

These scripts are run manually outside the build to create content stubs:

Environment variables

Variable Used by Purpose
PINBOARD_TOKEN quicklinks.js Pinboard API authentication
DEPLOY_HOOK netlify/functions/scheduled-deploy.js Netlify build hook URL