feat(voyage): build A11Y-panel from DS-primitives (greenfield)
This commit is contained in:
parent
df0e7837af
commit
b70b480d0d
2 changed files with 113 additions and 1 deletions
|
|
@ -883,10 +883,51 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<!-- v4.3 Step 22 — A11Y-panel built from DS primitives (greenfield).
|
||||
Empty placeholder until Wave 7 axe-core spec populates it via
|
||||
window.__voyage hooks (Step 23). Severity counters use key-stats
|
||||
severity modifiers (critical/high/medium/low) mapping axe-core's
|
||||
critical/serious/moderate/minor enum. -->
|
||||
<aside
|
||||
id="voyage-a11y-panel"
|
||||
class="guide-panel guide-panel--info"
|
||||
role="complementary"
|
||||
aria-label="A11Y-rapport (axe-core)"
|
||||
hidden
|
||||
>
|
||||
<div class="guide-panel__title">A11Y-rapport</div>
|
||||
<div class="guide-panel__body">
|
||||
<div class="key-stats" role="group" aria-label="Axe-core severity-summary">
|
||||
<div class="key-stat key-stat--critical">
|
||||
<div class="key-stat__value" data-a11y-stat="critical">0</div>
|
||||
<div class="key-stat__label">Critical</div>
|
||||
</div>
|
||||
<div class="key-stat key-stat--high">
|
||||
<div class="key-stat__value" data-a11y-stat="serious">0</div>
|
||||
<div class="key-stat__label">Serious</div>
|
||||
</div>
|
||||
<div class="key-stat key-stat--medium">
|
||||
<div class="key-stat__value" data-a11y-stat="moderate">0</div>
|
||||
<div class="key-stat__label">Moderate</div>
|
||||
</div>
|
||||
<div class="key-stat key-stat--low">
|
||||
<div class="key-stat__value" data-a11y-stat="minor">0</div>
|
||||
<div class="key-stat__label">Minor</div>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="findings__items" id="voyage-a11y-findings" aria-label="Axe-violations">
|
||||
<li class="findings__item" aria-disabled="true">
|
||||
<span class="findings__item-title">Kjør axe-spec for å fylle.</span>
|
||||
<span class="findings__item-meta">tests/e2e/voyage-playground-a11y.spec.mjs (Wave 7)</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- v4.3 Step 14 — Project dashboard mount slot. Hidden until
|
||||
loadProjectDirectory completes; renderDashboard fills with a
|
||||
fleet-grid of fleet-tiles (one per artifact: brief / plan /
|
||||
review / research / progress) plus status vocabulary badges. -->
|
||||
review / progress) plus status vocabulary badges. -->
|
||||
<section id="voyage-dashboard" class="voyage-dashboard__page" aria-label="Project dashboard" hidden></section>
|
||||
|
||||
<!-- v4.3 Step 15 — Artifact-detail mount slot. Hidden until a
|
||||
|
|
@ -1248,6 +1289,10 @@ playground first-run shows a complete round-trip-able artifact.
|
|||
'<div class="app-header__spacer"></div>' +
|
||||
'<div class="app-header__actions" role="group" aria-label="Hovednavigasjon">' +
|
||||
'<button type="button" class="btn btn--primary" data-action="open-project-picker">Velg prosjektmappe</button>' +
|
||||
// v4.3 Step 22 — A11Y panel toggle. Greenfield component built from
|
||||
// DS-primitives (guide-panel--info + key-stats + findings__item).
|
||||
// Initial state: empty placeholder; Wave 7 axe-spec populates it.
|
||||
'<button type="button" class="btn btn--ghost" data-action="toggle-a11y-panel" aria-controls="voyage-a11y-panel" aria-expanded="false" aria-label="Vis/skjul A11Y-rapport">A11Y</button>' +
|
||||
'<button type="button" class="theme-toggle" data-action="toggle-theme" aria-label="Bytt tema">' +
|
||||
'<span data-theme-label aria-hidden="true">☀</span>' +
|
||||
'</button>' +
|
||||
|
|
@ -2674,6 +2719,9 @@ playground first-run shows a complete round-trip-able artifact.
|
|||
// data-theme + colorScheme, persists to localStorage('voyage-theme').
|
||||
wireThemeToggle();
|
||||
|
||||
// Step 22 (v4.3) — A11Y-panel toggle (delegated data-action handler).
|
||||
wireA11yToggle();
|
||||
|
||||
// Step 8 (v4.3) — initial topbar render with single-crumb (voyage root).
|
||||
// renderDashboard / drill-down (Wave 3) re-renders with deeper crumbs.
|
||||
renderTopbar([{ label: 'Hjem' }]);
|
||||
|
|
@ -2758,6 +2806,25 @@ playground first-run shows a complete round-trip-able artifact.
|
|||
if (lbl) lbl.textContent = theme === 'light' ? '☾' : '☀';
|
||||
}
|
||||
|
||||
// v4.3 Step 22 — A11Y-panel toggle. Click on data-action="toggle-a11y-panel"
|
||||
// toggles the hidden attribute on #voyage-a11y-panel and updates aria-expanded
|
||||
// on the toggle button. Panel is empty placeholder until Wave 7 axe-core
|
||||
// spec calls window.__voyage.scheduleRender({ a11yViolations }) to populate.
|
||||
function wireA11yToggle() {
|
||||
document.addEventListener('click', function (e) {
|
||||
var btn = e.target && e.target.closest && e.target.closest('[data-action="toggle-a11y-panel"]');
|
||||
if (!btn) return;
|
||||
var panel = document.getElementById('voyage-a11y-panel');
|
||||
if (!panel) return;
|
||||
var willOpen = panel.hidden;
|
||||
panel.hidden = !willOpen;
|
||||
btn.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
|
||||
if (typeof announce === 'function') {
|
||||
announce(willOpen ? 'A11Y-rapport vist.' : 'A11Y-rapport skjult.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function wireThemeToggle() {
|
||||
var initial = document.documentElement.getAttribute('data-theme') || 'dark';
|
||||
setThemeLabel(initial);
|
||||
|
|
|
|||
|
|
@ -337,3 +337,48 @@ test('voyage-playground.html setActiveAnchor toggles data-active on badges (v4.3
|
|||
// injectAnchorBadges must propagate resolved state to badge data-resolved
|
||||
assert.match(text, /setAttribute\('data-resolved',\s*'true'\)/, 'data-resolved set on resolved badge required');
|
||||
});
|
||||
|
||||
// v4.3 Step 22 — A11Y-panel built from DS-primitives (greenfield)
|
||||
test('voyage-playground.html declares voyage-a11y-panel with guide-panel--info (v4.3 Step 22)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
assert.match(text, /id="voyage-a11y-panel"[^>]*guide-panel guide-panel--info/, 'voyage-a11y-panel with guide-panel--info required');
|
||||
// Must be hidden by default (placeholder until Wave 7)
|
||||
assert.match(text, /id="voyage-a11y-panel"[\s\S]{0,300}\bhidden\b/, 'voyage-a11y-panel hidden by default required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html declares data-action="toggle-a11y-panel" toggle-button (v4.3 Step 22)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
assert.match(text, /data-action="toggle-a11y-panel"/, 'toggle-a11y-panel button required');
|
||||
// aria-controls must point at the panel id
|
||||
assert.match(text, /data-action="toggle-a11y-panel"[\s\S]*?aria-controls="voyage-a11y-panel"/, 'aria-controls binding required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html A11Y-panel uses key-stats severity grid (v4.3 Step 22)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
// key-stats grid with critical/high/medium/low severity modifiers
|
||||
assert.match(text, /class="key-stat key-stat--critical"/, 'key-stat--critical required');
|
||||
assert.match(text, /class="key-stat key-stat--high"/, 'key-stat--high (serious) required');
|
||||
assert.match(text, /class="key-stat key-stat--medium"/, 'key-stat--medium (moderate) required');
|
||||
assert.match(text, /class="key-stat key-stat--low"/, 'key-stat--low (minor) required');
|
||||
// axe-core severity vocabulary on data-a11y-stat
|
||||
assert.match(text, /data-a11y-stat="critical"/, 'data-a11y-stat="critical" required');
|
||||
assert.match(text, /data-a11y-stat="serious"/, 'data-a11y-stat="serious" required');
|
||||
assert.match(text, /data-a11y-stat="moderate"/, 'data-a11y-stat="moderate" required');
|
||||
assert.match(text, /data-a11y-stat="minor"/, 'data-a11y-stat="minor" required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html A11Y-panel uses findings__items placeholder list (v4.3 Step 22)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
// Match either attribute order (class= or id= first); just confirm both live on the same <ol>.
|
||||
assert.match(text, /<ol[^>]*class="findings__items"[^>]*id="voyage-a11y-findings"|<ol[^>]*id="voyage-a11y-findings"[^>]*class="findings__items"/, 'findings__items list (id=voyage-a11y-findings) required');
|
||||
// Placeholder line referencing the Wave 7 Playwright spec
|
||||
assert.match(text, /Kjør axe-spec/, 'placeholder hint "Kjør axe-spec" required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html declares wireA11yToggle JS function (v4.3 Step 22)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
assert.match(text, /function\s+wireA11yToggle\s*\(\s*\)/, 'wireA11yToggle() function required');
|
||||
// Toggle must flip hidden + aria-expanded
|
||||
assert.match(text, /panel\.hidden\s*=\s*!willOpen/, 'panel.hidden toggle required');
|
||||
assert.match(text, /setAttribute\('aria-expanded'/, 'aria-expanded update required');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue