From c723d46ebf1f88b43f4bd48993f3c04086e85d49 Mon Sep 17 00:00:00 2001 From: msa46 Date: Sun, 16 Aug 2026 12:03:59 +0200 Subject: [PATCH] feat: compact programme selector --- astro.config.mjs | 1 + src/components/ProgrammeSwitch.astro | 16 ++++++++++++--- src/middleware.ts | 12 ------------ src/starlight-route-data.ts | 10 ++++++++++ src/styles/incognito.css | 29 +++++++++++++++++----------- tests/matomo-build.test.mjs | 28 ++++++++++++++++++++++++++- tests/programme-switch.test.mjs | 12 ++++++++++++ 7 files changed, 81 insertions(+), 27 deletions(-) delete mode 100644 src/middleware.ts create mode 100644 src/starlight-route-data.ts 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:|