mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-19 01:26:29 +03:00
Restructure narrative: Foundation, Language, Antidote, Visual Mode
Major site restructure reflecting Impeccable's expanded value prop: - 01 The Foundation: 7 design dimensions, 212 guidelines grid - 02 The Language: merged periodic table + Commands in Action - 03 The Antidote: moved from position 1, anti-patterns + gallery - 04 Visual Mode: live iframe embed of detection overlay demo - Composite demo page combining purple gradients + side-tab cards - Updated hero copy (212 guidelines, 22 commands) - 7-item sticky nav, backward-compat anchor aliases Detection overlay improvements: - Staggered entrance animation (80ms per element) - Banner slides in from top - Skip body/html from overlay targeting (fixes scrollbar bug) - Banner overflow: hidden + maxWidth: 100vw - CLAUDE.md: document that browser script is generated, never edit directly 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
4b356a6b5b
commit
03a4433dcc
@@ -1208,11 +1208,20 @@ if (IS_BROWSER) {
|
||||
// Inject hover styles via CSS (more reliable than JS event listeners)
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.textContent = `
|
||||
@keyframes impeccable-reveal {
|
||||
from { opacity: 0; outline-color: transparent; }
|
||||
to { opacity: 1; outline-color: ${OUTLINE_COLOR}; }
|
||||
}
|
||||
.impeccable-overlay:not(.impeccable-banner) {
|
||||
pointer-events: none;
|
||||
outline: 2px solid ${OUTLINE_COLOR};
|
||||
border-radius: 4px;
|
||||
transition: outline-color 0.3s ease;
|
||||
animation: impeccable-reveal 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
.impeccable-overlay.impeccable-visible {
|
||||
animation-play-state: running;
|
||||
}
|
||||
.impeccable-overlay.impeccable-hover {
|
||||
outline-color: rgba(0,0,0,0.85);
|
||||
@@ -1285,6 +1294,7 @@ if (IS_BROWSER) {
|
||||
// Uses a huge rootMargin so all *rendered* elements count as intersecting,
|
||||
// while display:none / closed <details> / hidden modals etc. do not.
|
||||
// This is event-driven -- no polling needed.
|
||||
let overlayIndex = 0;
|
||||
const visibilityObserver = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const overlay = entry.target._impeccableOverlay;
|
||||
@@ -1292,6 +1302,11 @@ if (IS_BROWSER) {
|
||||
if (entry.isIntersecting) {
|
||||
overlay.style.display = '';
|
||||
positionOverlay(overlay);
|
||||
if (!overlay._revealed) {
|
||||
overlay._revealed = true;
|
||||
overlay.style.animationDelay = `${(overlay._staggerIndex || 0) * 80}ms`;
|
||||
requestAnimationFrame(() => overlay.classList.add('impeccable-visible'));
|
||||
}
|
||||
} else {
|
||||
overlay.style.display = 'none';
|
||||
}
|
||||
@@ -1358,6 +1373,7 @@ if (IS_BROWSER) {
|
||||
|
||||
// Start hidden; the IntersectionObserver will show it once the target is rendered
|
||||
outline.style.display = 'none';
|
||||
outline._staggerIndex = overlayIndex++;
|
||||
el._impeccableOverlay = outline;
|
||||
visibilityObserver.observe(el);
|
||||
|
||||
@@ -1378,8 +1394,13 @@ if (IS_BROWSER) {
|
||||
background: LABEL_BG, color: 'white',
|
||||
fontFamily: 'system-ui, sans-serif', fontSize: '13px',
|
||||
display: 'flex', alignItems: 'center', pointerEvents: 'auto',
|
||||
height: '36px',
|
||||
height: '36px', overflow: 'hidden', maxWidth: '100vw',
|
||||
transform: 'translateY(-100%)',
|
||||
transition: 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)',
|
||||
});
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
banner.style.transform = 'translateY(0)';
|
||||
}));
|
||||
|
||||
// Scrollable findings area
|
||||
const scrollArea = document.createElement('div');
|
||||
@@ -1473,6 +1494,8 @@ if (IS_BROWSER) {
|
||||
// Skip browser extension elements (Claude, etc.)
|
||||
const elId = el.id || '';
|
||||
if (elId.startsWith('claude-') || elId.startsWith('cic-')) continue;
|
||||
// Skip html/body -- page-level findings go in the banner, not a full-page overlay
|
||||
if (el === document.body || el === document.documentElement) continue;
|
||||
|
||||
const findings = [
|
||||
...checkElementBordersDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
||||
|
||||
Reference in New Issue
Block a user