Skip to content

fix(options): declare every site option the theme reads, so they reach it - #194

Merged
mmcky merged 2 commits into
mainfrom
fix/declare-site-options
Sep 10, 2026
Merged

mmcky merged 2 commits into
mainfrom
fix/declare-site-options

Conversation

@mmcky

@mmcky mmcky commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Closes #173. First step of the remaining #147 sequence: both #92 (meta/SEO) and #114 (the per-lecture live-compute flag) need declared options, and #114's page flag would have collided with the undeclared git_metadata override.

What was wrong

The MyST CLI validates site.options against the template's declarations and drops every key the template does not declare. Until #174 this theme declared nothing; since then only the six multilingual options. So twitter, favicon, analytics_google, analytics_plausible, hide_toc, hide_search and the five launch_* keys were read by the theme but never arrived from myst.yml. Verified before the change: the fixture's site.options reached config.json with only the six declared keys.

What changes

template.yml declares every option the theme reads (18 in total), grouped and described, with no defaults. The four keys typed but never read anywhere (hide_outline, hide_title_block, hide_footer_links, outline_maxdepth) are removed from app/types.ts rather than declared as knobs that do nothing. logo_text, which the fixtures set and nothing reads, is dropped from the fixtures.

git_metadata decision. The page-level override is declared as a string holding a YAML block, the same form #174 used for languages and translators, and PageHeaderHistory parses it with the existing parseStructured (an object still passes through, so older content keeps working). This was the open question in the issue. The alternative, moving the override into the AST data the plugin writes, would have needed the plugin to read page frontmatter and is a plugin-repo change now that the plugin is moving to QuantEcon/quantecon-plugins.mystmd; declaring it keeps the override a theme contract. The fixture's features page now sets git_metadata and a declared key (hide_search) on the same page, which is exactly the case that used to lose the override silently.

favicon had a second blocker. With the option declared the CLI copies the file and rewrites the path correctly (measured: /cc-by-sa-4.0-80x15-<hash>.png, served by the content server as image/png), but the theme still returned a 32×32 PNG as image/x-icon: a static public/favicon.ico was served ahead of the [favicon.ico] route on every request, so neither the option nor the mystmd fallback was ever reachable. That file is byte-identical to the Sphinx lectures' _static/lectures-favicon.ico, so it is the right default and moves to public/logos/lectures-favicon.png; getFavicon serves it from disk when no option is set and fetches the configured file otherwise.

Verification

A new site-options test (desktop-chrome) asserts end to end that a declared site-wide option reaches the rendered page (twitter:creator="@quantecon"), that /favicon.ico on the main fixture is byte-for-byte the configured PNG, and that /favicon.ico on the no-thebe fixture (no option) is byte-for-byte the lectures favicon. The page-level path is covered by the existing history-open snapshot, which only renders because the features page's git_metadata block now survives validation beside a declared key. Full local suite: 37 passed, no visual baseline moved; npm run compile, the 27 unit tests and the plugin end-to-end test pass.

One thing surfaced for #92 rather than fixed here: pages emit twitter:creator but not twitter:site, because the root route's meta (where twitter:site lives) is replaced, not merged, by the article route's meta under Remix v2 semantics. The test asserts the tag pages actually render and says so in a comment.

Docs

README gains a "Site options" section with the full table and scope of each option, the git-history section documents the block-string override form, and the CHANGELOG has entries under Unreleased.

🤖 Generated with Claude Code

…h it

The MyST CLI validates `site.options` against template.yml and drops every
key the template does not declare, and only the six multilingual options
were declared. `twitter`, `favicon`, `analytics_google`,
`analytics_plausible`, `hide_toc`, `hide_search` and the five `launch_*`
keys were read by the theme but never arrived from myst.yml. All are
declared now, with no defaults (a declared default is written into every
page's validated `site:` block and overrides the site-wide value); the
four keys the theme never read (`hide_outline`, `hide_title_block`,
`hide_footer_links`, `outline_maxdepth`) are dropped from its types
instead of being declared as dead knobs.

The page-level `git_metadata` override is declared too, as a string
holding a YAML block (template options are scalar-only), parsed by
PageHeaderHistory; an object still works. Undeclared, it survived only
because the CLI leaves a page's raw `site:` block alone when nothing in
it validates, so any page that also set a declared key lost it silently.
The fixture's features page now sets both, which is the regression case.

`favicon` had a second blocker: a static public/favicon.ico, served ahead
of the `[favicon.ico]` route, shadowed the option and the fallback alike.
It is the QuantEcon lectures favicon (byte-identical to the Sphinx sites'),
so it moves to public/logos/ and becomes the route's default; a configured
favicon is fetched from the content server as the CLI copied it.

A `site-options` test asserts end to end that a declared option reaches
the rendered page (`twitter:creator`), that the configured favicon is
served byte for byte, and that the default is served when unset.

Closes #173

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-10 11:38 UTC

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

🎭 Visual regression results

passed  35 passed
skipped  6 skipped

Details

stats  41 tests across 2 suites
duration  1 minute, 5 seconds
commit  8d56a86

Skipped tests

mobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › without JavaScript › drawer-opens-without-javascript
mobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › drawer-closes-when-search-opens
mobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › launch-colab
mobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › live-compute-toggle
mobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › live-compute-toggle-absent-without-thebe
mobile-chrome › theme.spec.ts › Site options reach the theme (#173) › site-options

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

A few blocking issues remain around changelog convention compliance (missing PR links) and defensive robustness/performance concerns identified in the updated favicon and git-metadata parsing paths.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes a theme contract gap with the MyST CLI by declaring all site.options keys the theme reads in template.yml, ensuring those options aren’t silently dropped during validation. It also unblocks favicon configuration by removing the static-file shadowing behavior and adds an end-to-end visual test to prove options flow through to rendered output.

Changes:

  • Declare all theme-consumed site.options in template.yml (including scalar-YAML-block workarounds for structured data like git_metadata).
  • Make favicon effective by serving a default favicon via the /favicon.ico route when unset, and fetching the configured file when set.
  • Add a Playwright visual test asserting that declared options (twitter + favicon) reach the rendered page and that favicon bytes match expected fixtures.
File summaries
File Description
tests/visual/theme.spec.ts Adds an end-to-end “site options reach the theme” assertion (twitter meta + favicon bytes).
tests/visual/fixture/myst.yml.in Sets declared twitter and favicon options for the main visual fixture.
tests/visual/fixture/features.md Converts site.git_metadata override to YAML-block-string form and adds a declared per-page key alongside it.
tests/visual/fixture-rtl/myst.yml.in Removes unused logo_text from RTL fixture options.
tests/visual/fixture-no-thebe/myst.yml.in Removes unused logo_text from no-thebe fixture options.
template.yml Declares all options the theme reads; documents scalar-only limitation and the “no defaults” rule.
README.md Documents the full site-options surface and the YAML-block-string override form for git_metadata.
public/logos/lectures-favicon.png Adds the new default favicon asset used when favicon is unset.
plugins/git-metadata.mjs Updates documentation to match the new declared-option scalar/YAML-block-string requirement.
CHANGELOG.md Adds Unreleased entries describing the options + favicon + git_metadata behavior changes.
app/types.ts Aligns TS option typing with declared template options; removes previously-typed-but-unused layout knobs.
app/components/PageHeaderHistory.tsx Parses site.git_metadata via parseStructured and validates basic shape before use.
app/backend/loaders.server.ts Implements favicon defaulting and fetch logic when configured via declared favicon option.
Review details

Suppressed comments (2)

CHANGELOG.md:42

  • This new Unreleased entry links only to the issue; CONTRIBUTING.md requires linking each changelog entry to the PR as well, so readers can find the actual change diff.
  the CLI copied it ([#173](https://github.com/QuantEcon/quantecon-theme.mystmd/issues/173)).

CHANGELOG.md:49

  • This new Unreleased entry links only to the issue; CONTRIBUTING.md requires linking each changelog entry to the PR as well, so readers can find the actual change diff.
  ([#173](https://github.com/QuantEcon/quantecon-theme.mystmd/issues/173)).
  • Files reviewed: 12/13 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread app/backend/loaders.server.ts
Comment thread app/components/PageHeaderHistory.tsx
Comment thread CHANGELOG.md Outdated
Copilot review on #194: the default favicon is read from disk once and
cached rather than on every request; the parsed git_metadata override
keeps only changelog entries the renderer can use (string hash and date);
and the three changelog entries link the PR as CONTRIBUTING requires.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mmcky
mmcky merged commit 9cafa7a into main Sep 10, 2026
4 checks passed
@mmcky
mmcky deleted the fix/declare-site-options branch September 10, 2026 11:38
mmcky added a commit that referenced this pull request Sep 10, 2026
Moves the Unreleased entries under 2.7.0 (#194, #196, #197, #198, #191),
adds the missing #191 PR link, bumps package.json and the two README pins.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Every undeclared site.options key is dropped by the CLI, so twitter and launch_* never reach the theme

2 participants