feat(site): merge /anti-patterns and /visual-mode into /slop

Top nav was at six items and growing. The anti-patterns catalog and the
visual-mode overlay demo were always two views of the same subject (the
rule set and seeing it caught in place), so collapsing them into one page
reduces nav weight and puts the catalog + live demo next to each other.

Four sections in one scroll: See it (iframe demo), Try it live (specimen
gallery), The catalog (full rule list), Run it yourself (invocation
methods). Sidebar TOC nests the catalog sections under "The catalog" for
deep linking. 301s from the old URLs preserve external links.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-23 13:13:56 -07:00
co-authored by Claude Opus 4.7
parent c160ffc38d
commit 5316809139
12 changed files with 310 additions and 224 deletions
+6 -4
View File
@@ -259,7 +259,7 @@ async function buildStaticSite(extraEntrypoints = []) {
// Older Bun versions (e.g. the one Cloudflare Pages ships) don't dedupe
// shared CSS/JS chunks across HTML entrypoints — every entry tries to
// emit its own copy, and three different sub-pages all named index.html
// (under skills/, tutorials/, anti-patterns/) collide on the same
// (under docs/, tutorials/, slop/) collide on the same
// chunk filename. Including [dir] in the chunk template scopes each
// chunk to its entry's directory so the names stay unique even when
// dedupe is off. Local Bun still emits a single shared chunk; CF Bun
@@ -527,15 +527,17 @@ function generateCFConfig(buildDir) {
fs.writeFileSync(path.join(buildDir, '_headers'), headers);
// _redirects: rewrite JSON API routes to static files (200 = rewrite, not redirect).
// Also permanent redirects for legacy URLs: /skills -> /docs, /cheatsheet -> /docs.
// Plus permanent redirects for legacy URLs.
const redirects = `/api/skills /_data/api/skills.json 200
/api/commands /_data/api/commands.json 200
/api/patterns /_data/api/patterns.json 200
/api/command-source/:id /_data/api/command-source/:id.json 200
/gallery /visual-mode#try-it-live 301
/gallery /slop#try-it-live 301
/cheatsheet /docs 301
/skills /docs 301
/skills/:id /docs/:id 301
/anti-patterns /slop#catalog 301
/visual-mode /slop#see-it 301
`;
fs.writeFileSync(path.join(buildDir, '_redirects'), redirects);
@@ -557,7 +559,7 @@ function generateCFConfig(buildDir) {
async function build() {
console.log('🔨 Building cross-provider design skills...\n');
// Pre-generate sub-pages (skills, anti-patterns, tutorials) from source
// Pre-generate sub-pages (docs, slop, tutorials, live-mode, designing) from source
console.log('📝 Generating sub-pages...');
const { files: subPageFiles } = await generateSubPages(ROOT_DIR);
console.log(`✓ Generated ${subPageFiles.length} sub-page(s)\n`);