mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
Deprecate /gallery page, redirect to /visual-mode#try-it-live
The gallery page had broken styling and missing images. The visual mode page already has the same specimen gallery in a better layout. - Removed public/gallery.html and its build entry point - Updated homepage links to point to /visual-mode#try-it-live - Added 301 redirect from /gallery to /visual-mode#try-it-live - Added id="try-it-live" anchor to the visual-mode gallery section Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a530f08df6
commit
7d29aaca1b
@@ -1,307 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gallery of Shame | AI Anti-Patterns in the Wild | Impeccable</title>
|
||||
<meta name="description" content="A curated collection of the most common AI-generated UI anti-patterns. Learn to spot them, laugh at them, then fix them.">
|
||||
<link rel="icon" type="image/svg+xml" href="./favicon.svg">
|
||||
<link rel="canonical" href="https://impeccable.style/gallery">
|
||||
|
||||
<meta property="og:title" content="Gallery of Shame | AI Anti-Patterns | Impeccable">
|
||||
<meta property="og:description" content="A curated collection of the most common AI-generated UI anti-patterns. Learn to spot them, laugh at them, then fix them.">
|
||||
<meta property="og:url" content="https://impeccable.style/gallery">
|
||||
<meta property="og:image" content="https://impeccable.style/og-image.jpg">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400;1,600&family=Instrument+Sans:wght@400;500;600&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./css/sub-pages.css">
|
||||
<style>
|
||||
:root {
|
||||
--font-display: 'Cormorant Garamond', Georgia, serif;
|
||||
--font-body: 'Instrument Sans', system-ui, sans-serif;
|
||||
--font-mono: 'Space Grotesk', monospace;
|
||||
--color-ink: oklch(10% 0 0);
|
||||
--color-paper: oklch(98% 0 0);
|
||||
--color-cream: oklch(96% 0.005 350);
|
||||
--color-charcoal: oklch(25% 0 0);
|
||||
--color-ash: oklch(55% 0 0);
|
||||
--color-mist: oklch(92% 0 0);
|
||||
--color-bg: oklch(96% 0.005 350);
|
||||
--color-accent: oklch(60% 0.25 350);
|
||||
--color-accent-hover: oklch(52% 0.25 350);
|
||||
--color-shame-red: oklch(55% 0.2 25);
|
||||
--spacing-xs: 8px;
|
||||
--spacing-sm: 16px;
|
||||
--spacing-md: 24px;
|
||||
--spacing-lg: 32px;
|
||||
--spacing-xl: 48px;
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
* { margin: 0; }
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
background: var(--color-paper);
|
||||
color: var(--color-ink);
|
||||
line-height: 1.55;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.gallery-content a { color: var(--color-accent); text-decoration: underline; text-underline-offset: 3px; }
|
||||
.gallery-content a:hover { color: var(--color-accent-hover); }
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: var(--spacing-xl) var(--spacing-lg);
|
||||
text-align: center;
|
||||
}
|
||||
.hero-eyebrow {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.15em;
|
||||
color: var(--color-shame-red);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
.hero h1 {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(2.5rem, 5vw, 4rem);
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
line-height: 1.1;
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
.hero p {
|
||||
font-size: 1.125rem;
|
||||
color: var(--color-charcoal);
|
||||
max-width: 52ch;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Grid */
|
||||
.gallery-grid {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--spacing-lg) var(--spacing-xl);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Card */
|
||||
.card {
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.3s var(--ease-out), border-color 0.3s var(--ease-out);
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: 0 12px 40px -8px rgba(0,0,0,0.12);
|
||||
border-color: var(--color-ash);
|
||||
}
|
||||
.card-thumb {
|
||||
aspect-ratio: 16 / 10;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--color-mist);
|
||||
background: var(--color-cream);
|
||||
}
|
||||
.card-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.card-thumb-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s var(--ease-out);
|
||||
}
|
||||
.card:hover .card-thumb-overlay { opacity: 1; }
|
||||
.card-thumb-overlay span {
|
||||
color: white;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8125rem;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid rgba(255,255,255,0.4);
|
||||
border-radius: 4px;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.card-body { padding: var(--spacing-md); }
|
||||
.card-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
color: var(--color-ink);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
line-height: 1.2;
|
||||
}
|
||||
.card-desc {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-ash);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.site-footer {
|
||||
margin-top: var(--spacing-xl);
|
||||
padding: var(--spacing-lg);
|
||||
border-top: 1px solid var(--color-mist);
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-ash);
|
||||
}
|
||||
.site-footer a { color: var(--color-ash); }
|
||||
.site-footer a:hover { color: var(--color-ink); }
|
||||
.footer-links { display: flex; gap: var(--spacing-md); justify-content: center; flex-wrap: wrap; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.hero { padding: var(--spacing-lg) var(--spacing-sm); }
|
||||
.gallery-grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0 var(--spacing-sm) var(--spacing-lg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="sub-page gallery-content">
|
||||
|
||||
<!-- site-header v1 -->
|
||||
<header class="site-header" data-site-header>
|
||||
<a href="/" class="site-header-brand" aria-label="Impeccable home">
|
||||
<svg class="site-header-brand-logo" viewBox="0 0 32 32" aria-hidden="true"><rect width="32" height="32" rx="6" fill="#1a1a1a"/><text x="16" y="24" font-family="system-ui, -apple-system, sans-serif" font-size="22" font-weight="500" fill="#f5f3ef" text-anchor="middle">/</text></svg>
|
||||
<span class="site-header-brand-name">Impeccable</span>
|
||||
</a>
|
||||
<div class="site-header-right">
|
||||
<nav class="site-header-nav" aria-label="Primary">
|
||||
<a href="/" data-nav="home">Home</a>
|
||||
<a href="/skills" data-nav="docs">Docs</a>
|
||||
<a href="/anti-patterns" data-nav="anti-patterns" aria-current="page">Anti-Patterns</a>
|
||||
<a href="/visual-mode" data-nav="visual-mode">Visual Mode</a>
|
||||
</nav>
|
||||
<a href="https://github.com/pbakaus/impeccable" class="site-header-github" target="_blank" rel="noopener" aria-label="Impeccable on GitHub, 18k stars">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
|
||||
<span class="site-header-github-label">18k</span>
|
||||
<svg class="site-header-github-star" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2l2.76 6.36L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.24-.91L12 2z"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<p class="hero-eyebrow">Gallery of Shame</p>
|
||||
<h1>The Tell-Tale Signs of AI-Generated UI</h1>
|
||||
</section>
|
||||
|
||||
<div class="gallery-grid" id="gallery"></div>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="footer-links">
|
||||
<a href="/">Home</a>
|
||||
<a href="/#antidote">Anti-Patterns</a>
|
||||
<a href="/cheatsheet">Cheatsheet</a>
|
||||
<a href="https://github.com/pbakaus/impeccable">GitHub</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const items = [
|
||||
{
|
||||
id: 'purple-gradients',
|
||||
title: 'Purple Gradients Everywhere',
|
||||
desc: 'The AI color palette: purple-to-blue gradients on everything. Buttons, text, backgrounds, orbs. It\'s 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. The inception of containers.',
|
||||
},
|
||||
{
|
||||
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 shouldn\'t 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.',
|
||||
},
|
||||
];
|
||||
|
||||
const grid = document.getElementById('gallery');
|
||||
|
||||
grid.innerHTML = items.map(item => `
|
||||
<a class="card-link" href="/antipattern-examples/${item.id}.html" target="_blank" rel="noopener">
|
||||
<article class="card">
|
||||
<div class="card-thumb">
|
||||
<img src="/antipattern-images/${item.id}.png"
|
||||
alt="${item.title} anti-pattern example"
|
||||
loading="lazy"
|
||||
width="540" height="540">
|
||||
<div class="card-thumb-overlay"><span>View live example</span></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">${item.title}</h2>
|
||||
<p class="card-desc">${item.desc}</p>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
`).join('');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+2
-2
@@ -269,7 +269,7 @@
|
||||
<span class="gallery-stack-label">Bad Contrast</span>
|
||||
</a>
|
||||
</div>
|
||||
<a href="/gallery" class="gallery-stack-link">View full gallery →</a>
|
||||
<a href="/visual-mode#try-it-live" class="gallery-stack-link">View full gallery →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -707,7 +707,7 @@
|
||||
<span class="footer-logo">Impeccable</span>
|
||||
<nav class="footer-links" aria-label="Footer">
|
||||
<a href="#antidote">Anti-Patterns</a>
|
||||
<a href="/gallery">Gallery of Shame</a>
|
||||
<a href="/visual-mode">Visual Mode</a>
|
||||
<a href="#language">Commands</a>
|
||||
<a href="/cheatsheet">Cheatsheet</a>
|
||||
<a href="/privacy">Privacy</a>
|
||||
|
||||
@@ -517,7 +517,7 @@ function renderVisualModeMain() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="visual-mode-gallery" aria-label="Try it on synthetic specimens">
|
||||
<section class="visual-mode-gallery" id="try-it-live" aria-label="Try it on synthetic specimens">
|
||||
<header class="visual-mode-gallery-header">
|
||||
<h2 class="visual-mode-gallery-title">Try it live</h2>
|
||||
<p class="visual-mode-gallery-lede">These ${GALLERY_ITEMS.length} synthetic slop pages ship with the detector script baked in. Click any to see the overlay running on a real page, then scroll around and hover the outlined elements.</p>
|
||||
|
||||
+1
-3
@@ -175,7 +175,6 @@ function validateNoEmDashes(rootDir) {
|
||||
'content/site',
|
||||
'public/index.html',
|
||||
'public/cheatsheet.html',
|
||||
'public/gallery.html',
|
||||
'public/privacy.html',
|
||||
'scripts/build-sub-pages.js',
|
||||
'scripts/lib/sub-pages-data.js',
|
||||
@@ -230,7 +229,6 @@ function validateSiteHeader(rootDir) {
|
||||
const pages = [
|
||||
'public/index.html',
|
||||
'public/cheatsheet.html',
|
||||
'public/gallery.html',
|
||||
'public/privacy.html',
|
||||
];
|
||||
const marker = '<!-- site-header v1 -->';
|
||||
@@ -284,7 +282,6 @@ async function buildStaticSite(extraEntrypoints = []) {
|
||||
const entrypoints = [
|
||||
path.join(ROOT_DIR, 'public', 'index.html'),
|
||||
path.join(ROOT_DIR, 'public', 'cheatsheet.html'),
|
||||
path.join(ROOT_DIR, 'public', 'gallery.html'),
|
||||
path.join(ROOT_DIR, 'public', 'privacy.html'),
|
||||
...extraEntrypoints,
|
||||
];
|
||||
@@ -531,6 +528,7 @@ function generateCFConfig(buildDir) {
|
||||
/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
|
||||
`;
|
||||
fs.writeFileSync(path.join(buildDir, '_redirects'), redirects);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user