diff --git a/src/components/SiteNavigation.vue b/src/components/SiteNavigation.vue index ad13a4a..e82e1cb 100644 --- a/src/components/SiteNavigation.vue +++ b/src/components/SiteNavigation.vue @@ -8,7 +8,7 @@ const props = defineProps<{ onSectionLinkClick: (event: MouseEvent) => void; }>(); -const compactLabels: Readonly> = { +const navigationLabels: Readonly> = { start: 'Start', profile: 'Profile', experience: 'Career', @@ -30,8 +30,7 @@ const compactLabels: Readonly> = { props.journey.activeSectionId === item.id ? 'page' : undefined " @click="props.onSectionLinkClick" - >{{ item.label }}{{ compactLabels[item.id] }}{{ navigationLabels[item.id] }} diff --git a/src/styles/layout.css b/src/styles/layout.css index a8584b2..b669b58 100644 --- a/src/styles/layout.css +++ b/src/styles/layout.css @@ -73,10 +73,6 @@ outline-offset: -3px; } -.site-navigation__compact-label { - display: none; -} - .portfolio-main { min-width: 0; padding-block: var(--space-4) var(--space-5); @@ -131,14 +127,6 @@ grid-template-columns: repeat(4, minmax(0, 1fr)); } - .site-navigation__full-label { - display: none; - } - - .site-navigation__compact-label { - display: inline; - } - .portfolio-section { scroll-margin-block-start: calc( var(--site-navigation-block-size) + var(--space-3) diff --git a/tests/browser/accessibility-keyboard.spec.ts b/tests/browser/accessibility-keyboard.spec.ts index 2fe9294..da342d6 100644 --- a/tests/browser/accessibility-keyboard.spec.ts +++ b/tests/browser/accessibility-keyboard.spec.ts @@ -194,16 +194,15 @@ test("responsive navigation exposes the exact visible label as each link's acces await page.setViewportSize({ width: 1440, height: 900 }); await page.goto(distUrl, { waitUntil: "domcontentloaded" }); - await expect(page.getByRole("link", { name: "Experience", exact: true })).toBeVisible(); - await expect(page.getByRole("link", { name: "Additional work", exact: true })).toBeVisible(); - await expect(page.getByRole("link", { name: "Career", exact: true })).toHaveCount(0); - await expect(page.getByRole("link", { name: "More work", exact: true })).toHaveCount(0); + await expect(page.getByRole("link", { name: "Career", exact: true })).toBeVisible(); + await expect(page.getByRole("link", { name: "More work", exact: true })).toBeVisible(); + await expect(page.getByRole("link", { name: "Experience", exact: true })).toHaveCount(0); + await expect(page.getByRole("link", { name: "Additional work", exact: true })).toHaveCount(0); await page.setViewportSize({ width: 320, height: 800 }); const career = page.getByRole("link", { name: "Career", exact: true }); - const moreWork = page.getByRole("link", { name: "More work", exact: true }); - await expect(career.locator(".site-navigation__compact-label")).toHaveText("Career"); - await expect(moreWork.locator(".site-navigation__compact-label")).toHaveText("More work"); + await expect(career).toHaveText("Career"); + await expect(page.getByRole("link", { name: "More work", exact: true })).toHaveText("More work"); await expect(page.getByRole("link", { name: "Experience", exact: true })).toHaveCount(0); await expect(page.getByRole("link", { name: "Additional work", exact: true })).toHaveCount(0); diff --git a/tests/browser/no-javascript.spec.ts b/tests/browser/no-javascript.spec.ts index 62f2025..90c47c0 100644 --- a/tests/browser/no-javascript.spec.ts +++ b/tests/browser/no-javascript.spec.ts @@ -25,6 +25,17 @@ const sectionHeadings = [ 'CONTACT', ] as const; +const navigationLabels: Readonly> = { + start: 'Start', + profile: 'Profile', + experience: 'Career', + infrastructure: 'Infra', + 'selected-builds': 'Builds', + 'additional-work': 'More work', + toolkit: 'Toolkit', + contact: 'Contact', +}; + const visibleTextLeafSelector = 'h1,h2,h3,p,dt,dd,li,figcaption,a,svg text'; const visibleTextSelector = [ '.site-header :is(h1,h2,h3,p,dt,dd,li,figcaption,a)', @@ -96,12 +107,7 @@ const expectedVisibleTextSegments = ( return [ content.identity.name, content.identity.role, - ...sectionIds.map((id) => { - const label = navigationById.get(id); - if (label === undefined) - throw new Error(`Missing navigation label: ${id}`); - return label; - }), + ...sectionIds.map((id) => navigationLabels[id]), ...section('start', 1, [content.identity.valueProposition]), ...section('profile', 2, [ content.profile.introduction, diff --git a/tests/unit/AppShell.test.ts b/tests/unit/AppShell.test.ts index 20f9c47..dc86892 100644 --- a/tests/unit/AppShell.test.ts +++ b/tests/unit/AppShell.test.ts @@ -57,17 +57,17 @@ describe('semantic portfolio document', () => { expect(document.body.textContent).toContain('For a current CV or role-specific information, contact me directly.'); }); - it('renders separate full and compact navigation labels without overriding their accessible names', async () => { + it('renders one semantic navigation label with no duplicate responsive text', async () => { const document = await renderedDocument(); const experience = document.querySelector('nav a[href="#experience"]')!; const additional = document.querySelector('nav a[href="#additional-work"]')!; expect(experience.hasAttribute('aria-label')).toBe(false); - expect(experience.querySelector('.site-navigation__full-label')?.textContent).toBe('Experience'); - expect(experience.querySelector('.site-navigation__compact-label')?.textContent).toBe('Career'); + expect(experience.textContent).toBe('Career'); + expect(experience.childElementCount).toBe(0); expect(additional.hasAttribute('aria-label')).toBe(false); - expect(additional.querySelector('.site-navigation__full-label')?.textContent).toBe('Additional work'); - expect(additional.querySelector('.site-navigation__compact-label')?.textContent).toBe('More work'); + expect(additional.textContent).toBe('More work'); + expect(additional.childElementCount).toBe(0); }); it('binds navigation and section labels to their canonical IDs when content navigation is reordered', async () => { @@ -91,12 +91,9 @@ describe('semantic portfolio document', () => { expect([...document.querySelectorAll('main > section > h2')].map((heading) => heading.textContent)).toEqual([ 'START', 'PROFILE', 'EXPERIENCE', 'INFRASTRUCTURE', 'SELECTED BUILDS', 'ADDITIONAL WORK', 'TOOLKIT', 'CONTACT', ]); - expect([...document.querySelectorAll('nav a')].map((link) => [ - link.getAttribute('href'), - link.querySelector('.site-navigation__full-label')?.textContent, - ])).toEqual([ - ['#start', 'Start'], ['#profile', 'Profile'], ['#experience', 'Experience'], ['#infrastructure', 'Infrastructure'], - ['#selected-builds', 'Selected builds'], ['#additional-work', 'Additional work'], ['#toolkit', 'Toolkit'], ['#contact', 'Contact'], + expect([...document.querySelectorAll('nav a')].map((link) => [link.getAttribute('href'), link.textContent])).toEqual([ + ['#start', 'Start'], ['#profile', 'Profile'], ['#experience', 'Career'], ['#infrastructure', 'Infra'], + ['#selected-builds', 'Builds'], ['#additional-work', 'More work'], ['#toolkit', 'Toolkit'], ['#contact', 'Contact'], ]); });