diff --git a/astro.config.mjs b/astro.config.mjs
index b1764f2..c2a79c3 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -33,6 +33,7 @@ export default defineConfig({
},
favicon: '/favicon.ico',
customCss: ['./src/styles/incognito.css'],
+ routeMiddleware: ['./src/starlight-route-data.ts'],
components: {
Sidebar: './src/components/Sidebar.astro',
},
diff --git a/src/components/ProgrammeSwitch.astro b/src/components/ProgrammeSwitch.astro
index 9c081c6..6351db9 100644
--- a/src/components/ProgrammeSwitch.astro
+++ b/src/components/ProgrammeSwitch.astro
@@ -7,9 +7,19 @@ const withBase = (path: string) => `${import.meta.env.BASE_URL.replace(/\/$/, ''
---
diff --git a/src/middleware.ts b/src/middleware.ts
deleted file mode 100644
index 478107e..0000000
--- a/src/middleware.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { defineMiddleware } from 'astro:middleware';
-import { filterResolvedSidebar } from './config/programme-navigation.mjs';
-
-export const onRequest = defineMiddleware((context, next) => {
- try {
- const route = context.locals.starlightRoute;
- route.sidebar = filterResolvedSidebar(route.sidebar, context.url.pathname);
- } catch {
- // Non-Starlight routes such as the generated 404 page have no route data.
- }
- return next();
-});
diff --git a/src/starlight-route-data.ts b/src/starlight-route-data.ts
new file mode 100644
index 0000000..97fb310
--- /dev/null
+++ b/src/starlight-route-data.ts
@@ -0,0 +1,10 @@
+import { defineRouteMiddleware } from '@astrojs/starlight/route-data';
+import { filterResolvedSidebar } from './config/programme-navigation.mjs';
+
+export const onRequest = defineRouteMiddleware((context, next) => {
+ const base = import.meta.env.BASE_URL.replace(/\/$/, '');
+ const pathname = context.url.pathname.replace(base, '');
+ const route = context.locals.starlightRoute;
+ route.sidebar = filterResolvedSidebar(route.sidebar, pathname);
+ return next();
+});
diff --git a/src/styles/incognito.css b/src/styles/incognito.css
index 03e5c0b..0527135 100644
--- a/src/styles/incognito.css
+++ b/src/styles/incognito.css
@@ -134,7 +134,7 @@
}
.programme-switch {
- padding: 0.75rem;
+ padding: 0.625rem;
margin: 0 0.5rem 0.75rem;
border: 1px solid var(--sl-color-gray-5);
border-radius: 0.6rem;
@@ -142,7 +142,7 @@
.programme-switch__label {
display: block;
- margin-bottom: 0.45rem;
+ margin-bottom: 0.4rem;
color: var(--sl-color-gray-2);
font-size: var(--sl-text-xs);
font-weight: 600;
@@ -151,25 +151,32 @@
.programme-switch__links {
display: grid;
grid-template-columns: 1fr 1fr;
- gap: 0.35rem;
+ gap: 0.2rem;
+ padding: 0.2rem;
+ border-radius: 0.45rem;
+ background: var(--sl-color-gray-6);
}
.programme-switch__links a {
display: flex;
- min-height: 2.5rem;
+ min-height: 2.25rem;
align-items: center;
justify-content: center;
- padding: 0.35rem;
- border-radius: 0.4rem;
- text-align: center;
- line-height: 1.2;
+ padding: 0.3rem 0.5rem;
+ border-radius: 0.35rem;
+ color: var(--sl-color-gray-2);
+ font-size: var(--sl-text-xs);
+ font-weight: 600;
+ line-height: 1;
+ text-decoration: none;
+ white-space: nowrap;
}
.programme-switch__links a[aria-current='page'] {
- color: var(--sl-color-text-accent);
- background: var(--sl-color-accent-low);
+ color: var(--incognito-light);
+ background: var(--incognito-primary);
font-weight: 700;
- box-shadow: inset 0 0 0 1px var(--sl-color-accent);
+ box-shadow: var(--sl-shadow-sm);
}
.programme-switch__links a:focus-visible {
diff --git a/tests/matomo-build.test.mjs b/tests/matomo-build.test.mjs
index 334893b..c294d85 100644
--- a/tests/matomo-build.test.mjs
+++ b/tests/matomo-build.test.mjs
@@ -19,7 +19,7 @@ async function collectCss(directory) {
return chunks.join('\n');
}
-test('subpath production build includes the local consent controller and its UI styles', async () => {
+test('subpath production build includes local UI assets and focused programme navigation', async () => {
const output = await mkdtemp(join(process.cwd(), '.matomo-build-'));
try {
await execFileAsync('node_modules/.bin/astro', ['build', '--outDir', output], {
@@ -40,6 +40,32 @@ test('subpath production build includes the local consent controller and its UI
assert.equal(scripts[0].hasAttribute('defer'), true);
await access(join(output, 'matomo-consent.js'));
+ const computerScienceHtml = await readFile(join(output, 'computer-science/index.html'), 'utf8');
+ const { document: computerScienceDocument } = parseHTML(computerScienceHtml);
+ const computerScienceSidebar = computerScienceDocument.querySelector('#starlight__sidebar');
+ assert.ok(computerScienceSidebar);
+ assert.match(computerScienceSidebar.textContent, /Home/);
+ assert.match(computerScienceSidebar.textContent, /Previous exams and documents/);
+ assert.match(computerScienceSidebar.textContent, /Computer Science/);
+ assert.match(computerScienceSidebar.textContent, /Useful Information/);
+ assert.doesNotMatch(computerScienceSidebar.textContent, /About Incognito/);
+ assert.doesNotMatch(computerScienceSidebar.textContent, /Data Science & AI/);
+ assert.doesNotMatch(computerScienceSidebar.textContent, /Master AI/);
+ assert.doesNotMatch(computerScienceSidebar.textContent, /Master DSDM/);
+
+ const dataScienceHtml = await readFile(join(output, 'data-science-and-ai/index.html'), 'utf8');
+ const { document: dataScienceDocument } = parseHTML(dataScienceHtml);
+ const dataScienceSidebar = dataScienceDocument.querySelector('#starlight__sidebar');
+ assert.ok(dataScienceSidebar);
+ assert.match(dataScienceSidebar.textContent, /Home/);
+ assert.match(dataScienceSidebar.textContent, /Previous exams and documents/);
+ assert.match(dataScienceSidebar.textContent, /Data Science & AI/);
+ assert.match(dataScienceSidebar.textContent, /Useful Information/);
+ assert.doesNotMatch(dataScienceSidebar.textContent, /About Incognito/);
+ assert.doesNotMatch(dataScienceSidebar.textContent, /Computer Science/);
+ assert.doesNotMatch(dataScienceSidebar.textContent, /Master AI/);
+ assert.doesNotMatch(dataScienceSidebar.textContent, /Master DSDM/);
+
const css = await collectCss(output);
assert.match(css, /#incognito-analytics-consent/);
assert.match(css, /\.incognito-consent-action/);
diff --git a/tests/programme-switch.test.mjs b/tests/programme-switch.test.mjs
index bfb6c64..0d79ae0 100644
--- a/tests/programme-switch.test.mjs
+++ b/tests/programme-switch.test.mjs
@@ -10,3 +10,15 @@ test('Sidebar override renders an accessible no-JavaScript programme switch', as
assert.doesNotMatch(component, /client:|