Skip to content

v0.22.0

Latest

Choose a tag to compare

@mmcky mmcky released this 25 Aug 04:35
· 1 commit to main since this release

Added

  • Dismissible announcement banner — a new announcement theme option renders a notice at the top of every page (HTML allowed, so you can include emphasis and a link to changelog notes). Readers dismiss it with a ×; the dismissal persists in localStorage and is keyed to a hash of the message, so editing the text re-shows the banner for everyone who dismissed the previous one. An optional announcement_expires ISO date (YYYY-MM-DD) auto-hides the banner after that day — enforced client-side (so it disappears for visitors even without a rebuild) and at build time (an already-expired notice is omitted from the HTML). An invalid expiry date logs a warning and fails open. Two looks are available via announcement_style: bar (default) — a thin full-width strip that scrolls away below the toolbar — or callout — a boxed in-column notice; both adapt to dark mode and RTL. The banner defaults to empty/off, so existing sites are unaffected. The renderer iterates a list of notices internally so per-page announcements can be added additively later (tracked in #403).
  • translators theme option (#426) — a new translators option, parallel to authors, takes a list of {name, url} entries and renders them in the page header behind a visible label, so translated editions can credit the people who produced them. Authors keep the line directly under the page title and translators sit one row lower, right-aligned on the "Last changed" line and sharing its accent rule, so crediting them costs the header no extra vertical space; on narrow screens the two stack. The label defaults to "Translated by" and is overridable via translators_label so each edition renders it in its own language; authors keep their current label-free rendering, and the matching authors_label defaults to empty, so a site that sets neither renders byte-identical HTML. Either list can also be overridden per page in MyST or notebook front matter, which is how a team-translated edition credits whoever produced each lecture: a page value replaces the project value rather than merging with it, an explicit empty list leaves the block out on that page, and an absent key inherits the project value. Only the documented list-of-mappings form counts as an override, because authors is shared ground — docutils treats it as a bibliographic field and nbformat defines it in the notebook schema — so a page already carrying one written for something else keeps the project credit instead of rendering it badly or losing the byline. Author links now carry rel="author"; translator links deliberately do not, and the two lines carry distinct classes so downstream CSS can tell them apart. Front matter is read from the source file rather than through Sphinx's document metadata, because docutils treats authors as a bibliographic field and returns it in a shape that varies with the language setting — unworkable for a feature whose whole purpose is non-English editions. Part of the cross-theme attribution work tracked in QuantEcon/meta#360.

Fixed

  • A malformed authors value no longer renders one empty link per characterauthors given as a bare string (rather than the documented list of {name, url} entries) was iterated character by character, emitting an empty anchor for each. Both authors and translators now normalise a bare string, a list of strings, or a single mapping into the documented form, and drop entries with no usable name.

Documentation

  • Developer setup troubleshooting for stale .nodeenv — documented the nodeenv-version-mismatch error (an in-repo .nodeenv/ left over from an older pinned Node.js version) and its fix (rm -rf .nodeenv then rebuild), which otherwise blocks tox and editable installs locally. Also clarified that tox keeps the toolchain fully repo-local (.tox/, .nodeenv/, node_modules/ are all git-ignored and regenerated), so nothing is installed into the base/global environment.

CI

  • Regenerated visual baselines are now re-checked in the same run (#358) — the snapshot workflow wrote new baselines and committed them with nothing checking that they were any good. Both jobs now re-run the suite without --update-snapshots against the same built site and report the outcome in the summary comment (it reports rather than gates — the commit still happens, so the images are always there to inspect). The re-run writes to its own test-results-verify/ directory, since Playwright clears its output directory on every run and would otherwise erase the regeneration images that the snapshot-update-diff artifact carries. After /update-new-snapshots the comment deliberately does not attribute a failure to the snapshots just added — that job leaves existing baselines untouched, so the cause may be a baseline the PR legitimately invalidated.
  • The snapshot bot's commit can now trigger CI (#358) — commits pushed with GITHUB_TOKEN don't raise push/pull_request events, so regenerated baselines landed while the PR's visual check still showed its old failure, and the author had to push an empty commit. The workflow now pushes with an optional SNAPSHOT_BOT_TOKEN secret when one is set, falling back to GITHUB_TOKEN otherwise; the summary comment says which happened and what to do next. See docs/developer/visual-testing.md for how to add the secret.
  • /update-snapshots now reads the fixtures pin from the PR branch — GitHub always runs the default branch's copy of a workflow on issue_comment events, so update-snapshots.yml was resolving FIXTURES_SHA from main rather than from the PR under test. A PR that bumps the pin (because it needs a fixtures change to exercise a new feature) therefore regenerated against the old fixtures, produced byte-identical baselines, committed nothing — and still posted "✅ regenerated and committed", leaving the PR's visual job failing with no way to fix it. Both jobs now resolve the pin out of the checked-out branch's ci.yml, falling back to the workflow-level value. Both summary comments also report what actually happened (committed vs. unchanged, and which fixtures commit was built against) instead of unconditionally claiming success, and note that the bot's GITHUB_TOKEN commit does not itself trigger CI.
  • /update-snapshots is now restricted to trusted actors — both jobs check out the PR branch and execute its code (pip install . runs the PR's build backend) with a contents: write token, but had no author-association gate, so anyone able to comment on a PR could trigger that. Both now require OWNER, MEMBER, or COLLABORATOR.
  • CI Node bumped 20 → 24 — Node 20 reached end-of-life in April 2026, and the grouped npm updates in #400 raised engine floors (sass-loader 17 requires Node ≥22.11). Node 24 is the current active LTS (supported to April 2028). Applies to ci.yml, docs.yml, and update-snapshots.yml; .nvmrc and the contributor docs (CONTRIBUTING.md, docs/developer/setup.md) move to Node 24 in step so local dev matches CI.
  • Stabilized flaky mobile-chrome visual tests on math-heavy pages — after the Playwright 1.57→1.60 (Chromium) bump in #400, math/proofs/cross-references full-page screenshots intermittently rendered ~60px shorter than baseline, failing Playwright's dimension check before pixel tolerances apply. waitForReady now waits for document.fonts.ready and polls until the document height holds steady for 750ms, instead of a fixed 500ms sleep after MathJax typesetting.
  • Cleared open Dependabot security alerts via npm audit fixwebpack-dev-server 5.2.2→5.2.4 (GHSA-79cf-xcqc-c78w), shell-quote 1.8.1→1.8.4 (GHSA-w7jw-789q-3m8p, critical), qs 6.14.2→6.15.2 (GHSA-q8mj-m7cp-5q26), ws 8.18.0→8.21.0 (GHSA-58qx-3vcg-4xpx). All transitive dev/build-time only; built theme assets unchanged. The remaining uuid alert (GHSA-w5hq-g745-h8pq) was dismissed as not exploitable — sockjs only calls uuid.v4(), the advisory affects v3/v5/v6 with a caller-provided buf.
  • Dependabot now watches npm — added an npm ecosystem entry to dependabot.yml (monthly, grouped into a single PR) alongside the existing github-actions config.