https://kingsdigitallab.github.io/kdl/
https://kdl.kcl.ac.uk/
The website uses a static-first approach:
- ETL: A script fetches data from ClickUp and saves it in the YAML header of the markdown files in
frontend/src - Frontend: 11ty builds static pages from the ClickUp data and handwritten parts of the markdown files
Install the node packages:
npm installInstall the git hooks:
npx simple-git-hooksThis project is set up as a monorepo with:
- ETL: Fetches data from ClickUp and outputs JSON to
frontend/src/_data/ - Frontend: 11ty static site generator
To fetch data from ClickUp:
npm run etl:clickupThis fetches data from the "Website" custom item in ClickUp and saves JSON files to frontend/src/_data/.
To run the frontend locally:
npm run frontend:devThe site will be available at http://localhost:8080.
- Create a branch from
develop - Make your changes
- Test locally with
npm run frontend:dev- If this is not set up, just skip this step. If something goes wrong, merges can be reverted.
- Merge your branch into
develop- This triggers a deployment to the dev site
- Review your changes on the dev site
- Take a screenshot if the change is complicated
(note: adding text only is not complicated. If the page grabs data from somewhere else, it is complicated.) - Delete your branch if you are happy. The branch is just clutter now, your changes live in
developnow. (No need to worry: The branch can be restored if needed.)
- After reviewing on the dev site, open a PR from
developtomain. Now you are done.- Add someone as reviewer, this triggers GitHub to email them
- In the description, add the screenshot from before
- After the review will be approved, develop can be merged into main
(note: the review is purely technical to check whether the changes will render or break the site. Content is not reviewed.) - Merging triggers a deployment to the live site
---
title: workflow to add changes
---
gitGraph
checkout main
commit id: "branch for live site " tag: "eternal branch"
branch develop
checkout develop
commit id: "branch for dev site " tag: "eternal branch"
branch your-change-branch
checkout your-change-branch
commit id: "branch for making changes " tag: "temporary branch"
commit id: "Make changes"
commit id: "Test locally: npm run frontend:dev"
commit id: "merge back to develop to trigger release to dev site"
checkout develop
merge your-change-branch tag: "automatic release to dev"
commit id: "Review on dev site"
commit id: "maybe take screenshot"
commit id: "Open PR: develop to main. Merging will trigger release."
checkout main
merge develop tag: "automatic release to live"
We usually use VSCode, where you can click in the UI for all these actions. For reference, here are the commands:
# Create a new branch
git checkout -b my-content-change-branch develop
# Make changes and test locally
npm run frontend:dev
# Commit and push
git add .
git commit -m "description of changes"
git push -u origin my-content-change-branch
# Merge into develop
git checkout develop
git merge my-content-change-branch
git push develop
git branch -d my-content-change-branchSome content is managed in ClickUp and synced to the site via ETL, while other content is written directly in markdown files in this repository.
In ClickUp:
- Projects (This updates the
yamlfrontmatter offrontend/src/projects/projectname.md)- Project team members are synced from ClickUp into each project's
memberslist. This determines who is listed on a project page, but their names will render as plain text unless a matching entry exists in_data/people.jsonandabout/people/{slug}.md(see below).
- Project team members are synced from ClickUp into each project's
In Markdown files:
- People (two files to update — see example below)
- Blog posts (
frontend/src/blog/*.md) - FAQ pages (
frontend/src/faqs/*.md) - Theme pages (
frontend/src/themes/*.md) - Slides/presentations (
frontend/src/slides/*.md) - Project descriptions need to be written manually into the automatically created markdown file from above (
frontend/src/projects/projectname.md). Simply add an empty line below the second triple dash (---) and start writing your description.
People data is maintained manually in two files. Both are required — the JSON entry controls whether the person's name renders as a link on project pages, and the markdown file creates their profile page at /about/people/{slug}/.
- Add the person to
frontend/src/_data/people.json— Append a new entry following the existing structure. The key fields areagent.slug(used for lookups),agent.name, andagent.memberOf[].inProject(links the person to projects):
{
"jobTitle": null,
"agent": {
"name": "Their Name",
"slug": "their-name",
"description": "Optional short bio.",
"memberOf": [
{
"startDate": null,
"endDate": null,
"inProject": {
"name": "Project Name",
"alternateName": "",
"slug": "project-slug",
"foundingDate": null,
"dissolutionDate": null,
"department": [
{
"organisation_id": {
"agent": {
"name": "Department Name"
}
}
}
]
},
"inOrganisation": {
"agent": {
"name": "Organisation Name",
"slug": "org-slug"
}
},
"roleName": {
"name": "Their Role"
}
}
]
}
}- Create the profile page at
frontend/src/about/people/their-name.md— The filename must match the slug:
---
title: Their Name
slug: their-name
jobTitle: null
tags:
- people
memberOf:
- startDate: null
endDate: null
organisation:
name: Organisation Name
slug: org-slug
roleName: Their Role
---
Optional biography in markdown.- Test locally — Run
npm run frontend:devand check the person's name is linked on the relevant project pages.
- Create the markdown file - Add a new file at
frontend/src/blog/your-title.mdwith frontmatter:
---
title: Your Article Title
subtitle: A brief subtitle
tags:
- post
- Your Topic
authors:
- Your Name
date: 2026-04-21
excerpt: A short description for previews and SEO.
feature:
image: /assets/images/blog/your-image.jpg
title:
description: Alt text for the image
----
Add the image - Place your image in
frontend/src/assets/images/blog/your-image.jpg -
Check ClickUp (optional) - If the article references team members or projects, ensure they exist in ClickUp so the ETL can link them properly.
-
Test locally - Run
npm run frontend:devto preview your changes before merging.
We have files for html templating, called nunjuck files. They have the .njk extension. To lint those files, additional dependencies have to be installed. There is a python package called djlint, which can be pip installed. There is a VSCode extension https://marketplace.visualstudio.com/items?itemName=monosans.djlint, for which there are settings in the vscode settings, and it is currently also installed in the devcontainers.
TODO: Find a way to lint those files in a pre-commit hook and in the CI pipeline.
The data model is based on the schema.org vocabulary. Local customisations are prefixed with KDL.
erDiagram
AGENT }o--o{ LINKROLE: url
AGENT ||..o{ ORGANISATION: is
AGENT ||..o{ PERSON: is
AGENT }o--o{ KDLROLE: memberOf
AGENT {
string name
string alternateName
string description
}
ORGANISATION ||--o| ORGANISATION: parentOrganisation
ORGANISATION {
date foundingDate
date dissolutionDate
}
DEFINEDTERMSET ||--o{ DEFINEDTERM: hasDefinedTerm
DEFINEDTERMSET ||--o{ LINKROLE: url
DEFINEDTERMSET {
string name
}
DEFINEDTERM ||--|| DEFINEDTERMSET: inDefinedTermSet
DEFINEDTERM {
string name
}
PROJECT ||--|| DEFINEDTERM: creativeWorkStatus
PROJECT }o--o{ DEFINEDTERM: keywords
PROJECT }o--o{ LINKROLE: url
PROJECT ||--o{ ORGANISATION: department
PROJECT }o--o{ AGENT: funder
PROJECT }o--o{ KDLROLE: member
PROJECT }o--o{ PROJECT: relatedTo
PROJECT {
string name
string slug
string alternateName
date foundingDate
date dissolutionDate
text description
}
KDLROLE ||--|| AGENT: agent
KDLROLE ||--|| ORGANISATION: inOrganisation
KDLROLE ||--|| PROJECT: inProject
KDLROLE {
string name
date startDate
date endDate
}
LINKROLE {
string name
date startDate
date endDate
string url
}
WEBPAGE ||--|{ AGENT: author
WEBPAGE }o--o{ AGENT: contributor
WEBPAGE ||--o{ DEFINEDTERM: keywords
WEBPAGE }o--o{ AGENT: about
WEBPAGE }o--o{ PROJECT: about
WEBPAGE ||--|| WEBPAGE: isPartOf
WEBPAGE ||--o{ WEBPAGE: hasPart
WEBPAGE {
string name
string slug
string type
text abstract
text text
}