feat: compact programme selector
This commit is contained in:
parent
a0e9d2c042
commit
c723d46ebf
7 changed files with 81 additions and 27 deletions
|
|
@ -33,6 +33,7 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
favicon: '/favicon.ico',
|
favicon: '/favicon.ico',
|
||||||
customCss: ['./src/styles/incognito.css'],
|
customCss: ['./src/styles/incognito.css'],
|
||||||
|
routeMiddleware: ['./src/starlight-route-data.ts'],
|
||||||
components: {
|
components: {
|
||||||
Sidebar: './src/components/Sidebar.astro',
|
Sidebar: './src/components/Sidebar.astro',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,19 @@ const withBase = (path: string) => `${import.meta.env.BASE_URL.replace(/\/$/, ''
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav class="programme-switch" aria-label="Bachelor programme">
|
<nav class="programme-switch" aria-label="Bachelor programme">
|
||||||
<span class="programme-switch__label">Course information</span>
|
<span class="programme-switch__label">Bachelor programme</span>
|
||||||
<div class="programme-switch__links">
|
<div class="programme-switch__links">
|
||||||
<a href={withBase(targets.dataScience)} aria-current={active === 'data-science-and-ai' ? 'page' : undefined}>Data Science & AI</a>
|
<a
|
||||||
<a href={withBase(targets.computerScience)} aria-current={active === 'computer-science' ? 'page' : undefined}>Computer Science</a>
|
href={withBase(targets.dataScience)}
|
||||||
|
aria-label="Data Science & AI"
|
||||||
|
title="Data Science & AI"
|
||||||
|
aria-current={active === 'data-science-and-ai' ? 'page' : undefined}
|
||||||
|
>DSAI</a>
|
||||||
|
<a
|
||||||
|
href={withBase(targets.computerScience)}
|
||||||
|
aria-label="Computer Science"
|
||||||
|
title="Computer Science"
|
||||||
|
aria-current={active === 'computer-science' ? 'page' : undefined}
|
||||||
|
>CS</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
});
|
|
||||||
10
src/starlight-route-data.ts
Normal file
10
src/starlight-route-data.ts
Normal file
|
|
@ -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();
|
||||||
|
});
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.programme-switch {
|
.programme-switch {
|
||||||
padding: 0.75rem;
|
padding: 0.625rem;
|
||||||
margin: 0 0.5rem 0.75rem;
|
margin: 0 0.5rem 0.75rem;
|
||||||
border: 1px solid var(--sl-color-gray-5);
|
border: 1px solid var(--sl-color-gray-5);
|
||||||
border-radius: 0.6rem;
|
border-radius: 0.6rem;
|
||||||
|
|
@ -142,7 +142,7 @@
|
||||||
|
|
||||||
.programme-switch__label {
|
.programme-switch__label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 0.45rem;
|
margin-bottom: 0.4rem;
|
||||||
color: var(--sl-color-gray-2);
|
color: var(--sl-color-gray-2);
|
||||||
font-size: var(--sl-text-xs);
|
font-size: var(--sl-text-xs);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
@ -151,25 +151,32 @@
|
||||||
.programme-switch__links {
|
.programme-switch__links {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
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 {
|
.programme-switch__links a {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 2.5rem;
|
min-height: 2.25rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0.35rem;
|
padding: 0.3rem 0.5rem;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.35rem;
|
||||||
text-align: center;
|
color: var(--sl-color-gray-2);
|
||||||
line-height: 1.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'] {
|
.programme-switch__links a[aria-current='page'] {
|
||||||
color: var(--sl-color-text-accent);
|
color: var(--incognito-light);
|
||||||
background: var(--sl-color-accent-low);
|
background: var(--incognito-primary);
|
||||||
font-weight: 700;
|
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 {
|
.programme-switch__links a:focus-visible {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ async function collectCss(directory) {
|
||||||
return chunks.join('\n');
|
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-'));
|
const output = await mkdtemp(join(process.cwd(), '.matomo-build-'));
|
||||||
try {
|
try {
|
||||||
await execFileAsync('node_modules/.bin/astro', ['build', '--outDir', output], {
|
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);
|
assert.equal(scripts[0].hasAttribute('defer'), true);
|
||||||
await access(join(output, 'matomo-consent.js'));
|
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);
|
const css = await collectCss(output);
|
||||||
assert.match(css, /#incognito-analytics-consent/);
|
assert.match(css, /#incognito-analytics-consent/);
|
||||||
assert.match(css, /\.incognito-consent-action/);
|
assert.match(css, /\.incognito-consent-action/);
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,15 @@ test('Sidebar override renders an accessible no-JavaScript programme switch', as
|
||||||
assert.doesNotMatch(component, /client:|<script/);
|
assert.doesNotMatch(component, /client:|<script/);
|
||||||
assert.match(wrapper, /@astrojs\/starlight\/components\/Sidebar\.astro/);
|
assert.match(wrapper, /@astrojs\/starlight\/components\/Sidebar\.astro/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('programme switch uses compact visible labels with full accessible names', async () => {
|
||||||
|
const component = await readFile('src/components/ProgrammeSwitch.astro', 'utf8');
|
||||||
|
assert.match(component, />DSAI<\/a>/);
|
||||||
|
assert.match(component, />CS<\/a>/);
|
||||||
|
assert.match(component, /aria-label="Data Science & AI"/);
|
||||||
|
assert.match(component, /aria-label="Computer Science"/);
|
||||||
|
assert.match(component, /title="Data Science & AI"/);
|
||||||
|
assert.match(component, /title="Computer Science"/);
|
||||||
|
assert.match(component, />Bachelor programme<\/span>/);
|
||||||
|
assert.doesNotMatch(component, />Course information<\/span>/);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue