From ebe07cbae5a9f9bee5af0b6b755e5a63cf0c8663 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Wed, 8 Apr 2026 12:48:24 -0700 Subject: [PATCH] Merge gallery into /anti-patterns, hide rule ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes from the review. 1. Rule id chip hidden. The internal slugs (e.g. 'border-accent-on-rounded') are not useful to readers, only to detector code. Drop the .rule-card-id element from the card head entirely. The DOM id on the article stays so rules can still be anchor-linked. 2. Merge /gallery into /anti-patterns and drop 'Gallery' from the nav. 'Gallery' in the top nav reads as 'things built with impeccable' when it is actually a curated collection of AI-generated UI in the wild — the complement to the rule catalog above. - Add GALLERY_ITEMS to content/site/anti-patterns-catalog.js (11 entries, same ids and copy as the old gallery.html) - Render a new 'In the wild' section at the bottom of /anti-patterns with a card grid of the 11 specimens, each linking to its standalone live example under /antipattern-examples/{id}.html - New .gallery-card CSS: square thumbnail, italic display title, charcoal body, hover lifts the card and tints the title accent - Add an 'In the wild' entry to the anti-patterns TOC sidebar so readers can jump to it - Drop the 'Gallery' link from the top-level nav in the shared header partial and the 4 hand-authored HTML pages. The old /gallery route still serves its page directly (for bookmarked links), but the nav no longer advertises it and the gallery page itself now marks Anti-Patterns as the active nav item. --- content/site/anti-patterns-catalog.js | 83 +++++++++++++++++++- content/site/partials/header.html | 1 - public/cheatsheet.html | 1 - public/css/sub-pages.css | 104 +++++++++++++++++++++----- public/gallery.html | 3 +- public/index.html | 1 - public/privacy.html | 1 - scripts/build-sub-pages.js | 40 ++++++++-- scripts/lib/sub-pages-data.js | 7 +- 9 files changed, 205 insertions(+), 36 deletions(-) diff --git a/content/site/anti-patterns-catalog.js b/content/site/anti-patterns-catalog.js index b864f77e9..6f7ddeea6 100644 --- a/content/site/anti-patterns-catalog.js +++ b/content/site/anti-patterns-catalog.js @@ -165,8 +165,6 @@ export const VISUAL_EXAMPLES = { 'mobile-amputation': `
Export to CSV
"Not available on mobile."
`, }; -// ─── LLM-only rules ────────────────────────────────────────────────── - /** * Anti-patterns that live in the /impeccable skill's DON'T list but * don't have a deterministic detector. These can only be caught by @@ -176,6 +174,87 @@ export const VISUAL_EXAMPLES = { * description, skillSection. The generator merges these into the * grouped sections alongside detected rules with an 'llm' layer badge. */ +// ─── Gallery: real examples in the wild ────────────────────────────── + +/** + * Curated real-world examples of anti-patterns caught in the wild. + * Each entry maps to: + * - public/antipattern-images/{id}.png (preview thumbnail) + * - public/antipattern-examples/{id}.html (standalone live example) + * Rendered as a dedicated section on the /anti-patterns page, replacing + * the old /gallery route which was confusingly labeled in the top nav. + */ +export const GALLERY_ITEMS = [ + { + id: 'purple-gradients', + title: 'Purple Gradients Everywhere', + desc: + 'The AI color palette: purple-to-blue gradients on everything. Buttons, text, backgrounds, orbs. The new "make it pop."', + }, + { + id: 'lazy-cool', + title: 'Lazy "Cool"', + desc: + 'Glassmorphism, neon glows, blurred orbs, monospace everything. Looks like a hackathon project, not a product.', + }, + { + id: 'lazy-impact', + title: 'Lazy "Impact"', + desc: + 'When in doubt, animate everything. Bouncing buttons, wiggling icons, gradient text, floating badges. Motion without meaning.', + }, + { + id: 'thick-border-cards', + title: 'Side-Tab Cards', + desc: + 'A thick colored border on one side of a rounded card. The single most recognizable tell of AI-generated UI.', + }, + { + id: 'cardocalypse', + title: 'Cardocalypse', + desc: + 'Cards inside cards inside cards. Five levels of nesting, each with its own padding and shadow.', + }, + { + id: 'layout-templates', + title: 'Copy-Paste Layouts', + desc: + 'The same hero-metric-features template repeated with different colors. When every section looks the same, nothing stands out.', + }, + { + id: 'inter-everywhere', + title: 'Inter Everywhere', + desc: + 'One font for everything. Headings, body, labels, buttons. No typographic hierarchy, no personality, no design.', + }, + { + id: 'massive-icons', + title: 'Massive Icons', + desc: + 'Icon containers larger than the content they introduce. When the decoration is bigger than the message, priorities are backwards.', + }, + { + id: 'bad-contrast', + title: 'Bad Contrast Choices', + desc: + 'Gray text on colored backgrounds, low-contrast labels, unreadable combinations. Looking good and being readable should not conflict.', + }, + { + id: 'redundant-ux-writing', + title: 'Redundant UX Writing', + desc: + 'Label, sublabel, helper text, and hint text all saying the same thing in slightly different words. Say it once, say it well.', + }, + { + id: 'modal-abuse', + title: 'Modal Abuse', + desc: + 'Complex settings crammed into a modal. If it needs a scroll bar and three columns, it deserves its own page.', + }, +]; + +// ─── LLM-only rules ────────────────────────────────────────────────── + export const LLM_ONLY_RULES = [ { id: 'syne-display-font', diff --git a/content/site/partials/header.html b/content/site/partials/header.html index c262b3087..a8931c269 100644 --- a/content/site/partials/header.html +++ b/content/site/partials/header.html @@ -9,7 +9,6 @@ Home Docs Anti-Patterns - Gallery diff --git a/public/cheatsheet.html b/public/cheatsheet.html index c05a43d63..ee10745b4 100644 --- a/public/cheatsheet.html +++ b/public/cheatsheet.html @@ -176,7 +176,6 @@ Home Docs Anti-Patterns - Gallery diff --git a/public/css/sub-pages.css b/public/css/sub-pages.css index 79940eba4..729f7c1ba 100644 --- a/public/css/sub-pages.css +++ b/public/css/sub-pages.css @@ -812,27 +812,9 @@ main#main { .rule-card-head { display: flex; align-items: center; - justify-content: space-between; - gap: var(--spacing-sm); - margin-bottom: 2px; - min-height: 18px; -} - -.rule-card-id { - font-family: var(--font-mono); - font-size: 0.75rem; - font-weight: 500; - color: var(--color-ash); - background: transparent; - padding: 0; - border: none; -} - -.rule-card-badges { - display: inline-flex; - align-items: center; gap: 6px; - flex-shrink: 0; + margin-bottom: 2px; + flex-wrap: wrap; } .rule-card-category { @@ -1123,6 +1105,88 @@ main#main { max-width: 65ch; } +/* ============================================ + ANTI-PATTERNS: IN THE WILD (merged gallery) + ============================================ */ + +.gallery-section { + margin-top: clamp(3rem, 6vw, 4.5rem); +} + +.gallery-section-lede { + font-size: 0.9375rem; + line-height: 1.6; + color: var(--color-charcoal); + max-width: 60ch; + margin-bottom: var(--spacing-lg); +} + +.gallery-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: var(--spacing-md); +} + +.gallery-card { + display: flex; + flex-direction: column; + background: var(--color-paper); + border: 1px solid var(--color-mist); + border-radius: 10px; + overflow: hidden; + text-decoration: none; + color: inherit; + transition: border-color var(--duration-fast) var(--ease-out), + transform var(--duration-fast) var(--ease-out); +} + +.gallery-card:hover { + border-color: var(--color-ink); + transform: translateY(-2px); +} + +.gallery-card-thumb { + aspect-ratio: 1; + overflow: hidden; + background: var(--color-cream); + border-bottom: 1px solid var(--color-mist); +} + +.gallery-card-thumb img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: top left; + display: block; +} + +.gallery-card-body { + padding: var(--spacing-md); + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; +} + +.gallery-card-title { + font-family: var(--font-display); + font-size: 1.125rem; + font-style: italic; + font-weight: 500; + color: var(--color-ink); + line-height: 1.25; +} + +.gallery-card:hover .gallery-card-title { + color: var(--color-accent); +} + +.gallery-card-desc { + font-size: 0.8125rem; + line-height: 1.55; + color: var(--color-charcoal); +} + /* ============================================ MOBILE: collapsible sidebar behind a toggle ============================================ */ diff --git a/public/gallery.html b/public/gallery.html index 9b694f896..5c2765838 100644 --- a/public/gallery.html +++ b/public/gallery.html @@ -197,8 +197,7 @@ diff --git a/public/index.html b/public/index.html index 5e18347e6..b7fb0bdc2 100644 --- a/public/index.html +++ b/public/index.html @@ -59,7 +59,6 @@ Home Docs Anti-Patterns - Gallery diff --git a/public/privacy.html b/public/privacy.html index bd76cfca2..e93fe22bc 100644 --- a/public/privacy.html +++ b/public/privacy.html @@ -34,7 +34,6 @@ Home Docs Anti-Patterns - Gallery diff --git a/scripts/build-sub-pages.js b/scripts/build-sub-pages.js index f54b24e0c..f9e7a3cf4 100644 --- a/scripts/build-sub-pages.js +++ b/scripts/build-sub-pages.js @@ -19,6 +19,7 @@ import { CATEGORY_DESCRIPTIONS, LAYER_LABELS, LAYER_DESCRIPTIONS, + GALLERY_ITEMS, } from './lib/sub-pages-data.js'; import { renderMarkdown, slugify } from './lib/render-markdown.js'; import { renderPage } from './lib/render-page.js'; @@ -356,11 +357,16 @@ function renderAntiPatternsSidebar(grouped) { return `