From a200242a3d4fbeab3a27cc7abecb385fb8b47ebc Mon Sep 17 00:00:00 2001 From: Ryan Workman Date: Fri, 5 Jun 2026 16:10:09 -0600 Subject: [PATCH] Add drafts staging area for work-in-progress posts # Problem There was no safe place to keep in-progress drafts locally without risking them leaking into the build output or getting committed to the repo accidentally. # Solution Adds `_posts/drafts/` as a gitignored, build-skipped staging area. A new `EXCLUDED_THEME_DIRS` set in `build.js` tells `listThemeDirs()` to ignore the folder entirely, so anything sitting in drafts never renders, never appears on the homepage, and never generates a public `/drafts/` directory on the site. The workflow is: drop a draft into `_posts/drafts/` to work on it locally, then move it into a real `_posts//` folder when it's ready to publish. At that point it builds normally with no extra steps. CLAUDE.md is updated to document the convention alongside the rest of the `_posts/` architecture notes. # Notes The exclusion is name-based (`"drafts"`), not path-based, so a theme folder literally named `drafts` would also be excluded. That's an acceptable tradeoff given the convention is now documented. --- .gitignore | 1 + CLAUDE.md | 4 ++++ build.js | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 658c39d..06186ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ _local_preview.html node_modules/ .claude/ +_posts/drafts/ diff --git a/CLAUDE.md b/CLAUDE.md index 7f63550..3e37f10 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,6 +34,10 @@ The published URL will be ## Architecture - `_posts//*.md` — markdown sources. Theme = parent folder. +- `_posts/drafts/` — local, gitignored staging area for work-in-progress drafts. + `build.js` skips it (see `EXCLUDED_THEME_DIRS`), so a draft sitting here never + renders, never lands on the homepage, and never generates a public `drafts/` + directory. Move a draft into a real `_posts//` folder to publish it. - `_template.html` — per-post template. Carries the full `` (viewport, favicons, OG/Twitter meta, canonical link) plus the article body wrapper. - `_theme_template.html` — per-theme landing page template. diff --git a/build.js b/build.js index 4c12408..38524b1 100644 --- a/build.js +++ b/build.js @@ -137,13 +137,25 @@ function applyTemplate(template, vars) { // ---------- post discovery ---------- +// _posts/drafts/ is a local, gitignored staging area for work-in-progress +// drafts (e.g. imported from work notes). It is never rendered to the site — +// a draft gets moved into a real theme folder once it's ready to publish, at +// which point it starts building normally. Excluding it here keeps the staging +// area from leaking onto the homepage or generating a public /drafts/ dir. +const EXCLUDED_THEME_DIRS = new Set(["drafts"]); + function listThemeDirs() { if (!fs.existsSync(POSTS_DIR)) return []; return fs .readdirSync(POSTS_DIR, { withFileTypes: true }) .filter((e) => e.isDirectory()) .map((e) => e.name) - .filter((name) => !name.startsWith("_") && !name.startsWith(".")) + .filter( + (name) => + !name.startsWith("_") && + !name.startsWith(".") && + !EXCLUDED_THEME_DIRS.has(name), + ) .sort(); }