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
27 changes: 25 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
# EditorConfig houdt de opmaak gelijk tussen editors en IDE's.
# VS Code, JetBrains en anderen lezen dit bestand vanzelf.
# Meer info: https://editorconfig.org
#
# Deze versie is organisatiebreed gelijk. Wijk hier niet per repository van af:
# vijf licht verschillende varianten leverden alleen ruis op, geen voordeel.
#
# De configbestanden die zelf geen comments kunnen dragen omdat het JSON is,
# staan hier genoemd zodat er ergens een aanwijzing is wat ze doen:
#
# .htmlhintrc - HTML-linting (HTMLHint). Structuur- en toegankelijkheidsregels.
# renovate.json - Renovate-bot. Automatische dependency-updates via pull requests.

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
# Trailing whitespace betekent iets in Markdown (regeleinde)
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

[*.py]
indent_size = 4

[*.sh]
indent_size = 4
24 changes: 24 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# .gitattributes zorgt voor consistente regeleindes tussen Windows, Mac en Linux.
# Zonder dit kunnen regeleindes per ontwikkelaar of OS verschillen, wat leidt
# tot onnodige git-diffs en merge-conflicten.
#
# Deze versie is organisatiebreed gelijk. Wijk hier niet per repository van af:
# vier licht verschillende varianten leverden alleen ruis op, geen voordeel.

# Standaard: forceer LF voor alle tekstbestanden
* text=auto eol=lf

# Binaire bestanden: geen regeleindeconversie
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.webp binary
*.avif binary
*.pdf binary
*.woff binary
*.woff2 binary
*.ttf binary
*.otf binary
*.zip binary
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Beide eigenaren worden om review gevraagd, maar de goedkeuring van één van
# hen is genoeg om de merge vrij te geven. Zo ligt het werk niet stil als de
# ander er even niet is.
* @Stensel8 @AdiH1310
10 changes: 5 additions & 5 deletions .github/actions/setup-hugo/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ inputs:
runs:
using: composite
steps:
# The release comes off the network, so nothing is executed before the
# checksum says it is the archive we pinned.
# De release komt van het netwerk, dus er wordt niets uitgevoerd voordat de
# checksum zegt dat het het archief is dat we hebben vastgezet.
#
# --retry: the release CDN hands out an occasional 503, and without this a
# single one fails the whole build. curl retries 5xx and timeouts on its
# own; --retry-all-errors extends that to connection failures.
# --retry: de release-CDN geeft af en toe een 503, en zonder dit laat één
# zo'n antwoord de hele build falen. curl herhaalt 5xx en timeouts uit
# zichzelf; --retry-all-errors trekt dat door naar verbindingsfouten.
- name: Download and verify Hugo
shell: bash
env:
Expand Down
4 changes: 2 additions & 2 deletions .github/htmlhint/package-lock.json

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

2 changes: 1 addition & 1 deletion .github/htmlhint/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "hugo-template-htmlhint",
"name": "thectic-htmlhint",
"private": true,
"description": "Pinned HTMLHint install for .github/workflows/quality.yml. Not part of the site.",
"dependencies": {
Expand Down
28 changes: 28 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Samenvatting

<!-- Wat verandert er, en waarom? Een of twee zinnen. -->

## Type wijziging

<!-- De PR-titel moet met dit type beginnen, bijvoorbeeld `fix: kapotte link
op de contactpagina`. De controle "Conventional commit title" kijkt daarop.
Vink hieronder aan wat van toepassing is; de rest wordt automatisch
opgeruimd zodra de checks klaar zijn. -->

- [ ] `feat` — nieuwe pagina, sectie of functionaliteit
- [ ] `fix` — bugfix: kapotte link, verkeerde configuratie, renderfout
- [ ] `content` — bestaande inhoud bijwerken of verbeteren
- [ ] `docs` — README, CONTRIBUTING of andere metabestanden
- [ ] `chore` — onderhoud: dependencies, CI/CD, configuratie
- [ ] `refactor` — herstructurering zonder gedragsverandering
- [ ] `style` — opmaak, witruimte, typefouten
- [ ] `revert` — een eerdere commit terugdraaien

## Checklist

- [ ] PR-titel volgt de commit-conventie (`type: korte omschrijving`)
- [ ] Geen secrets, tokens of persoonsgegevens in de diff
- [ ] `hugo server` lokaal gedraaid vanuit `src/` en de pagina bekeken
- [ ] Licht én donker thema gecontroleerd, en op een smal scherm
- [ ] Geen gebroken links of verwijzingen naar bestanden die niet bestaan
- [ ] Versiebump van Hugo, actionlint of lychee? De bijbehorende SHA-256 ook bijgewerkt
40 changes: 20 additions & 20 deletions .github/workflows/config-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# SPDX-License-Identifier: MIT
name: Config validation

# The bot configs are the one part of CI that nothing else exercises: a broken
# renovate.json or dependabot.yml does not fail a build, it just quietly stops
# doing its job. This workflow is the thing that notices.
# De bot-configs zijn het enige deel van CI dat verder nergens door wordt
# geraakt: een kapotte renovate.json of dependabot.yml laat geen build falen,
# die houdt gewoon stilletjes op met zijn werk. Deze workflow merkt dat op.

on:
push:
Expand Down Expand Up @@ -46,33 +46,33 @@ jobs:
with:
node-version: 'lts/*'

# Renovate's own validator. --strict also fails on warnings, such as an
# option that is valid but deprecated. Given no arguments it finds the
# config files itself and validates them as repository config; passing a
# path instead makes it validate them as global config, which is a
# different and weaker set of rules.
# Renovates eigen validator. --strict laat hem ook falen op warnings,
# bijvoorbeeld een optie die geldig maar verouderd is. Zonder argumenten
# zoekt hij de configbestanden zelf op en valideert hij ze als
# repository-config; geef je een pad mee, dan valideert hij ze als
# global config, en dat is een andere en zwakkere set regels.
#
# Deliberately unpinned. This is a linter for our config, not something we
# ship, and the newest release is the one that knows about the newest
# deprecations. Its own version is not worth a pull request.
# Bewust niet vastgezet. Dit is een linter op onze eigen config en geen
# onderdeel van wat we uitleveren, en juist de nieuwste release kent de
# nieuwste deprecations. Zijn eigen versie is geen pull request waard.
#
# NPM_CONFIG_LOGLEVEL: npm prints "npm warn deprecated ..." for packages
# deep inside Renovate's own dependency tree. Those say nothing about the
# config being validated, and reading them as if they did is the obvious
# mistake to make when they appear directly above the validator's output.
# NPM_CONFIG_LOGLEVEL: npm print "npm warn deprecated ..." voor packages
# diep in Renovates eigen dependency-boom. Die zeggen niets over de config
# die gevalideerd wordt, en ze lezen alsof dat wel zo is, is de fout die
# je vanzelf maakt als ze vlak boven de output van de validator staan.
- name: Validate Renovate config
env:
NPM_CONFIG_LOGLEVEL: error
run: npx --yes --package renovate -- renovate-config-validator --strict

# The validator above accepts a well-formed pattern that matches nothing,
# so this covers the gap it leaves.
# De validator hierboven accepteert een correct gevormd patroon dat
# nergens op matcht; dit dekt het gat dat hij daarmee laat.
- name: Check Renovate file patterns
run: python3 .github/scripts/check-renovate-patterns.py renovate.json .github/renovate.json

# GitHub validates dependabot.yml only after it is on the default branch,
# and reports the result on a tab nobody opens. This brings that forward
# to the pull request.
# GitHub valideert dependabot.yml pas als die op de default branch staat,
# en meldt het resultaat op een tabblad dat niemand opent. Dit haalt dat
# naar voren, naar de pull request.
- name: Validate Dependabot config
env:
# renovate: datasource=pypi depName=check-jsonschema
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-bunny.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ concurrency:
group: deploy
cancel-in-progress: true

# No token needed; jobs that do opt in explicitly.
# Geen token nodig; jobs die dat wel zijn, vragen er expliciet om.
permissions: {}

jobs:
Expand Down
109 changes: 109 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Copyright (C) 2026 Sten Tijhuis
# SPDX-License-Identifier: MIT
name: PR title

# Twee controles op de pull request zelf, bewust in één job.
#
# GitHub rekent per job en rondt elke job naar boven af op een hele minuut.
# Beide stappen hieronder zijn in een paar seconden klaar en hebben geen
# checkout nodig, dus als losse jobs kosten ze twee volle minuten voor werk
# van tien seconden. In één job is dat één minuut.
#
# Dat de job `pull-requests: write` heeft terwijl de titelcontrole aan lezen
# genoeg heeft, is de prijs van die samenvoeging. Beide actions staan op een
# vastgezette SHA, dus dat is hier een acceptabele ruil.
#
# De titel en niet de losse commits: de titel is wat er op main terechtkomt
# zodra je squasht. Renovate levert zijn eigen titels al in dit formaat aan;
# dat is de semanticCommits-instelling in renovate.json.

on:
pull_request:
# edited hoort erbij: zonder dat blijft de check rood staan nadat iemand de
# titel heeft verbeterd, want een titelwijziging is geen nieuwe push.
types: [opened, edited, synchronize, reopened]

# Snel achter elkaar de omschrijving aanpassen startte evenveel runs. Alleen de
# laatste zegt nog iets, dus de rest mag weg.
concurrency:
group: pr-title-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions: {}

jobs:
pr-title:
name: Conventional commit title
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
content
docs
chore
refactor
style
revert

# Vinkt de twee punten af die uit de pull request zelf af te leiden zijn,
# en ruimt de niet-gekozen regels onder "Type wijziging" op. De rest van
# de checklist blijft handwerk: of iemand de pagina echt in de browser
# heeft bekeken, valt hier niet te controleren.
#
# Draait op !cancelled(), zodat een afgekeurde titel het opruimen niet
# tegenhoudt -- juist dan wil je de checklist bijgewerkt zien.
- name: Update PR checklist
if: ${{ !cancelled() }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});

let body = pr.body || '';
if (!body.trim()) return;

const setCheck = (keyword, passed) => {
body = body.replace(
new RegExp(`- \\[[ xX]\\] (.*${keyword}.*)`, 'i'),
`- [${passed ? 'x' : ' '}] $1`
);
};

// Dezelfde typelijst als hierboven en als CONTRIBUTING.md. Scope en
// een `!` voor een breaking change zijn toegestaan: feat(nav)!: ...
const TITLE_RE =
/^(feat|fix|content|docs|chore|refactor|style|revert)(\([^)]+\))?!?: .+/;
setCheck('PR-titel volgt', TITLE_RE.test(pr.title));

// De niet-gekozen types weghalen, maar alleen als er al een gekozen
// is. Zonder die voorwaarde stript de eerste run alle acht regels
// weg voordat de auteur er een heeft aangevinkt, en is de sectie
// weg voordat hij gebruikt kon worden.
const TYPE_LINE = /^- \[([ xX])\] `\w+` —[^\n]*\n?/gm;
const ticked = [...body.matchAll(TYPE_LINE)]
.some(m => m[1].toLowerCase() === 'x');
if (ticked) {
body = body.replace(/^- \[ \] `\w+` —[^\n]*\n?/gm, '');
}

body = body.replace(/\n{3,}/g, '\n\n');

if (body !== pr.body) {
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
body,
});
}
Loading