mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-14 15:16:35 +03:00
Adds a Manifest V3 Chrome extension that injects the detector when DevTools opens, with a dedicated panel for browsing findings, a toolbar popup for quick scan/toggle, and per-rule settings synced via chrome.storage. Categorizes anti-patterns into AI slop vs quality issues with visual differentiation (sparkle prefix, panel grouping). Overlay labels are polished with flush positioning, cycling for multi-finding elements, and synchronized hover darkening. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
2.3 KiB
JavaScript
68 lines
2.3 KiB
JavaScript
/**
|
|
* Impeccable DevTools Extension - Popup
|
|
*
|
|
* Quick controls: scan, toggle overlays, and see finding count.
|
|
*/
|
|
|
|
const countNumber = document.getElementById('count-number');
|
|
const countLabel = document.getElementById('count-label');
|
|
const btnScan = document.getElementById('btn-scan');
|
|
const btnToggle = document.getElementById('btn-toggle');
|
|
|
|
let overlaysVisible = true;
|
|
|
|
async function getActiveTabId() {
|
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
return tab?.id;
|
|
}
|
|
|
|
function updateFromState(state) {
|
|
if (!state) return;
|
|
const count = state.findings?.reduce((sum, f) => sum + f.findings.length, 0) || 0;
|
|
countNumber.textContent = String(count);
|
|
countNumber.classList.toggle('has-findings', count > 0);
|
|
countLabel.textContent = count === 1 ? 'anti-pattern' : 'anti-patterns';
|
|
overlaysVisible = state.overlaysVisible !== false;
|
|
btnToggle.textContent = overlaysVisible ? 'Hide overlays' : 'Show overlays';
|
|
}
|
|
|
|
async function loadState() {
|
|
const tabId = await getActiveTabId();
|
|
if (!tabId) return;
|
|
chrome.runtime.sendMessage({ action: 'get-state', tabId }, updateFromState);
|
|
}
|
|
|
|
// Listen for real-time updates from service worker
|
|
chrome.runtime.onMessage.addListener((msg) => {
|
|
if (msg.action === 'findings-updated') {
|
|
const count = msg.findings?.reduce((sum, f) => sum + f.findings.length, 0) || 0;
|
|
countNumber.textContent = String(count);
|
|
countNumber.classList.toggle('has-findings', count > 0);
|
|
countLabel.textContent = count === 1 ? 'anti-pattern' : 'anti-patterns';
|
|
btnScan.textContent = 'Scan page';
|
|
btnScan.disabled = false;
|
|
}
|
|
if (msg.action === 'overlays-toggled-broadcast') {
|
|
overlaysVisible = msg.visible;
|
|
btnToggle.textContent = overlaysVisible ? 'Hide overlays' : 'Show overlays';
|
|
}
|
|
});
|
|
|
|
btnScan.addEventListener('click', async () => {
|
|
const tabId = await getActiveTabId();
|
|
if (!tabId) return;
|
|
btnScan.textContent = 'Scanning...';
|
|
btnScan.disabled = true;
|
|
chrome.runtime.sendMessage({ action: 'scan', tabId });
|
|
});
|
|
|
|
btnToggle.addEventListener('click', async () => {
|
|
const tabId = await getActiveTabId();
|
|
if (!tabId) return;
|
|
chrome.runtime.sendMessage({ action: 'toggle-overlays', tabId });
|
|
overlaysVisible = !overlaysVisible;
|
|
btnToggle.textContent = overlaysVisible ? 'Hide overlays' : 'Show overlays';
|
|
});
|
|
|
|
loadState();
|