diff --git a/scripts/sitestarlight.py b/scripts/sitestarlight.py index b146ad0f..60783b53 100644 --- a/scripts/sitestarlight.py +++ b/scripts/sitestarlight.py @@ -1,6 +1,6 @@ """The site as an Astro Starlight project: pages, sidebar and data files. -generate_site.py writes each page body; this module gives it the form +generate_site.py writes each page body, and this module gives it the form Starlight reads. A page's links are written as the docs tree holds them (``../systems/sony.md``, MkDocs' convention, the one a Markdown editor follows), and the site serves them as addresses under /retrobios/, so @@ -397,7 +397,12 @@ def finalize_page( if boost: front["boost"] = boost if rel.startswith(CARD_PAGES): - front["tableOfContents"] = {"minHeadingLevel": 2, "maxHeadingLevel": 2} + sections = len(re.findall(r"^## ", body, re.M)) + # A page of cards under one or two headings has nothing to list, and + # the table of contents watches every block of the page to follow + # the reader: 2 x 430 ms of a phone's main thread on 400 cards. + front["tableOfContents"] = ( + {"minHeadingLevel": 2, "maxHeadingLevel": 2} if sections > 2 else False) if not search: front["pagefind"] = False front["head"] = page_head(rel, level, front["title"], browser_title, structured) diff --git a/website/src/scripts/site.ts b/website/src/scripts/site.ts index d7e9fd97..68a426dc 100644 --- a/website/src/scripts/site.ts +++ b/website/src/scripts/site.ts @@ -131,7 +131,20 @@ const enhanceTables = () => { }, { rootMargin: '400px 0px' }, ); - tables.forEach((table) => observer.observe(table)); + // Every table is measured once the page is drawn and idle, before anything + // is written, so the read finds the layout done instead of forcing it: a + // keyboard reaches a scrolling table anywhere on the page, not only near + // the screen. + const idle = window.requestIdleCallback ?? ((callback: () => void) => setTimeout(callback, 1)); + const start = () => + idle(() => { + // A table in a closed block is not laid out, and measuring it would + // lay it out: it is measured when its block opens. + markScrollable(tables.filter((table) => table.checkVisibility?.() ?? true)); + tables.forEach((table) => observer.observe(table)); + }); + if (document.readyState === 'complete') start(); + else addEventListener('load', start, { once: true }); let timer = 0; addEventListener('resize', () => { clearTimeout(timer); diff --git a/website/tools/check_tools.mjs b/website/tools/check_tools.mjs index 2e843d8b..facb8d79 100644 --- a/website/tools/check_tools.mjs +++ b/website/tools/check_tools.mjs @@ -71,6 +71,9 @@ console.log('glossary term:', await term.textContent(), '=', await term.getAttri // On a phone, a table whose rows end in a download is one block per row. await page.setViewportSize({ width: 390, height: 844 }); await page.goto(`${base}which-pack/`, { waitUntil: 'networkidle' }); +// Tables are set up as they near the screen. +await page.locator('table:has(a[href*="/releases/download/"])').first().scrollIntoViewIfNeeded(); +await page.waitForTimeout(300); const stacked = await page.locator('table[data-rb-stack]').count(); const overflow = await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1); console.log('stacked tables:', stacked, 'page wider than the phone:', overflow); diff --git a/website/tools/lighthouse.py b/website/tools/lighthouse.py index 3c8bbfce..e40ea638 100644 --- a/website/tools/lighthouse.py +++ b/website/tools/lighthouse.py @@ -42,7 +42,9 @@ def main() -> int: ["npx", "--prefix", str(Path(__file__).resolve().parent.parent), "lighthouse", base + page, "--quiet", "--output=json", f"--output-path={report.resolve()}", "--chrome-flags=--headless=new --no-sandbox", - f"--only-categories={','.join(categories)}"], + f"--only-categories={','.join(categories)}", + # Extra flags for one experiment, space separated. + *os.environ.get("LIGHTHOUSE_FLAGS", "").split()], env=env, cwd=out, check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) data = json.loads(report.read_text()) cats, audits = data["categories"], data["audits"]