From 5c4ac8fa79d433af53d41c4c332393e7c9af9f03 Mon Sep 17 00:00:00 2001 From: Ben Thomas <2719284+comnam90@users.noreply.github.com> Date: Mon, 25 May 2026 16:05:36 +1200 Subject: [PATCH 1/2] fix(ui): add skip-to-content link and focus-visible rings for info-panel links and refresh button Completes the remaining a11y work from #79 and #80 that the mission control redesign (#103) did not cover: - Add a "Skip to map" link as the first focusable child of so keyboard users can bypass the header and jump straight to #map. - Add `.info-link:focus-visible` so the seven info-panel anchors show the same accent outline as `.ctl:focus-visible`-styled controls. - Add Tailwind focus-visible utilities to the inline "Refresh Page" button in the map-error overlay (white outline against its green background). All focus rings follow the existing house style (outline + accent token) established by the mission control redesign. Closes #79 Closes #80 --- layouts/index.html | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/layouts/index.html b/layouts/index.html index 1deb834..7ff5fbf 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -75,7 +75,28 @@ height: 100vh; height: 100dvh; } - + + .skip-link { + position: absolute; + top: -100px; + left: 8px; + z-index: 9999; + padding: 8px 14px; + background: var(--accent); + color: var(--bg); + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + font-weight: 600; + text-decoration: none; + border-radius: 6px; + transition: top 0.15s ease; + } + .skip-link:focus-visible { + top: 8px; + outline: 2px solid var(--accent); + outline-offset: 2px; + } + .map-container { flex: 1; min-height: 0; @@ -757,6 +778,11 @@ transition: border-color 0.15s, background 0.15s; } .info-link:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); } + .info-link:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + border-color: var(--accent); + } .info-link-icon { width: 16px; height: 16px; flex-shrink: 0; color: var(--text-mute); } .info-link:hover .info-link-icon { color: var(--accent); } .info-link span { flex: 1; } @@ -801,6 +827,7 @@ +
@@ -904,7 +931,7 @@

Veeam Data Cloud Service Map

Failed to Load Map

The map failed to load. Please check your internet connection and try refreshing the page.

-
From 330f1e43c0cf7925184b610418f184d732f71039 Mon Sep 17 00:00:00 2001 From: Ben Thomas <2719284+comnam90@users.noreply.github.com> Date: Mon, 25 May 2026 18:36:41 +1200 Subject: [PATCH 2/2] fix(ui): address review feedback on a11y skip link - Skip-link focus ring now uses var(--text) instead of var(--accent) so it has clear contrast against both the link's green background and the page bg in either theme (per Copilot review). - Added tabindex="-1" to #map so the skip link reliably transfers keyboard focus, not just the viewport, before Leaflet inits and in the #mapError fallback (per Copilot review). - Updated the "should be keyboard navigable" Playwright test to verify the skip link becomes the first tab stop and adjusted subsequent assertions. --- layouts/index.html | 4 ++-- tests/ui.spec.ts | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/layouts/index.html b/layouts/index.html index 7ff5fbf..1f80d60 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -93,7 +93,7 @@ } .skip-link:focus-visible { top: 8px; - outline: 2px solid var(--accent); + outline: 2px solid var(--text); outline-offset: 2px; } @@ -908,7 +908,7 @@

Veeam Data Cloud Service Map

-
+
diff --git a/tests/ui.spec.ts b/tests/ui.spec.ts index 92af2c3..06c0c88 100644 --- a/tests/ui.spec.ts +++ b/tests/ui.spec.ts @@ -788,13 +788,18 @@ test.describe('Veeam Data Cloud Services Map - UI Tests', () => { test.skip(testInfo.project.name === 'webkit' && process.platform === 'linux', 'Dynamic aria-hidden accessibility tree updates are unreliable in webkit on Linux'); test.skip(testInfo.project.name === 'Mobile Safari', 'Hardware keyboard navigation does not apply to mobile'); await page.keyboard.press('Tab'); - + + const skipLink = page.getByRole('link', { name: 'Skip to map' }); + await expect(skipLink).toBeFocused(); + + await page.keyboard.press('Tab'); + const searchInput = page.getByRole('combobox', { name: 'Search regions' }); await expect(searchInput).toBeFocused(); - + await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); - + const serviceButton = page.getByRole('button', { name: /all services/i }); await expect(serviceButton).toBeFocused();