Skip to content
TildeMailv0.2.1

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.

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:

Terminal window
npm --prefix website ci
npm --prefix website run dev

Open the address that Astro prints. Search is not available in the development server; use the production preview to try it.

Terminal window
npm --prefix website test
npm --prefix website run build
npm --prefix website run preview

test 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.

The text lives where it always did:

  • docs/*.md holds 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.md stays 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 by scripts/generate-third-party-notices.sh) and LICENSE, 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.mdx is 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 of Directory.Build.props (website/version.mjs) when the site is built, so a release needs no manual edit of the site. The components are in website/src/components/.
  • website/src/styles/theme.css is 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.

  1. Write the Markdown file in docs/, starting with a # title.
  2. Add an entry to website/docs-manifest.mjs with 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 outside docs/ works the same way. An entry may also set title (instead of the first heading), group (a sidebar group), generated (no “Edit page” link) and, for a plain text file, format: 'text' with an intro.
  3. Run the tests and the build.

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, from docs/ 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.

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 docs workflow and choose Run workflow. The optional release_tag input is the revision for the source links.
  • At each release: the last job of release.yml builds the site from the new tag and publishes it. If only that job fails, the release stays published; run the docs workflow 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.