Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Checks a pull request before it is merged: formatting, types, a full build,
# and Lighthouse against the budgets in lighthouserc.json. It deploys nothing.
# browser tests, and Lighthouse against the budgets in lighthouserc.json. It
# deploys nothing.

name: CI

Expand All @@ -16,7 +17,7 @@ permissions:

jobs:
build:
name: Format, types, build, Lighthouse
name: Format, types, build, tests, Lighthouse
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.1
Expand All @@ -34,6 +35,13 @@ jobs:
- name: Types and build
run: npm run build

# What a visitor sees: every section, image and link, the layout from a
# 320px phone up, the four themes, and the page without JavaScript.
- name: Browser tests
run: |
npx playwright install --with-deps chromium
npm test

# Fails if performance, accessibility, best practices or SEO drop below
# their budgets, or if the page grows past 250 KB.
- name: Lighthouse
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ node_modules/
.DS_Store
.tern-port
.lighthouseci/
test-results/
playwright-report/
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ dist
node_modules
package-lock.json
.lighthouseci
test-results
playwright-report
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ and hold no text of their own, except section headings.
2. Run `npm run dev` and check the page in a light and a dark theme: the
theme follows the clock, so change the hour, or set `data-season` and
`data-time` on `<html>` in the browser's inspector.
3. Before pushing: `npm run format`, then `npm run build && npm run lighthouse`.
3. Before pushing: `npm run format`, then `npm run build && npm test && npm run lighthouse`.
The first time, `npx playwright install chromium` downloads the test browser.
4. Open a pull request into `develop`. CI runs the same checks; it must pass.
5. To publish, merge `develop` into `master`. `deploy.yml` builds and deploys.

Expand All @@ -28,6 +29,7 @@ and hold no text of their own, except section headings.
| ---------------------------------- | ------------------------------- | ------------------- |
| Formatting | Prettier, no diff | `npm run format` |
| Types | `astro check`, strict, 0 errors | `npm run build` |
| Browser tests | All pass | `tests/` |
| Lighthouse performance | ≥ 95 | `lighthouserc.json` |
| Accessibility, best practices, SEO | 100 | `lighthouserc.json` |
| Layout shift (CLS) | ≤ 0.01 | `lighthouserc.json` |
Expand Down Expand Up @@ -55,7 +57,7 @@ Dependencies update themselves; nobody has to accept a pull request.
- Every Monday, Dependabot opens one grouped pull request for npm and one for
GitHub Actions, against `master`, with releases at least 14 days old
(`cooldown` in `.github/dependabot.yml`).
- CI runs on it: format, types, build, Lighthouse budgets.
- CI runs on it: format, types, build, browser tests, Lighthouse budgets.
- If CI passes, `dependabot-merge.yml` merges it, deploys, and merges `master`
back into `develop`.
- If CI fails, the pull request stays open and nothing ships. That is the one
Expand Down
46 changes: 46 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"check": "astro check",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lighthouse": "lhci autorun"
"lighthouse": "lhci autorun",
"test": "playwright test"
},
"dependencies": {
"@fontsource-variable/inter": "5.3.0",
Expand All @@ -29,6 +30,7 @@
"devDependencies": {
"@astrojs/check": "0.9.10",
"@lhci/cli": "0.15.1",
"@playwright/test": "1.64.1",
"prettier": "3.9.10",
"prettier-plugin-astro": "1.1.1",
"typescript": "6.0.3"
Expand Down
25 changes: 25 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Browser tests against the built site (dist/), served by `astro preview`:
// what a visitor sees, not how the components are written.
import { defineConfig, devices } from '@playwright/test';

const port = 4329;

export default defineConfig({
testDir: 'tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
reporter: process.env.CI ? [['github'], ['list']] : 'list',
use: {
baseURL: `http://localhost:${port}`,
// The theme follows the visitor's clock; tests that depend on it set both.
timezoneId: 'Europe/Brussels',
locale: 'en-GB',
},
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
webServer: {
command: `npm run preview -- --port ${port} --ignore-lock`,
url: `http://localhost:${port}`,
reuseExistingServer: !process.env.CI,
},
});
Binary file modified public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/favicon-32x32.png
Binary file not shown.
Binary file modified public/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/icon-512.png
Binary file not shown.
17 changes: 17 additions & 0 deletions src/components/Companies.astro
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,21 @@ const logos = await Promise.all(
width: calc(var(--w) * 0.75);
}
}

/* When the six no longer fit on one line, full rows of three, then of two:
never one logo left alone on a row. */
@media (max-width: 640px) {
.logos {
display: grid;
grid-template-columns: repeat(3, 1fr);
justify-items: center;
gap: 22px 12px;
}
}

@media (max-width: 340px) {
.logos {
grid-template-columns: repeat(2, 1fr);
}
}
</style>
33 changes: 30 additions & 3 deletions src/components/Hero.astro
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import Download from './icons/Download.astro';
{person.lastName}
</h1>
<p class="role reveal">
{person.role} <span aria-hidden="true">|</span> {person.credentials}
{person.role}
<span class="sep" aria-hidden="true">
{' |'}
</span>
{/* The space belongs to the credentials, so screen readers keep it without the bar. */}
<span class="credentials">{` ${person.credentials}`}</span>
</p>
<p class="pitch reveal">{person.pitch}</p>
<div class="actions reveal">
Expand Down Expand Up @@ -69,7 +74,7 @@ import Download from './icons/Download.astro';
letter-spacing: -0.3px;
}

.role span {
.role .sep {
color: var(--primary);
}

Expand Down Expand Up @@ -121,12 +126,25 @@ import Download from './icons/Download.astro';
0 30px 60px -30px rgb(20 14 8 / 0.45);
}

/* Stacked, the text is centred above the photo, so both share one axis. */
@media (max-width: 920px) {
.hero {
grid-template-columns: 1fr;
gap: 48px;
padding-top: 40px;
padding-bottom: 72px;
text-align: center;
}

/* Centred lines of even length, with no word left alone on the last. */
.role,
.pitch {
margin-inline: auto;
text-wrap: balance;
}

.actions {
justify-content: center;
}

h1 {
Expand All @@ -147,8 +165,17 @@ import Download from './icons/Download.astro';
}
}

/* Phones: the two buttons share the row, or stack at full width. */
/* Phones: the two buttons share the row, or stack at full width. The
credentials take their own line, without a bar left at the end of one. */
@media (max-width: 480px) {
.role .sep {
display: none;
}

.credentials {
display: block;
}

.actions .btn {
flex: 1 1 auto;
justify-content: center;
Expand Down
33 changes: 20 additions & 13 deletions src/data/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,6 @@ export const companies: Logo[] = [
{ name: 'Cronos', src: cronos, height: 42 },
];

export const figures = [
{
value: '15+',
label: 'Years of software development, 5+ of them in professional cloud & data roles',
},
{ value: '11', label: 'AWS, Azure & Scrum certifications' },
{ value: '900+', label: 'GitHub stars on open-source projects I built' },
{
value: '6',
label: 'Client industries: health insurance, chemicals, logistics, engineering, sport, data',
},
];

export type Icon = 'compass' | 'shield' | 'chart' | 'people';

export const expertise: { icon: Icon; title: string; summary: string; points: string[] }[] = [
Expand Down Expand Up @@ -246,6 +233,8 @@ export interface Certification {
issuer: string;
year: string;
badge: ImageMetadata;
/** How many certifications the badge stands for, when more than one. */
count?: number;
}

export const certifications: { tier: string; items: Certification[] }[] = [
Expand Down Expand Up @@ -285,12 +274,30 @@ export const certifications: { tier: string; items: Certification[] }[] = [
issuer: 'Microsoft',
year: '2022–2023',
badge: azureAi,
count: 2,
},
{ name: 'Professional Scrum Master I', issuer: 'Scrum.org', year: '2022', badge: psm1 },
],
},
];

const certificationCount = certifications
.flatMap(({ items }) => items)
.reduce((total, { count = 1 }) => total + count, 0);

export const figures = [
{
value: '15+',
label: 'Years of software development, 5+ of them in professional cloud & data roles',
},
{ value: String(certificationCount), label: 'AWS, Azure & Scrum certifications' },
{ value: '900+', label: 'GitHub stars on open-source projects I built' },
{
value: '6',
label: 'Client industries: health insurance, chemicals, logistics, engineering, sport, data',
},
];

export const publications = [
{
venue: 'Springer Nature · 2023',
Expand Down
4 changes: 2 additions & 2 deletions src/layouts/Base.astro
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ const jsonLd = {
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />

<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="icon" href="/favicon-32x32.png" type="image/png" sizes="32x32" />
<link rel="icon" href="/favicon.ico" sizes="32x32" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />

<meta property="og:type" content="profile" />
Expand Down
Loading
Loading