Skip to content

refactor(copy): move editor-facing copy into site.json and content blocks - #356

Merged
yasinmiran merged 5 commits into
mainfrom
feat/editable-site-copy
Oct 22, 2026
Merged

yasinmiran merged 5 commits into
mainfrom
feat/editable-site-copy

Conversation

@yasinmiran

@yasinmiran yasinmiran commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Moves the text editors change on the footer, the home page hero, Training and Research Support out of the components, so bever (and anyone without a dev setup) can change it. Bever's write scope is src/content/** and src/data/**, which is why it couldn't change the footer email: the address was hardcoded in footer.tsx. Bever's side of this is already in (ELIXIR-NO/bever 3726101).

Where the text lives now

  • src/data/site.json holds short plain strings: emails, headings, intros, button labels and links, the footer's navigation, partner and funder lists, and the pricing tiers. No markdown in it. src/lib/site.ts checks it at build time with a strict schema, so a missing, misspelt or extra key, an empty string or a malformed link fails the build and says which path is wrong, for example contact: Unrecognized key(s) in object: 'phone'. Paths on this site are stored as /services without the base path; the schema adds it. A link has to start with https://, mailto: or a single / and may not contain whitespace, because //host and /\host lead off the site, and browsers drop tabs and line breaks before reading those slashes, so /<tab>/host would too.
  • src/content/blocks/<slug>/index.mdx holds prose with links, bold or italics: the four training cards, the support model paragraphs and the service agreement. block.astro renders them with the same link, bold and italic styles the pages had, and links stay in the same tab, unlike elements.tsx, which sends every Markdown link to a new one. Card blocks take their heading from a title in the frontmatter. A missing block, a card block without a title, or any other frontmatter key fails the build.

What stays in the components: icons, layout, aria labels and screen-reader text, the "Pause animation" control, section headings that have no intro of their own, and the footer's ELIXIR brand sentence, which is mandated wording.

support@elixir.no and contact@elixir.no are both in site.json as contact.supportEmail and contact.generalEmail, since they look like two different mailboxes. Everything that showed support@ still does; switching the footer is now a one-line edit.

The hero is a React island, so index.astro passes it its slice of site.json as props. Neither the schema nor the rest of the file ends up in the browser bundle.

site.json is formatted the way Python's json.dumps(indent=4, ensure_ascii=False) writes it, so bever's first edit only touches the lines it changes. The training heading's two non-breaking spaces are literal characters in the file now.

The one wording change

The moved text had four em dashes, which I replaced in a separate commit (a594ec2) so it's easy to drop:

  • Training search description: a colon after "from ELIXIR Norway"
  • Research Support search description: a comma after "life science researchers"
  • Research Support intro: a comma after "long-term collaborations"
  • Train-the-Trainer card: a full stop after "TtT programme", so "Learn teaching techniques" starts a new sentence

Not in this PR

  • src/data/organizations.ts has editor-facing text too (org subtitles, addresses, contact lists, callouts), and it's TypeScript. Moving its data to JSON is a separate PR.
  • The services index, latest news section and org contact pages have more hardcoded text and can follow the same pattern.

Testing

pnpm build (0 errors, 0 warnings), pnpm test, pnpm test:slugs and pnpm test:pages pass on Node 24. To check that the refactor changes nothing, I built main and this branch and compared all 304 pages: visible text (with non-breaking spaces kept distinct), link targets, image sources, alt text, aria labels and meta tags. The refactor commit gives zero differences. With the dash commit on top, only /training and /research-support differ, in those four sentences. A control run confirms the comparison catches a single lost non-breaking space.

I also screenshotted the home, Training, Research Support and About pages from both builds at 375 and 1440 px, in light and dark, with every non-local request blocked. All 16 pairs are pixel-identical. Block links have the same colour, the same hover underline and no target, and the service agreement's italics render the same as before.

The build gate fails as intended on bad input: an unknown key, an empty headline, an unknown frontmatter key and a missing block each stop the build with a message naming the file. The link rules have their own tests in src/lib/site.test.ts, which feed the schema off-site links, including ones with a tab, newline or carriage return after the first slash; those three kinds got past the previous check, and the tests for them fail against it.

… out of components

The text editors change was hardcoded in components, so changing an email
address or a heading needed a developer. Short plain strings now live in
src/data/site.json, checked at build time by a strict schema in
src/lib/site.ts: a missing, misspelt or extra key fails the build with the
path of the problem. Prose with links or emphasis lives in
src/content/blocks/<slug>/index.mdx and renders through block.astro, which
styles links, bold and italics the way the pages did before and keeps links
in the same tab. A block that is missing, or a card block without a title,
also fails the build.

Paths on this site are stored without the base path and get it from the
schema. The hero gets its copy as props from index.astro, so neither the
schema nor the rest of site.json ends up in the hero's browser bundle.

Nothing visible changes: every built page has the same text, links, image
sources and alt text as on main, and the home, training, research support
and about pages render pixel for pixel the same at 375 and 1440 px in both
themes.
…rt text

The moved text had four em dashes: both pages' search descriptions, the
research support intro and the Train-the-Trainer card. I replaced each with
a colon, comma or full stop, so editors start from text that follows the
house style.
Bever rewrites the file with Python's json.dumps(indent=4, ensure_ascii=False).
Starting from that layout keeps its first edit to the lines it changes, not
the whole file. The training heading's non-breaking spaces are now literal
characters instead of \u00a0 escapes; the text is the same.
Copilot AI balanced review requested due to automatic review settings October 22, 2026 08:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

A link or logo starting with // (or /\, which browsers read the same way)
passed the check as a path on this site, but the browser would load it from
another host. Paths now have to start with a single /.
Browsers drop tabs and line breaks from a link before they read it, so "/\t/example.org" got past the single-slash check from the previous commit and still opened example.org. I now refuse any whitespace in links and logo paths; a real URL never needs it, since a space is written %20.

The schema is exported so the new test in src/lib/site.test.ts can feed it bad links. Against the previous check, its tab, newline and carriage-return cases fail.
@yasinmiran
yasinmiran added this pull request to stack #358 October 22, 2026 21:26
@yasinmiran
yasinmiran removed this pull request from stack #358 October 22, 2026 21:26
@yasinmiran
yasinmiran merged commit 8b285b1 into main Oct 22, 2026
1 check passed
@yasinmiran
yasinmiran deleted the feat/editable-site-copy branch October 22, 2026 21:27
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