Skip to content

Convert the website from Jekyll to Hugo + Hextra - #273

Draft
garth-wells wants to merge 29 commits into
mainfrom
hextra-conversion
Draft

garth-wells wants to merge 29 commits into
mainfrom
hextra-conversion

Conversation

@garth-wells

Copy link
Copy Markdown
Member

Rebuilds the site with Hugo and the
Hextra theme, replacing Jekyll.

Every page keeps the address it had before. All 34 URLs (pages and
assets) were checked against the running site, including the old
/conference/pages_2024/schedule.html, which now redirects.

What moved where

Jekyll Hugo
_config.yml hugo.yaml
.md files in the repo root and subfolders content/
permalink: url:
image-zoom: fill imageFit: cover
_layouts/, _includes/ layouts/
_includes/_paper.html etc. layouts/_shortcodes/
_includes/_country.html data/flags.yaml
_data/navbar.yml menu.main in hugo.yaml
assets/ (served as-is) static/
assets/css/customsty.css assets/css/custom.css

Links between pages are now written as full addresses (/download/)
rather than relative paths to .md files.

Look and feel

The page header (background image, title, subtitle) is a partial
inserted below the navigation bar, so pages keep their hero images and
the front page keeps the logo. Hextra adds site search, a dark-mode
toggle (light by default) and a per-page contents list.

The Liquid includes become shortcodes: paper, person, quote,
image, and buttons/button. _developer.html was unused and has
been dropped. Each shortcode documents the settings it takes.

Judgement calls worth a look

  • Font Awesome is gone — 2114 files, 27MB, used for nine icons, all
    of which the theme already ships.
  • Inline maths is now \( \) only, not $ … $. The old MathJax
    settings treated $ as a delimiter, so ($500) … ($500) on the
    FEniCS 2026 page is currently being swallowed as maths on the live
    site. Dollar amounts are now left alone; the one real formula on that
    page became \(\varphi\).
  • The link test was broken. load_page_list tested
    os.path.isdir(f) against the working directory rather than the
    directory being walked, so it never recursed and only ever checked the
    two top-level pages. It now checks all of them, and href/src
    attributes as well. Links inside HTML comments are skipped, since the
    2027 page has a commented-out draft containing a placeholder URL.
  • The hand-rolled photo slider on the FEniCS 2026 page uses Hextra's
    gallery shortcode, and the YouTube embeds use Hugo's youtube
    shortcode.
  • _tools/make_bibtex.py has been pointed at the new paths but not
    run: the committed citations.bib is hand-curated (fuller author
    names, a legacy section) and the tool would overwrite it with a
    reduced version. That mismatch predates this change, but it may be
    worth deciding whether the tool should still exist.

Before merging

GitHub Pages can no longer build this itself. .github/workflows/deploy.yml
publishes the site, but only once Settings → Pages → Source is
switched from "Deploy from a branch" to "GitHub Actions". Until that
is changed, pushes to main will build but not publish.

Checks

A clean clone builds with hugo --minify --printPathWarnings --panicOnWarning with no warnings, and _test/ passes (103 tests,
flake8 clean).

🤖 Generated with Claude Code

garth-wells and others added 3 commits October 10, 2026 17:18
The site is now built with Hugo using the Hextra theme, replacing the
Jekyll setup. Every page keeps the address it had before.

Content moves to content/, with Jekyll's `permalink` becoming Hugo's
`url` and `image-zoom: fill` becoming `imageFit: cover`. Links between
pages are now written as full addresses rather than relative paths to
.md files.

The Liquid includes become Hugo shortcodes (`paper`, `person`, `quote`,
`image`, `buttons`/`button`), and the 250-branch country include becomes
a data file read by the `person` shortcode. The page header (background
image, title, subtitle) is a partial inserted below the navigation bar,
so pages keep their hero images.

Font Awesome (2114 files, 27MB) is dropped in favour of the icon set
that ships with the theme. The hand-rolled photo gallery on the FEniCS
2026 page uses Hextra's `gallery` shortcode, and YouTube embeds use
Hugo's `youtube` shortcode.

Inline maths is now delimited by \( \) only, so that dollar amounts
such as $500 are no longer parsed as maths.

The build workflow uses Hugo, and a new deploy workflow publishes to
GitHub Pages; this needs Settings -> Pages -> Source set to "GitHub
Actions". The tests read hugo.yaml and Hugo front matter. test_links
previously recursed into subdirectories using a path relative to the
working directory rather than to the directory being walked, so it only
ever checked the top-level pages; it now checks all of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The maths section was wrong on two counts: the delimiters are written
with a single backslash in the markdown source, and `math: true` is not
needed, because Hextra's render hook loads KaTeX whenever a page
actually contains maths. Drop the setting from the FEniCS 2026 page,
where it was a no-op.

Also document the three `imageFit` values rather than two, `aliases`,
`headerLogo` and `hideHeader`, how pages are named and arranged in
`content`, `data/flags.yaml`, `weight` in the navigation bar, how to
update the theme, and how to run the tests. Fix three typos carried
over from the previous README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The build instructions only covered Ubuntu. Add the Homebrew packages
for macOS, and say how to check that Hugo is the extended edition
rather than naming the editions of particular packages.

Split the section so that serving the website locally is its own step,
with the address to open and a note that the first run downloads the
theme. Pages link to each other by absolute address, so opening the
built files directly does not work; say so, and give the command to
serve the `public` folder instead.

Use `python3` rather than `python` throughout, as macOS has no `python`
on the path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread .github/workflows/build.yml Outdated
steps:
- run: sudo apt-get install -y ruby-bundler
name: Install prerequisites
- uses: actions/checkout@v4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are updating things, please update this to v7 (and maybe add a dependabot?

Comment thread .github/workflows/build.yml Outdated
- run: bundle exec jekyll build

- uses: actions/setup-go@v5
name: Install Go (needed to fetch the Hextra theme module)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setup go is also at v7 now

garth-wells and others added 15 commits October 10, 2026 17:29
Put a blank line after every heading, wrap prose at 80 columns, give
every fenced block a language, and use `1.` rather than `1)` for
numbered steps. Break the list of shortcodes out of a long parenthetical
sentence into a list, and wrap the example over two lines so that it
fits; shortcodes may be written either way.

No wording changes. markdownlint reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The header used to float a 90%-opaque white panel over the background
image. Against the FEniCS pattern that left the title washed out, and on
the front page the logo all but disappeared into the field of the same
artwork behind it.

Instead, draw the image through a pseudo-element with a dark gradient
scrim over it and set the title in white. The title is legible whatever
the image behind it, the venue photographs read properly, and the header
now looks the same in light and dark mode. The front page blurs its
background so that the logo stands clear of the pattern.

The header was also 540px tall, which pushed the content of every page
below the fold; it is now 330px, or 260px where there is no subtitle.

Elsewhere:

- Cap the text measure at 52rem. Pages without a table of contents
  beside them were setting prose across the full 1000px column.
- Make the front page's icon links look like the links they are: bordered
  cards with the icon in the brand blue and a hover state, laid out on a
  grid rather than as bare 80px glyphs.
- Keep centred images to 30rem, so a sponsor logo no longer fills the
  column.
- Centre a person's role and links under their centred name.

Six pages opened with a `#` heading that repeated the page title and
outranked the `##` sections beside it, so "Description" was set larger
than the "Updates" above it and was missing from the contents list.
Demote those to `##`. documentation/v0_9_0.md keeps its `#` headings,
which genuinely outrank their children.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The reference site uses no web fonts: it is Hextra with the stock
`ui-sans-serif, system-ui, …` stack, which is what this website already
had. That resolves to SF Pro on macOS, but to Segoe UI on Windows and
usually Cantarell or DejaVu on Linux, so most FEniCS users were not
seeing the face it looks like in a Mac browser.

Pin Inter instead, which is drawn along the same lines as SF Pro, so the
result is close to the macOS rendering for everyone. The old Jekyll site
set its headings in Lato; this replaces that, rather than leaving the
fonts to the visitor's operating system.

The font is served from static/assets/fonts rather than from Google
Fonts, so that opening a page makes no third-party request. It is the
variable font, covering every weight the website uses in one file, and
it is split by unicode-range: the content currently has no Latin
Extended characters, so browsers fetch only the 48KB Latin file, and the
85KB Latin Extended file is there for names that need it later. The
Latin file is preloaded so that text is not first painted in the
fallback face.

Inter is used under the SIL Open Font License; the licence and the
provenance of the files are in static/assets/fonts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow the pattern golangci-lint.run uses: the note about the website
stays on the left of the footer and the places the project can be found
sit on the right, as icons. Below 640px the two stack and centre.

The icons come from the theme's own set, so this adds no new assets, and
they link to the same two addresses the front page already uses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
They are in the footer of every page now, so the front page no longer
needs a row of its own for them. That leaves one row of three for the
things a visitor is most likely to want: Download, Documentation and the
source code.

Slack is still linked from the community page, and both are still linked
from the footer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The front page was 139 words with no code and no picture of a result,
which for a finite element library leaves out the whole argument. The
Stokes example and the two figures it used were already in the
repository but had been dropped from the page at some point and were
referenced by nothing.

Restore them, with the code brought up to the current API: the legacy
version used VectorElement, P2 * P1 and solve(), none of which exist in
DOLFINx. The snippet now follows the 0.11 Stokes demo, which it links
to, and the variational form above it matches the code sign for sign.

Sharing:

- No page had an og:image, so a link posted to Slack or LinkedIn showed
  as a bare title. Add a share card, drawn the same way as the front
  page header so that a shared link looks like the website, and point
  site.Params.images at it; Hextra then fills in og:image, twitter:image
  and upgrades the card to summary_large_image.
- No page set a description, so the meta description was an excerpt
  starting mid-sentence ("Getting started The latest stable release
  of..."). Write one for each of the main pages.

Also:

- The conference archive was a flat list of 23 entries where live links
  and dead ones read alike. Lay the linked ones out as cards and keep
  the rest as a short tail.
- Remove 3.3MB of images that nothing references, including the old
  front page header, a superseded crop of the BAM photograph, and seven
  portraits orphaned when the unused _developer include went. They
  remain in the history if they are wanted again.
- dolfinxversion builds the URL of the DOLFINx documentation but, unlike
  fenicsxversion, no test covered it, so it could have gone stale
  silently. Check it against the released tags.
- The gallery photographs had alt text of "Photo 1", "Photo 12", which
  tells a screen reader nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"FEniCSx 0.11" sat under the title of those two pages. Both say which
release is current in their first sentence, where it reads as a fact
rather than as a label, so the header was repeating itself.

The pages now use the shorter header, as the other pages without a
subtitle do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The figure shows three spheres, not two: the demo it came from placed
s0, s1 and s2 in the channel, and brightening the image confirms the
third behind the other two.

Also spell 24,000 with a separator and rewrap the opening paragraph,
which had a line left at 97 characters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
At the foot of the front page the logo acknowledges NumFOCUS's support,
so it was being drawn at the default 480px and dominating the section it
sits under. Set it to 260px.

The conference and GSoC pages are left alone: there the logo is one of a
row of sponsors and should match the others.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- "Travel support applications opens" -> "open".
- "We thank [Ridgway Scott Foundation]" -> "the Ridgway Scott
  Foundation", as the other conference pages and the foundation itself
  write it, and make "Best Presentation" singular to match the heading
  above it.
- The registration fee was said to open and stay open; registration
  does. Recast those two lines.
- Write the application address as a Markdown link, as the organising
  committee's addresses lower down already are.
- Indent a list continuation line, and drop a stray blank line between
  the two sponsor blocks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The page now reads in the order a reader needs it: what the conference
is, how to take part, where it is, what is recognised, and then the
administrative sections.

Three moves:

- Abstract submission now comes before Travel awards. A travel award
  application has to include "a tentative abstract ... which will also
  need to be formally submitted once abstract submission opens", so the
  reader was meeting that forward reference several sections before the
  one it points at.
- "Getting there", which is still commented out, sat after Abstract
  submission. It belongs under Conference venue, which it continues, so
  that it is in the right place when it is written.
- Code of conduct was wedged between Abstract submission and the awards.
  It is administrative, so it now sits with the other administrative
  sections near the end.

No wording is changed: the text is the same word for word, only moved.

Note that the previous order matched the FEniCS 2025 page almost exactly,
so 2025 will now read differently; it would be worth making the same
moves there if this order is preferred.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Front page: drop the "The FEniCS computing platform" heading, which
repeated the title in the header above it.

Download: remove the "FEniCSx vs legacy FEniCS" section, scope the
complex number heading to Debian/Ubuntu, and rewrap the prose.

FEniCS 2027: comment out the Updates section and the Description
heading until there is news to carry, and move the link to previous
conferences into a section of its own at the end.
The download page no longer points at them, and the project recommends
FEniCSx to new users, so the page was unreachable except by an old link
or bookmark.

Redirect /download/archive/ to the download page rather than letting it
404, since the page has been at that address for years. The legacy
library is still covered elsewhere: its citations, its documentation and
what becomes of its packages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The project posts conference talks there, and the FEniCS 2024 and 2026
pages already embed videos from it, so it belongs beside LinkedIn and
Slack.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing on the website said that the next conference is in Berlin or
that travel award applications close on 10 January 2027; the only sign
of it was a navigation bar entry. Put it in Hextra's banner, which is a
dismissible strip above the navigation bar on every page, and link it to
the travel awards section. The key means a later message is shown again
to anyone who closed this one, and deleting the block takes the banner
down.

The FEniCSx tutorial is the most useful thing to hand a newcomer, and it
was reachable only through the documentation page. It now has a card of
its own on the front page, second after Download, which is the order
somebody new reads them in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
garth-wells and others added 9 commits October 10, 2026 23:27
Remove the "FEniCSx vs legacy FEniCS" section from the documentation
page, fold the tutorial into the paragraph about the documentation, and
take the Tutorial card off the front page again.
checkout, setup-go and upload-artifact move to v7, upload-pages-artifact
to v5 and deploy-pages to v5; Go moves from 1.23 to 1.27. Hugo stays at
0.167.0, which is still the current release.

upload-pages-artifact stopped including dotfiles at v4. The built site
has none, so nothing is lost; if that changes, the action takes an
include-hidden-files input from v5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Output is unchanged: all 32 pages are byte-identical to the previous
build once the stylesheet fingerprint is normalised, and the only change
to the compiled CSS is the three dropped !important.

Templates:

- Delete layouts/baseof.html. It was a copy of Hextra's whole page
  skeleton existing only to insert the page header after the navbar, and
  the header sits in exactly the same place when it is the first thing
  inside `define "main"`. One fewer theme file to keep in step.
- home.html, list.html and single.html were three byte-identical copies
  of Hextra's article scaffolding. The body moves to
  partials/page-body.html and each layout becomes two lines. (The three
  files have to stay: Hugo's lookup prefers the theme's own home.html
  and list.html over a project-wide template.)
- page-header.html: drop `hideHeader`, which no page used and which
  indented the whole partial, and the `$fallbackSubtitle` variable that
  existed only to carry the 404 subtitle forward. Subtitles now go
  through RenderString, so `{{< param fenicsxversion >}}` works there as
  it does in a page body, in place of a private {token} syntax that
  understood two names.
- person.html: the website, GitHub, Twitter and LinkedIn blocks were the
  same markup four times. One range over a slice of dicts, as
  custom/footer.html already does.

Config: remove 15 keys from hugo.yaml that restate a Hugo or Hextra
default and so only pin behaviour that would otherwise follow the theme.

CSS: remove all three !important. Each fought a theme rule that does not
apply -- two are excluded by the theme's own :not(.not-prose) selector,
and the third is beaten on source order anyway, since custom.css is
concatenated after the theme's stylesheet.

JavaScript: 404-redirect.js had a branch for the bare prefix ("pub")
beside the general one, but substring gives the empty string there, so
the general branch already covered it.

Tests: extract the duplicated hugo.yaml and GitHub-client setup in
test_version_numbers.py into helpers. In test_links.py, stop re-reading
and re-parsing every page three times, and make the duplicate-URL check
one assertion that names the offending URL rather than one test per
page.

CI: the Hugo version was pinned in two workflows that would drift. Both
now use a composite action that holds it once. build.yml no longer
builds main, which deploy.yml already builds, so a merge runs one build
rather than two, and its artifact expires after a week.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The site rendered every page through copies of Hextra's own templates,
taken so that the title could be replaced by a full-width header band.
Those copies go silently stale whenever the theme changes its page
scaffolding, which is the whole maintenance cost of forking a theme.

Use the theme's templates and its documented hooks instead:

- custom/page-begin.html puts the banner image above the title.
- custom/content-begin.html puts the subtitle below it.
- Hextra renders the title itself, so nothing has to suppress its <h1>
  and no CSS fights the theme.

The band therefore sits inside the content column rather than spanning
the window, and is styled as a rounded banner. The front page keeps its
blurred background and logo.

Section pages (the _index.md files) get `layout: single` in their front
matter: without it Hextra lays them out as documentation index pages,
with a left sidebar and a left-aligned title, which looked nothing like
the rest of the site.

layouts/404.html stays, and is the only file left that borrows theme
markup. Hextra's 404 is a standalone document that goes through no
hooks, so replacing it with the theme's would drop the site chrome and,
more to the point, the script that redirects the legacy /pub/,
/olddocs/ and /qa/ addresses. Its comment now says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Notes for coding agents working in this repository. README.md already
explains page settings and how to build, so this covers what it does
not: how to check a change, the rules that keep the theme unforked, and
the handful of traps that otherwise cost an hour each -- the maths
delimiter that Markdown steals, the bibliography tool that overwrites a
curated file, the version tests that rate-limit against the GitHub API,
and the footer that no headless screenshot can see.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rule was there but read as a note about vendoring. State it as the
first rule, covering Hugo as well as the theme, and list what the
repository does own so that the boundary is unambiguous.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The leading underscore was Jekyll's marker for "do not publish this
directory". Hugo has no such rule -- it publishes content/ and static/
and ignores everything else -- so the underscores had stopped meaning
anything and only made the two directories look special.

Nothing is published from either directory before or after, so no
address on the website changes. The paths the scripts resolve are
relative to their own file and the directories kept their depth, so
those are untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each reference was a single run of text between two blue bars, with the
title buried mid-sentence and the DOI and arXiv links wrapped in square
brackets. The right-hand bar also sat wherever the full-width box ended,
which was rarely near the text.

Give each one the shape a reader scans: title first, then the authors,
then the venue and year, with the links as small labelled buttons. One
accent bar on the left, and the :target highlight stays, so a link
straight to a citation still shows which one it landed on.

The shortcode takes exactly the same parameters, so no citation changes
and tools/make_bibtex.py, which reads the markdown rather than the
rendered page, is unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants