Writing documentation
The documentation website is built with Astro Starlight, in English only, from the Markdown files in docs/. It is served by Codeberg Pages at https://squidd.codeberg.page/TildeMail/. A release publishes the site by itself, and the same workflow can be run by hand to publish a fix between releases.
Run it locally
Section titled “Run it locally”Use Node 24.21.0 (also recorded in website/.nvmrc; the engines field of website/package.json refuses other major versions). From the repository root:
npm --prefix website cinpm --prefix website run devOpen the address that Astro prints. Search is not available in the development server; use the production preview to try it.
npm --prefix website testnpm --prefix website run buildnpm --prefix website run previewtest runs the tests of the importer and of the link check (node --test). build imports the pages, builds the site and its search index, then checks the links. preview serves the result of the build.
scripts/build-site.sh [revision] does what the workflows do: npm ci, the tests, then the build. The optional revision (a tag such as v0.2.0, a branch or a commit) is where the source links of the site point; empty means develop. The script passes it to the importer in the TMAIL_DOCS_REF environment variable.
Edit a page
Section titled “Edit a page”The text lives where it always did:
docs/*.mdholds the guides and references. The first#heading of a file is the title of its page.- Write links in Markdown, never in raw HTML: the importer rewrites only Markdown links and images, so an
<a href>or<img src>would break under the base path. README.mdstays the entry point of the repository; the site does not import it.- The documents in the root of the repository are imported too, in a Project group of the sidebar:
CHANGELOG.md(written by git-cliff at each release),CODE_CONVENTION.md,THIRD-PARTY-NOTICES.md(generated byscripts/generate-third-party-notices.sh) andLICENSE, which is plain text and is shown as a code block under a short intro line. Edit them in the root, never on the site; the pages of the generated ones have no “Edit page” link. website/src/content/docs/index.mdxis the home page, written by hand: the title, the three install ways and the links to the tutorial and the reference.- The version shown next to the site title and in the footer is read from the
<Version>element ofDirectory.Build.props(website/version.mjs) when the site is built, so a release needs no manual edit of the site. The components are inwebsite/src/components/. website/src/styles/theme.cssis the theme: the colors, the fonts and the home page styles, all on top of the Starlight tokens.
Never edit website/src/content/docs/generated/ or website/public/generated/. The importer (website/scripts/prepare-docs.mjs) replaces them on every build, and Git ignores them. If you change a file in docs/ while the development server runs, run npm --prefix website run prepare:docs in a second terminal to import it again.
Add a page
Section titled “Add a page”- Write the Markdown file in
docs/, starting with a#title. - Add an entry to
website/docs-manifest.mjswith the source path, a slug (lowercase letters, digits and hyphens) and the label shown in the sidebar. The order of the list is the order of the sidebar. The source is a path from the repository root, so a file outsidedocs/works the same way. An entry may also settitle(instead of the first heading),group(a sidebar group),generated(no “Edit page” link) and, for a plain text file,format: 'text'with anintro. - Run the tests and the build.
How links are handled
Section titled “How links are handled”Write links as relative paths, as you would for the repository. The importer rewrites them:
- a link to another page listed in the manifest becomes the route of that page, and keeps its
#fragment; this holds for the root documents too, fromdocs/and between themselves (../LICENSE,docs/security.md); - a link to an image copies the image into the site;
- a link to any other file or folder of the repository becomes a Codeberg link at the published revision;
- links with a scheme (
https:,mailto:) and links inside the page are left alone, and code blocks are never touched.
The import stops, naming the file and the line, for a link that points nowhere, a link that leaves the repository, a page without a title, or a duplicate or invalid slug. The previous output stays in place.
After the Astro build, website/scripts/check-links.mjs reads the built HTML and fails the build if a local link, image or #fragment does not exist, if a page of the manifest is missing, if an anchor appears twice on a page, or if the search index was not built. External addresses are not fetched.
How it is published
Section titled “How it is published”The site is built in a Forgejo Actions workflow and uploaded to Codeberg Pages with the git-pages action. The address and the base path (/TildeMail) are set once in website/site-config.mjs, which the build and the link check share. The site URL matches the repository, so the automatic token of the run is enough: there is no secret to set up.
- By hand: in the Actions tab, open the
docsworkflow and choose Run workflow. The optionalrelease_taginput is the revision for the source links. - At each release: the last job of
release.ymlbuilds the site from the new tag and publishes it. If only that job fails, the release stays published; run thedocsworkflow by hand to retry.
Each publication replaces the whole site; older versions are not kept. Runs of the docs workflow never overlap. See Development for the rest of the CI.