mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
Each problem-space fixture is now a single file with two columns: left
for cases that should flag, right for cases that should not. Matches the
icon-tile-stack convention and makes browser-based visual review easier.
The pass column proves that no false positives leak from look-alike
patterns next to the real anti-patterns.
Merged (4 pairs → 4 files)
- color-should-{flag,pass}.html → color.html
- motion-should-{flag,pass}.html → motion.html
- glow-should-{flag,pass}.html → glow.html
- layout-should-{flag,pass}.html → layout.html
Left untouched
- should-{flag,pass}.html — used by the CLI smoke tests in
detect-antipatterns.test.js, which need a known-clean fixture for the
exit-code-0 path.
- typography-should-{flag,pass}.html — all three typography rules
(overused-font, single-font, flat-type-hierarchy) are page-level and
fundamentally can't share a page with their pass cases. Loading two
font stacks suppresses single-font; varied sizes suppress flat-type-
hierarchy. Documented in the test file.
Test calibration
- Hardcoded the jsdom finding counts (motion: 2 bounce + 2 layout-
transition; glow: 1 dark-glow). Real browser sees more because
jsdom doesn't fully apply class-based styles, but the pass-column
count is reliably 0. Browser-verified all 4 fixtures show expected
flag counts and zero pass-column false positives.
Fixture chrome fixes
- Sub-section labels (.col h3) now use #64748b instead of #94a3b8 so
the fixture's own UI doesn't trigger low-contrast. glow.html got a
CSS restructure into card-dark/card-light/card-medium variants so
every text/background pairing meets WCAG AA. layout.html's "card
with image" gradient changed from blue→purple to amber→rose so it
doesn't trip ai-color-palette.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
139 lines
6.8 KiB
HTML
139 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Layout Anti-Patterns — Should Flag vs Should Pass</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; background: #f9fafb; padding: 24px; margin: 0; color: #111827; }
|
|
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1280px; margin: 0 auto; }
|
|
.col h2 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }
|
|
.col h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; margin: 24px 0 8px; color: #64748b; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="grid">
|
|
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
LEFT COLUMN: should flag
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="flag">
|
|
<h2>Should flag</h2>
|
|
|
|
<h3>Nested cards (cardocalypse)</h3>
|
|
|
|
<!-- Classic: card inside card -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-4">
|
|
<h4 class="text-lg font-semibold mb-3">Outer Card</h4>
|
|
<div class="bg-white rounded-lg shadow-md p-4">
|
|
<h5 class="font-medium">Inner Card</h5>
|
|
<p class="text-sm text-gray-600">Card inside card.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Three levels deep -->
|
|
<div class="bg-white rounded-xl shadow-lg p-6 mb-4">
|
|
<h4 class="text-lg font-semibold mb-3">Level 1</h4>
|
|
<div class="bg-gray-50 rounded-lg shadow-sm p-4 mb-3">
|
|
<h5 class="font-medium mb-2">Level 2</h5>
|
|
<div class="bg-white rounded-md shadow-sm p-3">
|
|
<p class="text-sm">Level 3 — nesting inception.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CSS variant: border + bg + shadow nesting -->
|
|
<div style="background: white; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); padding: 1.5rem; margin-bottom: 1rem;">
|
|
<h4 style="font-weight: 600; margin-bottom: 0.75rem;">Outer (CSS)</h4>
|
|
<div style="background: #f9fafb; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); padding: 1rem;">
|
|
<p style="font-size: 0.875rem; color: #6b7280;">Inner card via CSS.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- shadcn-style Card nested in Card -->
|
|
<div class="rounded-lg border bg-white shadow-sm p-6 mb-4" data-component="card">
|
|
<h4 class="font-semibold mb-3">shadcn-style Outer Card</h4>
|
|
<div class="rounded-lg border bg-white shadow-sm p-4" data-component="card">
|
|
<p class="text-sm text-gray-600">Another shadcn Card nested inside.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════════════════════════════════════════════════════════
|
|
RIGHT COLUMN: should pass
|
|
═══════════════════════════════════════════════════════════ -->
|
|
<div class="col" data-col="pass">
|
|
<h2>Should pass</h2>
|
|
|
|
<h3>shadcn Card sub-components (not nested cards)</h3>
|
|
<div class="rounded-lg border bg-white shadow-sm mb-4">
|
|
<div class="flex flex-col space-y-1.5 p-6">
|
|
<h4 class="text-lg font-semibold">Card Title</h4>
|
|
<p class="text-sm text-gray-500">Card description goes here.</p>
|
|
</div>
|
|
<div class="p-6 pt-0">
|
|
<p class="text-sm text-gray-600">CardContent — a sub-section, not a nested card. No shadow, no border-radius of its own.</p>
|
|
</div>
|
|
<div class="flex items-center p-6 pt-0">
|
|
<button class="px-4 py-2 bg-gray-900 text-white text-sm rounded-md">Action</button>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Card with form inputs</h3>
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-4 border">
|
|
<h4 class="font-semibold mb-4">Settings</h4>
|
|
<div class="space-y-3">
|
|
<input type="text" placeholder="Name" class="w-full px-3 py-2 border rounded-md shadow-sm text-sm">
|
|
<input type="email" placeholder="Email" class="w-full px-3 py-2 border rounded-md shadow-sm text-sm">
|
|
<select class="w-full px-3 py-2 border rounded-md shadow-sm text-sm bg-white">
|
|
<option>Select option</option>
|
|
</select>
|
|
<textarea placeholder="Bio" class="w-full px-3 py-2 border rounded-md shadow-sm text-sm h-20 resize-none"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Card with code block</h3>
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-4 border">
|
|
<h4 class="font-semibold mb-3">Installation</h4>
|
|
<pre class="bg-gray-900 text-gray-100 rounded-md p-4 text-sm overflow-x-auto"><code>npm install @acme/sdk</code></pre>
|
|
</div>
|
|
|
|
<h3>Card with badges</h3>
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-4 border">
|
|
<h4 class="font-semibold mb-3">Tags</h4>
|
|
<div class="flex flex-wrap gap-2">
|
|
<span class="px-2 py-1 bg-blue-100 text-blue-700 rounded-full text-xs font-medium">React</span>
|
|
<span class="px-2 py-1 bg-green-100 text-green-700 rounded-full text-xs font-medium">TypeScript</span>
|
|
<span class="px-2 py-1 bg-purple-100 text-purple-700 rounded-full text-xs font-medium">Tailwind</span>
|
|
</div>
|
|
</div>
|
|
|
|
<h3>Card with image</h3>
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-4 border">
|
|
<div class="w-full h-32 bg-gradient-to-br from-amber-400 to-rose-500 rounded-lg shadow-inner mb-4"></div>
|
|
<h4 class="font-semibold">Project Preview</h4>
|
|
<p class="text-sm text-gray-600 mt-1">Image with rounded corners and shadow.</p>
|
|
</div>
|
|
|
|
<h3>Pricing cards (intentionally similar)</h3>
|
|
<div class="grid grid-cols-3 gap-2 mb-4">
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border">
|
|
<h4 class="font-semibold mb-1 text-sm">Free</h4>
|
|
<div class="text-lg font-bold mb-2">$0</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border-2 border-blue-500">
|
|
<h4 class="font-semibold mb-1 text-sm">Pro</h4>
|
|
<div class="text-lg font-bold mb-2">$29</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4 border">
|
|
<h4 class="font-semibold mb-1 text-sm">Enterprise</h4>
|
|
<div class="text-lg font-bold mb-2">Custom</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script src="/js/detect-antipatterns-browser.js"></script>
|
|
</body>
|
|
</html>
|