Conversation
…uilds
The CLI flattens {tableofcontents} into a plain bulleted list: section
titles as bare text list items, entries as "1 Title" (enumerator baked
in, no period). Intercept the toc:project block and rebuild the TOC from
the site manifest instead, where the enumerator is a separate field:
section titles render as real <h2> headings (stable anchor ids, listed in
the On this page outline) inside a nav labelled "Table of contents",
entries as "1. Title", lists bulletless.
Sizes match the live python.quantecon.org toctree, measured 2026-09-14:
links 1.1em (19.8px) at every depth, captions 1.2em serif (21.6px).
The no-thebe fixture gains a nested toc group and the directive on its
landing page; outline.md deliberately stays top-level so its section-only
enumerator expectations in outline-pinned-and-nested keep holding.
New tests: toc-tree unit suite (nesting, index exclusion, id dedupe,
label formatting), front-toc-structure / front-toc-in-outline DOM
assertions, and a front-toc screenshot of the no-thebe landing page.
|
🎭 Visual regression resultsDetails
Skipped testsmobile-chrome › theme.spec.ts › QuantEcon theme — visual regression › without JavaScript › drawer-opens-without-javascript |
…ument the block The item top margin was 0.5rem, 8px against this theme's 16px root where the lecture builds' 0.5rem of an 18px root is 9px; it is now 0.5em. The typography plugin pads every li by 0.375em where the builds' items sit flush, so the li rule zeroes padding-inline-start. Darwin baselines for front-toc.png re-recorded for the two changes. CHANGELOG gains the PR link and UPSTREAM-CANDIDATES the local PR number. docs/layout.md documents the landing-page table of contents and notes that its section titles are listed in "On this page". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mmcky
left a comment
There was a problem hiding this comment.
Thanks @DrDrij, this is a good piece of work: rebuilding from the manifest instead of re-parsing the baked list is the right call, the .heading-text contract with the outline is correctly observed, and the unit coverage is exactly what the tree code needs. I verified the upstream contracts it relies on (data.part === 'toc:project' from the toc transform, the manifest's separate enumerator field, and the outline's main h1..h4 selector), ran typecheck and unit locally, and checked the preview against the live Sphinx sites.
What I pushed to the branch (merge of main plus one commit, no rewrite of your commit):
- Merged
mainto clear theCHANGELOG.mdconflict with #238, and added the PR link the changelog convention wants;UPSTREAM-CANDIDATES.ymlnow sayslocal_pr: 240. - Two list values that missed the builds by a few pixels. The item top margin was
0.5rem, which is 8px against this theme's 16px root, where the builds'0.5remof an 18px root is 9px, so it is now0.5em. And the typography plugin pads everyliby 0.375em (6.75px here) where the builds' items sit flush, so thelirule now zeroespadding-inline-start. Both are instyles/front-toc.csswith the derivation in the comment. - Re-recorded the two
-darwinfront-toc.pngbaselines for those pixel changes. - Documented the block in
docs/layout.md(a short "Landing-page table of contents" section, plus a line under "On this page" saying the TOC's section titles are listed there), since no docs page mentioned it.
One thing for you to decide: the caption size. The comment in front-toc.css says the captions measure 21.6px in serif on python.quantecon.org. I measured the .toctree-wrapper p.caption on python.quantecon.org, python-programming.quantecon.org and julia.quantecon.org today and all three give the same numbers:
| Property | Live Sphinx sites | This PR |
|---|---|---|
| Caption size | 27px (1.5em) | 21.6px (1.2em) |
| Caption font | Source Sans Pro, weight 400 | PT Serif, weight 400 |
| Caption top margin | 27px | 21.6px |
Rendering the caption at the theme's h4 step in PT Serif is a defensible choice, since it keeps the theme's own heading voice rather than the pydata caption's, but the comment presents it as a measurement and it is not one. Either match the builds (1.5em, sans, 1.5em top margin) or keep the serif look and rewrite the comment to give the actual reason. I have left the value and the comment alone so the choice is yours; if you change the size the darwin baselines will need re-recording once more.
Smaller points, your call:
- Each
<section aria-labelledby>is aregionlandmark, so the lpp landing page now has six regions inside the nav and python.quantecon.org would have around ten. That is a lot of landmark noise for screen-reader users, and theh2already gives the section its structure. I would droparia-labelledby(or use a plaindiv). - The directive's
:depth:option survives the transform on the node, but the renderer rebuilds from the full manifest and ignores it. And aurl:entry inproject.tochas no slug, sobuildTocTreewould render it as a section heading rather than an external link. No lecture repo uses either today, so a follow-up issue is fine if you would rather not handle them here. - Note for reviewers: the preview builds lpp's Sphinx
mainwith numbering off, so it exercises the sections and bulletless lists but never the "1. Title" labels. Only the no-thebe fixture test covers those.
Remaining before merge: the -linux baselines for the new screenshot need recording. I will post /update-new-snapshots on this PR once the pushed commit's CI has run, and the refresh commit's gated runs then need approving. Copilot has not reviewed this PR yet, unlike #236, #238 and #239, so a manual review request is worth doing before merge.
|
/update-new-snapshots |
|
🎭 Refreshed visual baselines in d711c81:
|
Summary
The landing page's
{tableofcontents}currently renders as a plain bulleted list: section titles are bare<li>text nodes with a nested list under them, and entries read "1 About These Lectures" — the CLI bakes the enumerator into the text with no period. The existing Sphinx lecture sites render section captions as headings over bulletless lists with "1. Title" entries.This intercepts the
toc:projectblock (the only marker the CLI'sbuildTocTransformleaves) and rebuilds the TOC from the site manifest, whereenumeratoris a separate field — no string surgery on "1 Title" text, so a lecture titled "2008 Financial Crisis" can never be mangled into "2008. Financial Crisis".Rendering
<h2>headings inside<nav aria-label="Table of contents">— a deliberate semantic improvement over the old theme's<p role="heading" aria-level="2">. Each carries a stable, deduplicated anchor id (viacreateHtmlId) and the.heading-textspan, so sections join the "On this page" outline and are deep-linkable. (.exclude-from-outlineremains a one-line opt-out if a quiet outline is preferred.)1. Title— enumerator, period, space, title; pages without an enumerator render as the bare title.1.5emper nested level (logical properties, so RTL mirrors).--qe-link-*tokens; underline on hover/focus-visible only; dark mode inherits the existing white-anchor painting.Files
app/tocTree.ts— pure helpers (nesting, index-page exclusion, id dedupe, labels), unit-testable undernode --test.app/components/ProjectTOC.tsx— the renderer, mirroringContentsSidebar.tsx's manifest access.app/renderers.tsx/app/root.tsx—TOC_RENDERERSwraps the baseblockrenderer (selector keys cannot reachdata.part); every other block delegates to upstream untouched, includingtoc:children/toc:page/toc:section.styles/front-toc.css— imported fromstyles/app.css.fixture-no-thebegains a nested toc group and the directive on its landing page.outline.mddeliberately stays top-level — nesting it switches its heading enumerators to the title-prefixed "2.1." shape and would breakoutline-pinned-and-nested's section-only expectations (commented in the fixture).UPSTREAM-CANDIDATES.yml(project-toc-renderer): upstream myst-theme has no TOC renderer at all.Testing
tests/unit/toc-tree.test.mjs— 10 tests (nesting, index exclusion, duplicate-title id dedupe, "1. Title" formatting, number-leading titles untouched, empty-tree fallback); verified the period test goes red when the period is dropped.theme.spec.ts:front-toc-structure(real<h2>with id in the labelled nav, "1. " label, bare title for un-enumerated pages,list-style-type: none, no self-link),front-toc-in-outline(the section h2 lands in "On this page" with a working anchor), and onefront-toc.pngscreenshot of the no-thebe landing page, pinned to the outline's settled state.mystbuild of lecture-python.myst (light + dark).