Personal website for Joost van der Borg (joostvanderborg.nl), built with Eleventy (11ty v3) and deployed on Netlify.
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.
.
├── .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
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).
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.
| 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.
---
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
---
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.js)styles/, uploads/, posts/**/*.js, robots.txt, js/*humanDate — formats dates in Dutch short format (e.g. "15-6-2024")has_tags — returns tags minus the "post" base tagimage (async) — uses @11ty/eleventy-img to generate AVIF, WebP, JPEG at 600px and 2000px; outputs a <picture> element with srcsetogimage — returns path to the 600px version of an image for OG meta tags@11ty/eleventy-plugin-rss — generates /feed.xml (RSS) and /feed.json (JSON Feed), both from collections.post@11ty/eleventy-plugin-syntaxhighlight — Prism.js syntax highlighting/feed.xml — RSS 2.0/feed.json — JSON Feedcollections.postSingle file: styles/main.css. Approach:
prefers-color-scheme)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:
_site/uploads — Eleventy Image transformed/optimised images (avoids re-processing on every build).cache — @11ty/eleventy-fetch remote asset cache.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/.
These scripts are run manually outside the build to create content stubs:
book_list.js — reads a list of books (books.txt format: date Title, Author), looks each up on Open Library, and writes a Markdown stub into a given output directory. Usage: node book_list.js books.txt posts/2024/01/book_details.js — generates a single book stub from an ISBN. Legacy script, superseded by book_list.js.book_search.js / book_search_old.js — Open Library search helpers, also used to assist with book post creation.| Variable | Used by | Purpose |
|---|---|---|
PINBOARD_TOKEN |
quicklinks.js |
Pinboard API authentication |
DEPLOY_HOOK |
netlify/functions/scheduled-deploy.js |
Netlify build hook URL |