Skip to content

feat(seo): full OpenGraph/Twitter set, collapsible stderr, docs reference (Phase 6) - #197

Merged
mmcky merged 4 commits into
mainfrom
feat/phase-6-meta-docs
Sep 10, 2026
Merged

mmcky merged 4 commits into
mainfrom
feat/phase-6-meta-docs

Conversation

@mmcky

@mmcky mmcky commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Closes #92, Phase 6 of the book-theme parity plan and the last build item on the #147 gate besides #182 (PR #196). Three parts, as PLAN.md scopes the phase.

Meta / SEO

Measured against python-programming.quantecon.org, the Sphinx sites emit og:title, og:type, og:url, og:image, og:description, og:site_name and twitter:card, twitter:site, twitter:creator, twitter:title, twitter:description, twitter:image. Upstream's getMetaTagsForArticle covers about half. app/seo.ts adds the rest on top and replaces same-key upstream tags rather than duplicating them:

Tag Source
og:type website, as on every Sphinx lecture page
og:site_name the site title
og:url a new site_url option plus the page path (base URL included)
og:image / twitter:image the page thumbnail, else new og_logo_url / twitter_logo_url options, the book theme's names so a lecture repo copies its _config.yml values across
twitter:site the twitter option; upstream emits it only from the root route's meta, which the article route's replaces under Remix v2 semantics, so it had never rendered
og:locale current_language (Phase 4)

Why site_url and not site.domains. domains is the natural myst key, and it is validated and stored, but the site manifest the CLI hands the theme does not carry it (verified on the built fixture's config.json). The option is the Sphinx sites' html_baseurl equivalent; domains remains a fallback in the helper should the manifest ever include it.

Collapsible stderr

PLAN.md asked to verify before porting: upstream renders a stderr stream as a plain <pre class="jupyter-error">. The Sphinx build's stderr-warnings.js folds it after page load with DOM surgery; here STDERR_RENDERERS wraps the stderr output node in a native <details> at render, closed by default, with the book theme's amber styling, so the fold holds in the server-rendered HTML with no script and survives re-renders. Stdout and results in the same cell stay visible.

Docs

A docs/ reference with one page per book-theme docs/user/* page (configuration, layout, authors, launch, notebooks, git metadata, code highlighting, text colour schemes, dark mode, RTL and editions, announcements, and features/stderr-warnings), each naming its myst.yml keys and saying plainly what has no counterpart and why (the announcement banner, the alternative code palettes, the collapse of outline sub-entries).

Tests

social-meta asserts the full set on the no-thebe fixture, which gains site_url, twitter and both logo URLs, and checks og:image and twitter:card appear once each. stderr-collapsed asserts the fold is closed by default, stdout stays visible, and it opens on click; the no-thebe notebook gains a cell with stderr and stdout streams. Six unit tests cover origin, locale, the tag set and the merge. Full local suite: 36 passed on the first run plus the three re-run after two test fixes; no baseline moves (all fixture changes are on the snapshot-free no-thebe project).

Merge after #196. The two touch different files, but docs/layout.md and docs/dark-mode.md describe the pinned, collapsing outline that #196 delivers, so this lands second.

🤖 Generated with Claude Code

…ence

Phase 6 of the book-theme parity plan.

Meta tags: app/seo.ts adds, on top of upstream's article tags, what the
Sphinx lecture sites emit and upstream leaves out -- og:type,
og:site_name, og:url (from a new `site_url` option; myst's `site.domains`
never reaches the theme's manifest), a site-level og:image /
twitter:image when the page has no thumbnail (`og_logo_url` /
`twitter_logo_url`, the book theme's names, so a lecture repo copies its
values across), twitter:site (upstream puts it in the root route's meta,
which the article route's replaces under Remix v2 semantics, so it never
rendered) and og:locale from current_language. Same-key upstream tags
are replaced, not duplicated.

Collapsible stderr: upstream renders a stderr stream as a plain <pre>;
verified, and ported as a native <details> around the stderr `output`
node (STDERR_RENDERERS, layered after JUPYTER_RENDERERS) rather than the
Sphinx build's post-load DOM surgery, so the fold holds in the
server-rendered HTML with no script. Styled in the book theme's amber.

Docs: a docs/ reference with one page per book-theme user page
(configuration, layout, authors, launch, notebooks, git metadata, code
highlighting, text colour schemes, dark mode, RTL and editions,
announcements, the stderr fold), each naming its myst.yml keys and what
has no counterpart.

Tests: `social-meta` asserts the full set on the no-thebe fixture, which
gains site_url, twitter and both logo URLs; `stderr-collapsed` asserts
the fold is closed by default, stdout stays visible, and it opens. Six
unit tests cover the helpers. No baseline moves.

Closes #92

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 10, 2026 12:17
@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 22:29 UTC

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

🎭 Visual regression results

passed  40 passed
skipped  11 skipped

Details

stats  51 tests across 2 suites
duration  1 minute, 19 seconds
commit  b6a42e0

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 › On this page outline (#182) › outline-pinned-and-nested
mobile-chrome › theme.spec.ts › On this page outline (#182) › outline-tracks-scroll
mobile-chrome › theme.spec.ts › On this page outline (#182) › outline-unnumbered
mobile-chrome › theme.spec.ts › Meta/SEO and notebook output polish (#92) › social-meta
mobile-chrome › theme.spec.ts › Meta/SEO and notebook output polish (#92) › stderr-collapsed
mobile-chrome › theme.spec.ts › Site options reach the theme (#173) › site-options

Matches the autoexpand behaviour #196 now ships.

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

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.

🔵 Needs a closer look

It changes SEO meta output on every page and the notebook output render path, and the new docs describe outline behavior that only lands in the separate, unmerged PR #196, so merge ordering and final sign-off warrant human review.

Pull request overview

This PR implements Phase 6 of the book-theme parity plan (#92): the full OpenGraph/Twitter meta-tag set, a collapsible stderr fold on notebook cells, and a docs/ feature reference. It builds on the declared-options path (#173/#194): a new app/seo.ts helper layers og:type, og:site_name, og:url (from a new site_url option), site-level og:image/twitter:image (og_logo_url/twitter_logo_url), twitter:site and og:locale on top of upstream's getMetaTagsForArticle, merged via mergeMeta so same-key upstream tags are replaced rather than duplicated. A STDERR_RENDERERS override wraps the upstream output renderer, folding stderr streams in a native <details> at render time. I verified the SEO merge logic and the OUTPUT_RENDERERS.output/jupyter_data shape against @myst-theme 1.3.0 upstream source, and confirmed the documented defaults (git-metadata max 6, back-to-top 80px, launcher defaults) match the code.

Changes:

  • Add app/seo.ts (origin/locale/tag-merge helpers) and wire it into both route meta functions on top of upstream article tags.
  • Add STDERR_RENDERERS wrapping the Jupyter output renderer to fold stderr in a <details>, with .qe-stderr styling; new site_url/og_logo_url/twitter_logo_url options in template.yml/types.ts.
  • Add a docs/ reference set, unit tests (seo.test.mjs), visual tests, and a fixture cell; update README/PLAN/CHANGELOG.
File summaries
File Description
app/seo.ts New SEO helper: origin resolution, BCP-47→OG locale, tag set, merge
app/routes/$.tsx, _index.tsx Wire socialMetaTags/mergeMeta into article + index meta
app/renderers.tsx STDERR_RENDERERS wraps upstream output in a <details> fold
app/root.tsx Register STDERR_RENDERERS after JUPYTER_RENDERERS
app/types.ts, template.yml Declare site_url/og_logo_url/twitter_logo_url options
styles/quantecon.css .qe-stderr amber fold styling (light + dark)
tests/unit/seo.test.mjs, tests/visual/theme.spec.ts Unit + visual coverage for the tag set and the fold
tests/visual/fixture-no-thebe/* Fixture cell (stderr+stdout) and site.options for the tests
docs/*, README.md, PLAN.md, CHANGELOG.md Parity docs and record updates
Review details
  • Files reviewed: 28/28 changed files
  • Comments generated: 2
  • Review effort level: Balanced

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

Comment thread CHANGELOG.md Outdated
Comment thread docs/layout.md Outdated
Copilot review on #197: each Unreleased entry links its PR.

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

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.

🔵 Needs a closer look

It changes server-rendered social meta on every page and overrides a core jupyter output renderer, and several docs intentionally describe outline behavior that only lands once the separate PR #196 merges first, so human verification of the merge ordering and site-wide rendering is warranted.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

README.md:242

  • This table row states both og_logo_url and twitter_logo_url are used "when a page has no thumbnail", but that is only accurate for og_logo_url. In app/seo.ts, twitterImage = options?.twitter_logo_url || image, so twitter_logo_url takes precedence over a page thumbnail for twitter:image (confirmed by tests/unit/seo.test.mjs where a /thumb.png page image still yields twitter:image = https://x/tw.png). A maintainer reading this row may not expect the configured Twitter logo to override page thumbnails. Consider clarifying the two behaviours separately.
  • Files reviewed: 28/28 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Brings in #196 (pinned outline). Two add/add conflicts, both kept in
full: styles/quantecon.css (the `.qe-outline*` rules from main, then
the `.qe-stderr` rules from this branch) and tests/visual/theme.spec.ts
(the "On this page outline (#182)" describe from main, then the
"Meta/SEO and notebook output polish (#92)" describe from this branch).
The no-thebe fixture config, CHANGELOG and PLAN auto-merged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mmcky
mmcky merged commit 164b1fe into main Sep 10, 2026
4 checks passed
@mmcky
mmcky deleted the feat/phase-6-meta-docs branch September 10, 2026 22:29
mmcky added a commit that referenced this pull request Sep 10, 2026
`live_compute` read as a setting that might take a mode value, and a name
with "browser" or "pyodide" in it was considered and rejected because the
gate wraps whichever backend `project.thebe` configures (lite, binder or
server). `enable_live_compute` keeps the `enable_` prefix the option table
already uses (`enable_rtl`), so it is visibly a boolean, and keeps "live
compute", the term the README, changelog and header control already use.

Also documents the option in the docs/ feature reference that landed in
main via #197, and drops the "Phase 4" label from the changelog entry: this
is not a parity-plan item (mmcky, PR #195 discussion), and Copilot noted
that Phase 4 is internationalisation in any case.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.

Phase 6 — Meta/SEO + notebook-output polish

2 participants