mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
Refresh the Impeccable product experience
Rework the landing page proof, steering demo, feature grid, slop catalog, detector coverage, theming, Live workflow, and responsive behavior.\n\nAI-assisted implementation by OpenAI Codex.
This commit is contained in:
@@ -38,8 +38,8 @@ const { activeNav } = Astro.props;
|
||||
type="button"
|
||||
class="theme-toggle"
|
||||
data-theme-toggle
|
||||
aria-label="Theme: auto, matching your system. Click to switch to light mode."
|
||||
title="Theme: auto (matches system)"
|
||||
aria-label="Theme: dark. Click to switch to light mode."
|
||||
title="Theme: dark"
|
||||
>
|
||||
<svg class="theme-toggle-icon--auto" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
|
||||
@@ -1,47 +1,12 @@
|
||||
---
|
||||
const proofs = [
|
||||
{
|
||||
id: 'polish',
|
||||
command: '/polish',
|
||||
label: 'Remove the tells',
|
||||
summary: 'Three AI defaults removed',
|
||||
callouts: [
|
||||
{ label: 'Pulsing status', y: '25%' },
|
||||
{ label: 'Italic serif', y: '48%' },
|
||||
{ label: 'Claude beige', y: '76%' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'distill',
|
||||
command: '/distill',
|
||||
label: 'Find the hierarchy',
|
||||
summary: 'Seven containers flattened',
|
||||
callouts: [
|
||||
{ label: 'Cards in cards', y: '28%' },
|
||||
{ label: 'Everything equal', y: '52%' },
|
||||
{ label: 'Status-chip soup', y: '77%' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'clarify',
|
||||
command: '/clarify',
|
||||
label: 'Make the task obvious',
|
||||
summary: 'One clear decision remains',
|
||||
callouts: [
|
||||
{ label: 'Vague headline', y: '28%' },
|
||||
{ label: 'Every field at once', y: '54%' },
|
||||
{ label: 'Generic CTA', y: '78%' },
|
||||
],
|
||||
},
|
||||
{ id: 'polish', command: '/polish', label: 'Remove the tells' },
|
||||
{ id: 'distill', command: '/distill', label: 'Find the hierarchy' },
|
||||
{ id: 'clarify', command: '/clarify', label: 'Make the task obvious' },
|
||||
];
|
||||
---
|
||||
|
||||
<section class="hero-proof" data-hero-proof aria-label="Impeccable command before and after examples">
|
||||
<div class="hero-proof-topline">
|
||||
<span class="hero-proof-result" data-hero-proof-result aria-live="polite">{proofs[0].summary}</span>
|
||||
<span class="hero-proof-instruction">Drag to compare</span>
|
||||
</div>
|
||||
|
||||
<div class="hero-proof-stage">
|
||||
{proofs.map((proof, index) => (
|
||||
<div
|
||||
@@ -50,62 +15,82 @@ const proofs = [
|
||||
role="tabpanel"
|
||||
aria-labelledby={`hero-proof-tab-${proof.id}`}
|
||||
data-proof-panel={proof.id}
|
||||
data-summary={proof.summary}
|
||||
hidden={index !== 0}
|
||||
>
|
||||
<div class="hero-proof-layer hero-proof-layer--before">
|
||||
<span class="hero-proof-state hero-proof-state--before">AI default</span>
|
||||
<span class="hero-proof-side-label hero-proof-side-label--before">Before</span>
|
||||
|
||||
<div class={`hero-proof-canvas hero-proof-canvas--${proof.id}`} aria-hidden="true">
|
||||
{proof.id === 'polish' && (
|
||||
<article class="proof-polish proof-polish--before">
|
||||
<header class="proof-polish-head">
|
||||
<span class="proof-polish-pulse"><i></i> AI-powered</span>
|
||||
<span class="proof-polish-menu">•••</span>
|
||||
<span class="proof-polish-sprint">Launch / 14</span>
|
||||
<span class="proof-polish-pulse">
|
||||
<i></i> On track
|
||||
</span>
|
||||
</header>
|
||||
<div class="proof-polish-body">
|
||||
<span class="proof-polish-kicker">Built for modern teams</span>
|
||||
<h3>Beautifully <em>crafted</em> for the future of work.</h3>
|
||||
<p>Manage projects, share updates, and keep everyone aligned in one place.</p>
|
||||
<span class="proof-polish-cta">Get started</span>
|
||||
<span class="proof-polish-kicker">
|
||||
Release planning
|
||||
<span class="proof-annotation">AI kicker</span>
|
||||
</span>
|
||||
<div class="proof-polish-heading">
|
||||
<h3>Ship the <em>launch plan</em> by Friday.</h3>
|
||||
<span class="proof-annotation">Italic serif</span>
|
||||
</div>
|
||||
<p>Owners, dependencies, and decisions in one view.</p>
|
||||
<div class="proof-polish-progress"><i></i></div>
|
||||
<footer><span>8 of 11 decisions closed</span><b>Review plan →</b></footer>
|
||||
<span class="proof-annotation proof-annotation--surface">AI beige</span>
|
||||
</div>
|
||||
</article>
|
||||
)}
|
||||
|
||||
{proof.id === 'distill' && (
|
||||
<article class="proof-distill proof-distill--before">
|
||||
<header><strong>Analytics overview</strong><span>Live</span></header>
|
||||
<header>
|
||||
<strong>Analytics overview</strong>
|
||||
<span class="proof-distill-live">
|
||||
Live
|
||||
<span class="proof-annotation">Status-chip soup</span>
|
||||
</span>
|
||||
</header>
|
||||
<div class="proof-distill-grid">
|
||||
<div><small>Revenue</small><b>$84.2k</b><i>+12%</i></div>
|
||||
<div><small>Orders</small><b>1,248</b><i>+8%</i></div>
|
||||
<div><small>Visitors</small><b>18.4k</b><i>+21%</i></div>
|
||||
<div><small>Conversion</small><b>3.8%</b><i>+4%</i></div>
|
||||
<span class="proof-annotation">Everything equal</span>
|
||||
</div>
|
||||
<div class="proof-distill-nested">
|
||||
<span>Weekly performance</span><div><i></i><i></i><i></i></div>
|
||||
<span class="proof-annotation">Cards in cards</span>
|
||||
</div>
|
||||
<div class="proof-distill-nested"><span>Weekly performance</span><div><i></i><i></i><i></i></div></div>
|
||||
</article>
|
||||
)}
|
||||
|
||||
{proof.id === 'clarify' && (
|
||||
<article class="proof-clarify proof-clarify--before">
|
||||
<header><span>Get started</span><small>All fields required</small></header>
|
||||
<h3>Unlock your potential today</h3>
|
||||
<div class="proof-clarify-fields"><i></i><i></i><i></i><i></i></div>
|
||||
<span class="proof-clarify-cta">Continue</span>
|
||||
<div class="proof-clarify-heading">
|
||||
<h3>Unlock your potential today</h3>
|
||||
<span class="proof-annotation">Vague headline</span>
|
||||
</div>
|
||||
<div class="proof-clarify-fields">
|
||||
<i>Acme Labs</i><i>Product lead</i><i>Activation</i><i>This quarter</i>
|
||||
<span class="proof-annotation">Too many fields</span>
|
||||
</div>
|
||||
<span class="proof-clarify-cta">
|
||||
Continue
|
||||
<span class="proof-annotation">Generic CTA</span>
|
||||
</span>
|
||||
</article>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="hero-proof-callouts" aria-hidden="true">
|
||||
{proof.callouts.map((callout) => (
|
||||
<span class="hero-proof-callout" style={`--callout-y: ${callout.y};`}>
|
||||
{callout.label}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-proof-layer hero-proof-layer--after">
|
||||
<span class="hero-proof-state hero-proof-state--after">With Impeccable</span>
|
||||
<span class="hero-proof-side-label hero-proof-side-label--after">After</span>
|
||||
|
||||
<div class={`hero-proof-canvas hero-proof-canvas--${proof.id}`} aria-hidden="true">
|
||||
{proof.id === 'polish' && (
|
||||
@@ -115,7 +100,6 @@ const proofs = [
|
||||
<span class="proof-polish-track">On track</span>
|
||||
</header>
|
||||
<div class="proof-polish-body">
|
||||
<span class="proof-polish-kicker">Release planning</span>
|
||||
<h3>Ship the launch plan by Friday.</h3>
|
||||
<p>Owners, dependencies, and decisions in one view.</p>
|
||||
<div class="proof-polish-progress"><i></i></div>
|
||||
@@ -149,8 +133,8 @@ const proofs = [
|
||||
<input
|
||||
class="hero-proof-range"
|
||||
type="range"
|
||||
min="18"
|
||||
max="82"
|
||||
min="0"
|
||||
max="100"
|
||||
value="54"
|
||||
aria-label={`Reveal the improved ${proof.command} example`}
|
||||
data-proof-range
|
||||
@@ -167,12 +151,12 @@ const proofs = [
|
||||
class:list={['hero-proof-tab', { 'is-active': index === 0 }]}
|
||||
id={`hero-proof-tab-${proof.id}`}
|
||||
aria-controls={`hero-proof-panel-${proof.id}`}
|
||||
aria-label={`${proof.command} ${proof.label}`}
|
||||
aria-selected={index === 0 ? 'true' : 'false'}
|
||||
tabindex={index === 0 ? 0 : -1}
|
||||
data-proof-tab={proof.id}
|
||||
>
|
||||
<span class="hero-proof-command">{proof.command}</span>
|
||||
<span class="hero-proof-tab-label">{proof.label}</span>
|
||||
{proof.command}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
---
|
||||
import '../styles/live-ui-gallery.css';
|
||||
import { LIVE_COMMANDS } from '../../skill/scripts/live/vocabulary.mjs';
|
||||
|
||||
const STATE_GROUPS = [
|
||||
{
|
||||
label: 'Global chrome',
|
||||
states: [
|
||||
['global-ready', 'Ready'],
|
||||
['global-disconnected', 'Agent disconnected'],
|
||||
['global-foreground', 'Codex CLI fallback'],
|
||||
['global-tools', 'Detect + DESIGN.md'],
|
||||
['steer-expanded', 'Steer composing'],
|
||||
['steer-processing', 'Steer processing'],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Selection',
|
||||
states: [
|
||||
['configure-replace', 'Configure selection'],
|
||||
['action-picker', 'Action picker'],
|
||||
['configure-listening', 'Voice input'],
|
||||
['configure-locked', 'Apply locked'],
|
||||
['annotation', 'Annotations'],
|
||||
['insert-placeholder', 'Insert placeholder'],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Generation + review',
|
||||
states: [
|
||||
['generating', 'Generating'],
|
||||
['generation-recovery', 'Recovery'],
|
||||
['cycling-progressive', 'Variant 1 arrived'],
|
||||
['cycling-second', 'Variant 2 arrived'],
|
||||
['tune-open', 'Tune panel'],
|
||||
['applying', 'Applying variant'],
|
||||
['confirmed', 'Variant applied'],
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Copy + support',
|
||||
states: [
|
||||
['edit-copy', 'Edit copy'],
|
||||
['copy-pending', 'Copy edits pending'],
|
||||
['copy-applying', 'Copy edits applying'],
|
||||
['copy-attention', 'Apply needs attention'],
|
||||
['design-panel', 'DESIGN.md panel'],
|
||||
['toast-error', 'Error toast'],
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const statePayload = STATE_GROUPS.flatMap((group) =>
|
||||
group.states.map(([key, label]) => ({ key, label, group: group.label })),
|
||||
);
|
||||
const commandPayload = JSON.stringify(LIVE_COMMANDS).replace(/</g, '\\u003c');
|
||||
const statesJson = JSON.stringify(statePayload).replace(/</g, '\\u003c');
|
||||
---
|
||||
|
||||
<!--
|
||||
Dev-only, embeddable state harness for Impeccable Live. The chrome mirrors:
|
||||
- skill/scripts/live-browser.js (standalone browser UI and exact wording)
|
||||
- skill/scripts/live/ui-core.mjs (surface/state inventory)
|
||||
- skill/scripts/live/vocabulary.mjs (canonical command labels and SVGs)
|
||||
|
||||
Production Live deliberately uses the same dark Neo Kinpaku chrome on light
|
||||
and dark host pages (barPaletteForTheme, live-browser.js). The two columns
|
||||
below therefore vary the host canvas, not the chrome palette.
|
||||
-->
|
||||
<section class="live-ui-gallery" data-live-ui-gallery data-dev-only="true" aria-label="Live UI state inspector">
|
||||
<header class="live-ui-gallery__header" data-live-ui-gallery-controls>
|
||||
<div class="live-ui-gallery__state-readout" aria-live="polite" aria-atomic="true">
|
||||
<span data-gallery-state-group>Global chrome</span>
|
||||
<strong data-gallery-state-label>Ready</strong>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="live-ui-gallery__control-panel"
|
||||
aria-label="Gallery controls"
|
||||
aria-keyshortcuts="ArrowLeft ArrowRight Home End"
|
||||
>
|
||||
<label class="live-ui-gallery__sr-only" for="live-ui-gallery-state">State</label>
|
||||
<div class="live-ui-gallery__select-row">
|
||||
<button type="button" class="live-ui-gallery__step" data-gallery-step="-1" aria-label="Previous state">←</button>
|
||||
<select id="live-ui-gallery-state" data-gallery-state aria-controls="live-ui-gallery-light-stage live-ui-gallery-dark-stage">
|
||||
{STATE_GROUPS.map((group) => (
|
||||
<optgroup label={group.label}>
|
||||
{group.states.map(([key, label]) => <option value={key}>{label}</option>)}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
<button type="button" class="live-ui-gallery__step" data-gallery-step="1" aria-label="Next state">→</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="live-ui-gallery__quick-nav" aria-label="Quick state selection">
|
||||
{STATE_GROUPS.map((group) => (
|
||||
<div class="live-ui-gallery__quick-group">
|
||||
<span>{group.label}</span>
|
||||
<div>
|
||||
{group.states.map(([key, label]) => (
|
||||
<button type="button" data-gallery-state-button={key}>{label}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="live-ui-gallery__previews" data-live-ui-gallery-workspace>
|
||||
<section class="live-ui-gallery__preview" aria-labelledby="live-ui-gallery-light-title">
|
||||
<header>
|
||||
<span class="live-ui-gallery__theme-dot" aria-hidden="true"></span>
|
||||
<h3 id="live-ui-gallery-light-title">Light host</h3>
|
||||
<code>host: light</code>
|
||||
</header>
|
||||
<div id="live-ui-gallery-light-stage" class="live-ui-stage is-light" data-live-gallery-preview="light"></div>
|
||||
</section>
|
||||
|
||||
<section class="live-ui-gallery__preview" aria-labelledby="live-ui-gallery-dark-title">
|
||||
<header>
|
||||
<span class="live-ui-gallery__theme-dot" aria-hidden="true"></span>
|
||||
<h3 id="live-ui-gallery-dark-title">Dark host</h3>
|
||||
<code>host: dark</code>
|
||||
</header>
|
||||
<div id="live-ui-gallery-dark-stage" class="live-ui-stage is-dark" data-live-gallery-preview="dark"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script is:inline type="application/json" data-live-gallery-states set:html={statesJson}></script>
|
||||
<script is:inline type="application/json" data-live-gallery-vocabulary set:html={commandPayload}></script>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
import '../scripts/live-ui-gallery.js';
|
||||
</script>
|
||||
@@ -1,16 +1,24 @@
|
||||
<section class="slop-teaser-section slop-pattern-section" id="slop" aria-labelledby="slop-pattern-title">
|
||||
<section
|
||||
class="slop-teaser-section slop-pattern-section"
|
||||
id="slop"
|
||||
aria-labelledby="slop-pattern-title"
|
||||
data-slop-scan
|
||||
data-detector="on"
|
||||
>
|
||||
<header class="slop-pattern-head">
|
||||
<div>
|
||||
<h2 id="slop-pattern-title" class="slop-teaser-title">AI has a house style. Impeccable knows the tells.</h2>
|
||||
<h2 id="slop-pattern-title" class="slop-teaser-title">Detects and removes AI slop.</h2>
|
||||
<p class="slop-teaser-body">
|
||||
The defaults move. The pattern is the same: the model reaches for whatever currently signals
|
||||
“taste” without asking whether it belongs. Impeccable catches those reflexes before they become your design.
|
||||
59 checks catch the defaults agents keep reaching for before they become your design.
|
||||
</p>
|
||||
</div>
|
||||
<div class="slop-pattern-actions">
|
||||
<span class="slop-pattern-count"><strong>59</strong> detector checks</span>
|
||||
<button class="slop-scan-control" type="button" aria-pressed="true" data-slop-scan-button>
|
||||
<span class="slop-scan-control-dot" aria-hidden="true"></span>
|
||||
<span data-slop-scan-label>Detector on</span>
|
||||
</button>
|
||||
<a class="ks-button ks-button-secondary" href="/slop">
|
||||
Open the full gallery
|
||||
Explore all 59
|
||||
<span class="ks-button-arrow" aria-hidden="true">
|
||||
<svg viewBox="0 0 16 8" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square">
|
||||
<path d="M0 4h14M10 0l4 4-4 4"/>
|
||||
@@ -20,80 +28,150 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="slop-pattern-board">
|
||||
<article class="slop-pattern-item slop-pattern-item--wide">
|
||||
<div class="slop-pattern-specimen slop-pattern-specimen--serif" aria-hidden="true">
|
||||
<span class="slop-pattern-kicker">A quieter way to work</span>
|
||||
<span class="slop-pattern-serif-line">Beautifully <em>crafted</em><br />for modern teams.</span>
|
||||
</div>
|
||||
<div class="slop-pattern-meta">
|
||||
<span class="slop-pattern-index">Typography · detected</span>
|
||||
<h3>Italic serif hero</h3>
|
||||
<p>Instrument Serif and its neighbors became the shortcut for tasteful AI output.</p>
|
||||
</div>
|
||||
</article>
|
||||
<div class="slop-pattern-board" aria-label="Interactive gallery of detected AI design patterns">
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--serif"
|
||||
href="/slop#rule-italic-serif-display"
|
||||
aria-label="View rule: Italic serif display headline on an AI beige palette"
|
||||
style="--scan-order: 0"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--serif" aria-hidden="true">
|
||||
<span class="slop-target slop-target--serif" data-label="AI beige + serif">
|
||||
Beautifully <em>crafted</em><br />for modern teams.
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<article class="slop-pattern-item">
|
||||
<div class="slop-pattern-specimen slop-pattern-specimen--beige" aria-hidden="true">
|
||||
<span class="slop-beige-wordmark">Claude & Co.</span>
|
||||
<span class="slop-beige-copy">Soft, tasteful, safely indistinct.</span>
|
||||
<span class="slop-beige-button">Begin</span>
|
||||
</div>
|
||||
<div class="slop-pattern-meta">
|
||||
<span class="slop-pattern-index">Color · detected</span>
|
||||
<h3>Claude beige</h3>
|
||||
<p>Warm tinted paper is now the safe AI surface, chosen before the product has a palette.</p>
|
||||
</div>
|
||||
</article>
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--soft-card"
|
||||
href="/slop#rule-generic-drop-shadows"
|
||||
aria-label="View rule: Rounded rectangles with generic drop shadows"
|
||||
style="--scan-order: 1"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--soft-card" aria-hidden="true">
|
||||
<span class="slop-target slop-target--soft-card" data-label="Soft rounded card">
|
||||
<span class="slop-soft-card-icon">✦</span>
|
||||
<strong>Everything in one place</strong>
|
||||
<span class="slop-soft-card-copy">Plan, create, and collaborate with ease.</span>
|
||||
<span class="slop-soft-card-action">Get started <i>→</i></span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<article class="slop-pattern-item">
|
||||
<div class="slop-pattern-specimen slop-pattern-specimen--sidetab" aria-hidden="true">
|
||||
<div class="slop-side-card">
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--sidetab"
|
||||
href="/slop#rule-side-tab"
|
||||
aria-label="View rule: Side-tab accent border"
|
||||
style="--scan-order: 2"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--sidetab" aria-hidden="true">
|
||||
<span class="slop-target slop-target--sidetab" data-label="Side-tab border">
|
||||
<strong>Performance insight</strong>
|
||||
<span>Your conversion rate is up 12% this week.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slop-pattern-meta">
|
||||
<span class="slop-pattern-index">Visual detail · detected</span>
|
||||
<h3>Side-tab border</h3>
|
||||
<p>A thick colored stripe on a rounded card remains one of the clearest generated-UI tells.</p>
|
||||
</div>
|
||||
</article>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<article class="slop-pattern-item">
|
||||
<div class="slop-pattern-specimen slop-pattern-specimen--pulse" aria-hidden="true">
|
||||
<div class="slop-pulse-status">
|
||||
<span class="slop-pulse-dot"></span>
|
||||
<span>AI is thinking</span>
|
||||
</div>
|
||||
<div class="slop-pulse-lines"><i></i><i></i><i></i></div>
|
||||
</div>
|
||||
<div class="slop-pattern-meta">
|
||||
<span class="slop-pattern-index">Motion · detected</span>
|
||||
<h3>Pulsing status dot</h3>
|
||||
<p>Decorative pulse implies live state even when nothing is changing.</p>
|
||||
</div>
|
||||
</article>
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--eyebrow"
|
||||
href="/slop#rule-hero-eyebrow-chip"
|
||||
aria-label="View rule: Hero eyebrow pill chip"
|
||||
style="--scan-order: 3"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--eyebrow" aria-hidden="true">
|
||||
<span class="slop-target slop-target--eyebrow" data-label="Eyebrow chip">
|
||||
<span class="slop-eyebrow-chip">Introducing</span>
|
||||
<strong>The operating system<br />for modern teams.</strong>
|
||||
<span>Everything you need to move faster.</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<article class="slop-pattern-item slop-pattern-item--wide">
|
||||
<div class="slop-pattern-specimen slop-pattern-specimen--nested" aria-hidden="true">
|
||||
<div class="slop-nested-shell">
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--pulse"
|
||||
href="/slop#section-motion"
|
||||
aria-label="View rule: Decorative pulsing status dot"
|
||||
style="--scan-order: 4"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--pulse" aria-hidden="true">
|
||||
<span class="slop-target slop-target--pulse" data-label="Pulsing status dot">
|
||||
<span class="slop-pulse-status"><i class="slop-pulse-dot"></i> AI is thinking</span>
|
||||
<span class="slop-pulse-lines"><i></i><i></i><i></i></span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--nested"
|
||||
href="/slop#rule-nested-cards"
|
||||
aria-label="View rule: Nested cards"
|
||||
style="--scan-order: 5"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--nested" aria-hidden="true">
|
||||
<span class="slop-target slop-target--nested" data-label="Cards in cards">
|
||||
<span>Workspace</span>
|
||||
<div class="slop-nested-card">
|
||||
<span class="slop-nested-card">
|
||||
<span>Overview</span>
|
||||
<div class="slop-nested-card slop-nested-card--inner">Card inside card inside card.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slop-pattern-meta">
|
||||
<span class="slop-pattern-index">Layout · detected</span>
|
||||
<h3>Nested cards</h3>
|
||||
<p>Containers become the hierarchy because the model never made one with type, space, or rhythm.</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<span class="slop-nested-card slop-nested-card--inner">Card inside card inside card.</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<footer class="slop-pattern-foot">
|
||||
<p><code>npx impeccable detect src/</code> catches deterministic tells. <a href="/docs/critique">/critique</a> adds the design review.</p>
|
||||
</footer>
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--icons"
|
||||
href="/slop#rule-icon-tile-stack"
|
||||
aria-label="View rule: Icon tile stacked above heading"
|
||||
style="--scan-order: 6"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--icons" aria-hidden="true">
|
||||
<span class="slop-target slop-target--icons" data-label="Identical icon tiles">
|
||||
<span><i>✦</i><b>Automate</b><small>Move faster.</small></span>
|
||||
<span><i>⌁</i><b>Integrate</b><small>Work smarter.</small></span>
|
||||
<span><i>↗</i><b>Scale</b><small>Grow together.</small></span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="slop-pattern-item slop-pattern-item--markers"
|
||||
href="/slop#rule-numbered-section-markers"
|
||||
aria-label="View rule: Numbered section markers"
|
||||
style="--scan-order: 7"
|
||||
>
|
||||
<span class="slop-pattern-specimen slop-pattern-specimen--markers" aria-hidden="true">
|
||||
<span class="slop-target slop-target--markers" data-label="Numbered section labels">
|
||||
<span><b>01</b> Discover</span>
|
||||
<span><b>02</b> Design</span>
|
||||
<span><b>03</b> Deliver</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
const setupSlopDetectors = () => {
|
||||
document.querySelectorAll<HTMLElement>('[data-slop-scan]').forEach((root) => {
|
||||
if (root.dataset.scanReady === 'true') return;
|
||||
root.dataset.scanReady = 'true';
|
||||
|
||||
const button = root.querySelector<HTMLButtonElement>('[data-slop-scan-button]');
|
||||
const label = root.querySelector<HTMLElement>('[data-slop-scan-label]');
|
||||
if (!button || !label) return;
|
||||
|
||||
const setDetector = (active: boolean) => {
|
||||
root.dataset.detector = active ? 'on' : 'off';
|
||||
button.setAttribute('aria-pressed', String(active));
|
||||
label.textContent = active ? 'Detector on' : 'Detector off';
|
||||
};
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
setDetector(button.getAttribute('aria-pressed') !== 'true');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
setupSlopDetectors();
|
||||
document.addEventListener('astro:page-load', setupSlopDetectors);
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
const {
|
||||
rule,
|
||||
visual,
|
||||
layer = 'cli',
|
||||
description = rule.description,
|
||||
categoryLabel = rule.category === 'slop' ? 'AI slop' : 'Quality',
|
||||
category = rule.category,
|
||||
skillHref = rule.skillSection ? `/docs/impeccable#section-${rule.skillSection.toLowerCase().replace(/\s*&\s*/g, '-').replace(/\s+/g, '-')}` : '/detector',
|
||||
linkLabel = rule.skillSection ? 'See in /impeccable' : 'Inspect the detector',
|
||||
} = Astro.props;
|
||||
|
||||
const layerLabel = layer === 'browser' ? 'Browser' : 'CLI';
|
||||
const layerTitle = layer === 'browser'
|
||||
? 'Deterministic, but requires rendered browser layout.'
|
||||
: 'Deterministic. Runs from npx impeccable detect on source files.';
|
||||
---
|
||||
|
||||
<article class="rule-card" id={`rule-${rule.id}`} data-layer={layer}>
|
||||
<div class="rule-card-visual" aria-hidden="true">
|
||||
<div class="rule-card-visual-inner" set:html={visual} />
|
||||
</div>
|
||||
<div class="rule-card-body">
|
||||
<div class="rule-card-head">
|
||||
<span class="rule-card-category" data-category={category}>{categoryLabel}</span>
|
||||
<span class="rule-card-layer" data-layer={layer} title={layerTitle}>{layerLabel}</span>
|
||||
{rule.gated && <span class="rule-card-layer" data-layer="optin" title={`Off by default. Enable with --${rule.gated}.`}>opt-in</span>}
|
||||
</div>
|
||||
<h3 class="rule-card-name">{rule.name}</h3>
|
||||
<p class="rule-card-desc">{description}</p>
|
||||
<a class="rule-card-skill-link" href={skillHref}>{linkLabel}</a>
|
||||
</div>
|
||||
</article>
|
||||
Reference in New Issue
Block a user