From a0e9d2c042d0adbefd609b6c3a4488227f81c6cd Mon Sep 17 00:00:00 2001 From: msa46 Date: Sun, 16 Aug 2026 11:57:16 +0200 Subject: [PATCH] feat: focus programme sidebar navigation --- src/config/programme-navigation.mjs | 29 ++++++++----- tests/programme-navigation.test.mjs | 63 +++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/config/programme-navigation.mjs b/src/config/programme-navigation.mjs index ac9686e..d254a78 100644 --- a/src/config/programme-navigation.mjs +++ b/src/config/programme-navigation.mjs @@ -25,6 +25,7 @@ const computerScience = { }; const compact = { label: 'Bachelor programmes', items: [{ slug: 'computer-science' }, { slug: 'data-science-and-ai' }] }; +const programmeSharedLabels = new Set(['Home', 'Previous exams and documents', 'Useful Information']); export function programmeForPathname(pathname) { if (pathname.startsWith('/computer-science')) return 'computer-science'; @@ -47,20 +48,30 @@ export function programmeSwitchTargets(pathname) { export function sidebarForPathname(pathname) { const programme = programmeForPathname(pathname); - const withoutProgrammes = sidebar.filter(({ label }) => label !== 'Computer Science' && label !== 'Data Science & AI'); const dataScience = sidebar.find(({ label }) => label === 'Data Science & AI'); - const undergraduate = programme === 'computer-science' ? computerScience : programme === 'data-science-and-ai' ? dataScience : compact; - return [...withoutProgrammes.slice(0, 3), undergraduate, ...withoutProgrammes.slice(3)]; + + if (programme) { + const undergraduate = programme === 'computer-science' ? computerScience : dataScience; + const home = sidebar.find(({ label }) => label === 'Home'); + const previousExams = sidebar.find(({ slug }) => slug === 'previous-exams-and-documents'); + const usefulInformation = sidebar.find(({ label }) => label === 'Useful Information'); + return [home, previousExams, undergraduate, usefulInformation]; + } + + const withoutProgrammes = sidebar.filter(({ label }) => label !== 'Computer Science' && label !== 'Data Science & AI'); + return [...withoutProgrammes.slice(0, 3), compact, ...withoutProgrammes.slice(3)]; } export function filterResolvedSidebar(entries, pathname) { const programme = programmeForPathname(pathname); - return entries.filter((entry) => { - if (entry.label === 'Computer Science') return programme !== 'data-science-and-ai'; - if (entry.label === 'Data Science & AI') return programme !== 'computer-science'; - return true; - }).map((entry) => { - if (!programme && (entry.label === 'Computer Science' || entry.label === 'Data Science & AI') && 'entries' in entry) { + + if (programme) { + const activeLabel = programme === 'computer-science' ? 'Computer Science' : 'Data Science & AI'; + return entries.filter(({ label }) => programmeSharedLabels.has(label) || label === activeLabel); + } + + return entries.map((entry) => { + if ((entry.label === 'Computer Science' || entry.label === 'Data Science & AI') && 'entries' in entry) { return { ...entry, entries: entry.entries.slice(0, 1) }; } return entry; diff --git a/tests/programme-navigation.test.mjs b/tests/programme-navigation.test.mjs index 2b3dc4e..31e07b3 100644 --- a/tests/programme-navigation.test.mjs +++ b/tests/programme-navigation.test.mjs @@ -1,17 +1,64 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { programmeForPathname, programmeSwitchTargets, sidebarForPathname } from '../src/config/programme-navigation.mjs'; +import { filterResolvedSidebar, programmeForPathname, programmeSwitchTargets, sidebarForPathname } from '../src/config/programme-navigation.mjs'; -test('programme routes select the matching sidebar while retaining global groups', () => { +test('programme routes identify the active bachelor programme', () => { assert.equal(programmeForPathname('/computer-science/year-1/'), 'computer-science'); assert.equal(programmeForPathname('/data-science-and-ai/year-2/'), 'data-science-and-ai'); assert.equal(programmeForPathname('/useful-information/'), null); - for (const path of ['/computer-science/', '/data-science-and-ai/', '/useful-information/']) { - const text = JSON.stringify(sidebarForPathname(path)); - assert.match(text, /Useful Information/); - assert.match(text, /Master AI/); - assert.match(text, /previous-exams-and-documents/); - } +}); + +test('programme routes retain only the selected curriculum and shared destinations', () => { + const computerScience = JSON.stringify(sidebarForPathname('/computer-science/year-1/')); + assert.match(computerScience, /"label":"Home"/); + assert.match(computerScience, /previous-exams-and-documents/); + assert.match(computerScience, /"label":"Computer Science"/); + assert.match(computerScience, /"label":"Useful Information"/); + assert.doesNotMatch(computerScience, /"label":"Data Science & AI"/); + assert.doesNotMatch(computerScience, /"label":"About Incognito"/); + assert.doesNotMatch(computerScience, /"label":"Master AI"/); + assert.doesNotMatch(computerScience, /"label":"Master DSDM"/); + + const dataScience = JSON.stringify(sidebarForPathname('/data-science-and-ai/year-2/')); + assert.match(dataScience, /"label":"Home"/); + assert.match(dataScience, /previous-exams-and-documents/); + assert.match(dataScience, /"label":"Data Science & AI"/); + assert.match(dataScience, /"label":"Useful Information"/); + assert.doesNotMatch(dataScience, /"label":"Computer Science"/); + assert.doesNotMatch(dataScience, /"label":"About Incognito"/); + assert.doesNotMatch(dataScience, /"label":"Master AI"/); + assert.doesNotMatch(dataScience, /"label":"Master DSDM"/); +}); + +test('global routes retain the existing global navigation', () => { + const global = JSON.stringify(sidebarForPathname('/useful-information/')); + assert.match(global, /"label":"About Incognito"/); + assert.match(global, /"label":"Master AI"/); + assert.match(global, /"label":"Master DSDM"/); + assert.match(global, /"label":"Bachelor programmes"/); +}); + +test('resolved programme sidebars use the same focused groups', () => { + const entries = [ + { label: 'Home' }, + { label: 'About Incognito' }, + { label: 'Previous exams and documents' }, + { label: 'Computer Science' }, + { label: 'Data Science & AI' }, + { label: 'Master AI' }, + { label: 'Master DSDM' }, + { label: 'Useful Information' }, + ]; + + assert.deepEqual( + filterResolvedSidebar(entries, '/computer-science/').map(({ label }) => label), + ['Home', 'Previous exams and documents', 'Computer Science', 'Useful Information'], + ); + assert.deepEqual( + filterResolvedSidebar(entries, '/data-science-and-ai/').map(({ label }) => label), + ['Home', 'Previous exams and documents', 'Data Science & AI', 'Useful Information'], + ); + assert.deepEqual(filterResolvedSidebar(entries, '/useful-information/'), entries); }); test('shared course switches to its paired programme route', () => {