diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..f726236 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,38 @@ +name: Deploy Pages + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: pages-${{ github.repository }} + cancel-in-progress: true + +jobs: + deploy: + if: github.repository == 'AxeForging/inspectorbooster' + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: web + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/web/axeforge-icon.png b/web/axeforge-icon.png new file mode 100644 index 0000000..da16248 Binary files /dev/null and b/web/axeforge-icon.png differ diff --git a/web/axeforge.css b/web/axeforge.css new file mode 100644 index 0000000..2c8b958 --- /dev/null +++ b/web/axeforge.css @@ -0,0 +1,242 @@ +/* ============================================================ + AxeForge Brand Kit v1 — https://tools.axeforge.io + Copy this file into your project. See BRAND.md for the spec. + + Works two ways from this one file: + - Tailwind v4: `@import "tailwindcss"; @import "./axeforge.css";` + (the @theme inline block maps tokens to axe-* utilities) + - Plain CSS / no Tailwind: just link it; browsers ignore @theme. + + Flavors (set on ): forge (default) | circuit | flux | relay | signal + Theme (set on ): dark (default, omit) | light — data-theme="light" + ============================================================ */ + +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=optional'); +/* display=optional (not swap): the browser decides once at layout time and + never swaps mid-session — kills the web-font-swap layout shift. Trade-off: + on a slow first load a visitor may get the fallback font for that session + instead of Inter/JetBrains Mono, since it never swaps in later. */ + +/* ---- Shell tokens: identical in every flavor except relay. Never override + otherwise -- relay's neutral-gray shell is a deliberate, one-time exception + (see the "new flavor discussion" note below), not a precedent for others. ---- */ +:root { + color-scheme: dark; + + --af-bg: #05070a; + --af-surface: #0a0f1a; + --af-surface-2: #0d1117; /* terminal body */ + --af-surface-3: #161b22; /* terminal header */ + --af-line: #1a2233; + --af-text: #ffffff; + --af-text-muted: #94a3b8; + + --af-font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + --af-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace; + + --af-radius: 0.5rem; + --af-radius-lg: 1rem; + + /* ---- Flavor tokens: the ONLY vars a flavor changes. Default = forge. ---- */ + --af-accent: #ff4e00; + --af-accent-hover: #e64600; + --af-accent-contrast: #ffffff; /* text placed ON the accent; white passes only on forge, bold/large */ +} + +[data-flavor="circuit"] { + --af-accent: #22d3ee; + --af-accent-hover: #06b6d4; + --af-accent-contrast: #05070a; +} + +[data-flavor="flux"] { + --af-accent: #a78bfa; + --af-accent-hover: #8b5cf6; + --af-accent-contrast: #05070a; +} + +/* relay: the one flavor that also overrides shell tokens (bg/surface/-2/-3/line), + not just the 3 accent vars -- "external tools/hardware/products" (Heyra, rsvp-m5, + ReplayRaccoon), inheriting ReplayRaccoon's neutral-gray shell instead of the + default blue-black. This is the "new flavor discussion" the Do/Don't section + below refers to, made real -- a deliberate one-time exception, not a precedent. */ +[data-flavor="relay"] { + --af-bg: #0a0a0a; + --af-surface: #1a1a1a; + --af-surface-2: #161616; /* terminal body */ + --af-surface-3: #202020; /* terminal header */ + --af-line: #2a2a2a; + + --af-accent: #ff6b00; + --af-accent-hover: #e56000; + --af-accent-contrast: #05070a; +} + +[data-flavor="signal"] { + --af-accent: #ffb000; + --af-accent-hover: #e69e00; + --af-accent-contrast: #05070a; +} + +/* ---- Light theme: opt-in via data-theme="light" on , alongside + data-flavor. Omit data-theme for dark (the default) — existing tools + that never set it are unaffected. Every accent below is the SAME hue as + its dark-mode counterpart, darkened only as far as needed to clear + 4.5:1 against the light shell bg (computed, not eyeballed) — verified + >=4.5:1 as button-fill-with-white-text at any size too, so light mode + drops dark mode's forge-only "bold/large" caveat entirely. + + --af-surface-2/-3 (terminal body/header) are deliberately NOT overridden + here: the terminal stays a dark console on a light page — a common + convention (docs sites, code blocks) that also sidesteps re-deriving + accent-as-text contrast for a component that's a fixed dark box in + every flavor already. ---- */ +[data-theme="light"] { + color-scheme: light; + --af-bg: #f7f8fa; + --af-surface: #ffffff; + --af-line: #dde1e6; + --af-text: #0a0f1a; + --af-text-muted: #475569; /* 7.13:1 on --af-bg */ +} + +[data-theme="light"][data-flavor="forge"] { + --af-accent: #cf3f00; /* 4.54:1 on --af-bg, 4.81:1 vs white button text */ + --af-accent-hover: #b63700; + --af-accent-contrast: #ffffff; +} + +[data-theme="light"][data-flavor="circuit"] { + --af-accent: #0b7c8d; /* 4.60:1 on --af-bg, 4.90:1 vs white button text */ + --af-accent-hover: #0a6d7c; + --af-accent-contrast: #ffffff; +} + +[data-theme="light"][data-flavor="flux"] { + --af-accent: #7a4ff7; /* 4.60:1 on --af-bg, 4.90:1 vs white button text */ + --af-accent-hover: #5e2af5; + --af-accent-contrast: #ffffff; +} + +/* relay-light: the neutral-gray shell exception carried into light mode too + — same reasoning as dark relay (matches ReplayRaccoon's own neutral + palette rather than the kit's blue-tinted default), so relay reads as + one consistent identity across both themes instead of only diverging + from the pack in dark mode. */ +[data-theme="light"][data-flavor="relay"] { + --af-bg: #f5f5f5; + --af-line: #e2e2e2; + --af-text: #0a0a0a; + --af-text-muted: #525252; /* 7.17:1 on --af-bg */ + --af-accent: #ba4e00; /* 4.61:1 on --af-bg, 6.12:1 hover vs white button text */ + --af-accent-hover: #a44500; + --af-accent-contrast: #ffffff; +} + +[data-theme="light"][data-flavor="signal"] { + --af-accent: #966800; /* 4.62:1 on --af-bg, 4.91:1 vs white button text */ + --af-accent-hover: #845c00; + --af-accent-contrast: #ffffff; +} + +/* ---- Tailwind v4 adapter. Inert (ignored at-rule) without Tailwind. + Must be `inline`: utilities then emit var(--af-*) directly, so a + [data-flavor] override below :root still wins. Plain @theme would + resolve the var() once at :root and pin every flavor to forge. ---- */ +@theme inline { + --font-sans: var(--af-font-sans); + --font-mono: var(--af-font-mono); + + --color-axe-black: var(--af-bg); + --color-axe-navy: var(--af-surface); + --color-axe-line: var(--af-line); + --color-axe-muted: var(--af-text-muted); + --color-axe-accent: var(--af-accent); + --color-axe-accent-hover: var(--af-accent-hover); + --color-axe-accent-contrast: var(--af-accent-contrast); + + /* deprecated — old hub names; use axe-accent / axe-accent-hover */ + --color-axe-orange: var(--af-accent); + --color-axe-orange-hover: var(--af-accent-hover); +} + +/* ---- Base ---- */ +body { + background: var(--af-bg); + color: var(--af-text); + font-family: var(--af-font-sans); + -webkit-font-smoothing: antialiased; +} + +:focus-visible { + outline: 2px solid var(--af-accent); + outline-offset: 2px; +} + +/* ---- Components (vanilla CSS — no Tailwind required) ---- */ + +.technical-grid { + background-size: 80px 80px; + background-image: radial-gradient(circle, var(--af-line) 1px, transparent 1px); +} + +.glass-card { + background: color-mix(in srgb, var(--af-surface) 60%, transparent); + -webkit-backdrop-filter: blur(24px); + backdrop-filter: blur(24px); + border: 1px solid var(--af-line); + border-radius: var(--af-radius-lg); + transition: border-color 0.5s ease, box-shadow 0.5s ease; +} +.glass-card:hover { + border-color: color-mix(in srgb, var(--af-accent) 50%, transparent); +} + +.terminal-window { + background: var(--af-surface-2); + border: 1px solid var(--af-line); + border-radius: var(--af-radius); + overflow: hidden; + font-family: var(--af-font-mono); + font-size: 0.75rem; + line-height: 1.5; + box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5); +} +.terminal-header { + background: var(--af-surface-3); + padding: 0.5rem 1rem; + display: flex; + align-items: center; + gap: 0.5rem; + border-bottom: 1px solid var(--af-line); +} + +/* macOS traffic lights — semantic, not brand; fixed hexes on purpose */ +.dot { width: 10px; height: 10px; border-radius: 9999px; } +.dot-red { background: #ff5f56; } +.dot-yellow { background: #ffbd2e; } +.dot-green { background: #27c93f; } + +.glow-accent, +.glow-orange /* deprecated alias */ { + box-shadow: 0 0 20px color-mix(in srgb, var(--af-accent) 15%, transparent); +} + +.axe-button { + display: inline-flex; + align-items: center; + gap: 0.5rem; + background: var(--af-accent); + color: var(--af-accent-contrast); /* never hardcode white — fails on circuit/flux/signal */ + padding: 0.75rem 1.5rem; + border: 0; + border-radius: var(--af-radius); + font-family: var(--af-font-sans); + font-size: 1.25rem; /* WCAG "large text" floor (18.66px+ bold) — forge's white-on-accent (3.31:1) only clears AA at large-text's 3:1, not body text's 4.5:1 */ + font-weight: 700; + cursor: pointer; + text-decoration: none; + transition: background 0.15s ease, transform 0.15s ease; +} +.axe-button:hover { background: var(--af-accent-hover); } +.axe-button:active { transform: scale(0.95); } diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..51e1c34 Binary files /dev/null and b/web/favicon.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..738df00 --- /dev/null +++ b/web/index.html @@ -0,0 +1,445 @@ + + + + + +InspectorBooster — ultra CSS/XPath inspector for QA engineers + + + + + + + + + + + + + + + + +
+
+ + + AxeForge/inspectorbooster + + +
+
+ +
+
+
+
Chrome extension for QA engineers
+

Stop guessing at CSS selectors.

+

+ Open the side panel, hover any element, and InspectorBooster ranks every + selector strategy it can find — testid, id, role, aria-label, + placeholder, class, CSS path, XPath, text — each scored 0-100 by + stability and uniqueness. Organize what you find into scopes and + aliases, record whole interaction flows, and export straight to + Playwright or Cypress. +

+ +
+ +
+
Live demo (simulated output, not a real page)
+
+
+ + inspect: <button data-testid="login-btn"> +
+
+
+
+
+
+ +
+
+
+
How it works
+

One inspection, every selector strategy

+

The content script generates all viable selectors for the element under your cursor, scores each one, and hands you the ranked list — not just the first one that happens to match.

+
+
+
+

Smart selector engine

+

Generates testid, id, role, aria-label, placeholder, class, CSS path, XPath, and text selectors for every element, each scored 0-100 by stability and uniqueness.

+
+
+

Missing testid tip

+

Flags elements that lack a data-testid attribute so flaky selectors get caught before they ship into a test suite.

+
+
+

Scopes and aliases

+

Organize elements into named, nestable scopes (Login Page, Header, Product List) and give them human-readable aliases, searchable by name, description, or tag.

+
+
+

Interaction recording

+

Captures clicks, inputs, keypresses, and navigation with full ranked selector options per step, then exports the whole flow as a test script.

+
+
+
+
+ +
+
+
+
Selector engine
+

Ranked by stability, not by luck

+

Every strategy gets a score for a unique match and a lower score for a non-unique one, so the panel can auto-select your preferred type on every click.

+
+
+ + + + + + + + + + + + +
StrategyTypeScore (unique/non-unique)Example
data-testidtestid98 / 78[data-testid="login-btn"]
#idid92 / 52#login-btn
Role + namerole88 / 65role=button[name="Sign In"]
aria-labelaria83 / 56button[aria-label="Close"]
placeholderplaceholder75 / 55input[placeholder="Search..."]
Class chaincss72 / 30-65button.btn.btn-primary
CSS pathcss62 / 35#login-form > div > button
Partial classcss58 / 38[class*="product-card"]
Text (exact)text44//button[normalize-space(.)="Sign In"]
Absolute XPathxpath28//html/body/div[1]/form/button[1]
+
+
+
+ +
+
+
+
Workflow
+

Four views, one panel

+
+
+
+
01
+

Inspect

+

Hover any element from the side panel to see its ranked selector options. Switch RAW / Playwright / Cypress display mode globally, and copy the formatted string ready to paste into test code.

+
+
+
02
+

Library

+

Save elements into scopes and give them aliases. Set a scope container selector and framework exports chain through it automatically: page.locator('[data-testid="card"]').getByTestId('buy-btn').

+
+
+
03
+

Record

+

Capture clicks, inputs, keypresses, and navigation with a live feed while recording. Rename, exclude, or swap the active selector on any step afterward.

+
+
+
04
+

Export

+

Six formats: JSON and YAML (scoped or flat map), plus Playwright .spec.ts and Cypress .cy.js. Preview before download, or paste JSON/YAML back in to import.

+
+
+
+
+ +
+
+
+
Use cases
+

Why QA engineers reach for InspectorBooster

+
+
+
+

"This selector will break on the next deploy"

+

Skip the class-name guesswork — the panel ranks the stable options first and warns when an element has no data-testid at all.

+
+
+

Writing a Playwright suite

+

Switch the display mode to PW and every copy is already formatted, from a simple click target to a full role query.

+ page.getByRole('button', { name: 'Sign In' }) +
+
+

Recording a login flow

+

Click through the flow once with recording on, then export the whole interaction straight to a Playwright spec.

+ login-flow.spec.ts +
+
+

Scoping a repeated component

+

Give a product card scope its own container selector, and every element inside exports chained through it — no duplicated boilerplate.

+ cy.get('[data-testid="card"]').find('[data-testid="buy-btn"]') +
+
+
+
+ +
+
+
+
Install
+

Load it as an unpacked extension

+
+
+
+ +
+

Build the extension

+
cd extension && npm install && npm run build
+
+
+
+ +

Open chrome://extensions and enable Developer mode

+
+
+ +

Load unpacked — select extension/dist/

+
+
+ +

Open the side panel — click the extension icon, or open it from the panel button

+
+
+ Full instructions on GitHub +
+
+ + + + + + diff --git a/web/robots.txt b/web/robots.txt new file mode 100644 index 0000000..952cbc9 --- /dev/null +++ b/web/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://axeforging.github.io/inspectorbooster/sitemap.xml diff --git a/web/sitemap.xml b/web/sitemap.xml new file mode 100644 index 0000000..cc3503f --- /dev/null +++ b/web/sitemap.xml @@ -0,0 +1,8 @@ + + + + https://axeforging.github.io/inspectorbooster/ + monthly + 1.0 + +