← back to build-pages
ui: prev/next project nav on /p/:slug — wraps at registry ends + 1 smoke
0c0d61c455f103667753afe0fd20bd613d8492a6 · 2026-05-13 17:47:05 -0700 · SteveStudio2
Files touched
M server.jsM test/smoke.js
Diff
commit 0c0d61c455f103667753afe0fd20bd613d8492a6
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 17:47:05 2026 -0700
ui: prev/next project nav on /p/:slug — wraps at registry ends + 1 smoke
---
server.js | 17 +++++++++++++++++
test/smoke.js | 1 +
2 files changed, 18 insertions(+)
diff --git a/server.js b/server.js
index 2fe46ca..8cd00ba 100644
--- a/server.js
+++ b/server.js
@@ -480,6 +480,12 @@ app.get('/p/:slug', async (req, res, next) => {
if (!p) return res.status(404).send(shell('Not found', '<h1>404</h1><p>No such project.</p>'));
try {
const { commits, facets, files } = await getProjectBundle(req.params.slug, p);
+ // Prev/next links across the registry — lets you cycle through journals
+ // without bouncing back to the home page each time. Wraps at the ends.
+ const slugs = Object.keys(PROJECTS);
+ const idx = slugs.indexOf(req.params.slug);
+ const prevSlug = slugs[(idx - 1 + slugs.length) % slugs.length];
+ const nextSlug = slugs[(idx + 1) % slugs.length];
const idxData = JSON.stringify(commits.map(c => ({
h: c.shortHash, d: c.dateISO.slice(0, 10), s: c.subject, b: c.body.slice(0, 4000),
})));
@@ -555,6 +561,17 @@ app.get('/p/:slug', async (req, res, next) => {
<ul class="bp-files">${fileLis}</ul>
</section>
+ <section class="bp-section">
+ <h2>Other build journals</h2>
+ <p class="bp-meta">
+ <a href="/p/${esc(prevSlug)}">← ${esc(PROJECTS[prevSlug].name)}</a>
+ ·
+ <a href="/">all 4 projects</a>
+ ·
+ <a href="/p/${esc(nextSlug)}">${esc(PROJECTS[nextSlug].name)} →</a>
+ </p>
+ </section>
+
<section class="bp-section">
<h2>Export</h2>
<p class="bp-meta">
diff --git a/test/smoke.js b/test/smoke.js
index ca8cdfd..bbb3dea 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -172,6 +172,7 @@ function check(name, cond, hint = '') {
check('feed: at least 1 entry', /<entry>/.test(r.body));
r = await fetch('/p/butlr');
check('butlr: feed autodiscover',/rel="alternate" type="application\/atom\+xml"/.test(r.body));
+ check('butlr: prev/next nav', /Other build journals/.test(r.body));
// 11b. CSV export (per project)
r = await fetch('/p/butlr/commits.csv');
← b6ddd07 api: /api/fleet/all one-shot aggregate (projects + velocity
·
back to build-pages
·
ui: commit-detail prev/next history nav — walk forward/backw a633cb5 →