diff --git a/scripts/generate_site.py b/scripts/generate_site.py index df4b4a93..21588d04 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -2205,6 +2205,7 @@ def decorate_markdown_pages(docs: Path) -> dict[str, str]: description=description, structured=structured, terms=terms, search=authored.get("search") != "exclude", logo=str(authored.get("logo") or ""), + parent=authored.get("parent"), ) write_decorated(docs / target, text) # One file per page: a page that gained or lost its components @@ -7509,12 +7510,19 @@ def _emulator_nav(profiles: dict) -> list: def _system_nav(manufacturers: dict) -> list: - """Manufacturer pages, the machines apart from the game and engine trees.""" - machines, games = [], [] + """Manufacturer pages, the machines apart from the arcade boards and the + game and engine trees: an arcade page's crumb read "Consoles and + computers".""" + machines, arcade, games = [], [], [] for mfr in sorted(manufacturers, key=str.casefold): entry = {mfr: f"systems/{_slug(mfr)}.md"} - (games if mfr in GAME_DATA_TOPS else machines).append(entry) + if mfr in GAME_DATA_TOPS: + games.append(entry) + else: + (arcade if mfr == "Arcade" else machines).append(entry) nav: list = ["systems/index.md", {"Consoles and computers": machines}] + if arcade: + nav.append({"Arcade": arcade}) if games: nav.append({"Game engines and PC games": games}) return nav @@ -7904,6 +7912,20 @@ def _generate(args: argparse.Namespace) -> None: if stem in coverages: raise RuntimeError(f"a system page takes the platform {stem}'s address") PART_PAGES.add(f"platforms/{stem}.md") + # One console of one setup's list, a reference: "playstation + # bios" found five setups' lists before the console's page. + # Weighed down, they still won on their title, which the page + # weight does not reach, and their file list is already kept out + # of the index: the title alone, found again on the setup's page + # and the console's, is all the search held of them. + SEARCH_DEMOTED.add(f"platforms/{stem}.md") + front = _front_matter(page) + if front: + page = page[page.find("\n---\n", 4) + 5:].lstrip("\n") + front.update(level="reference", search="exclude", + parent={"label": cov["platform"], "link": f"{name}.md"}) + page = "---\n" + yaml.safe_dump(front, sort_keys=False, allow_unicode=True) \ + + "---\n\n" + page write_if_changed(str(docs / "platforms" / f"{stem}.md"), page) PAGE_DATA[f"platforms/{name}.md"] = platform_structured_data(name, cov) diff --git a/scripts/sitestarlight.py b/scripts/sitestarlight.py index 0b10e2f0..5623c57b 100644 --- a/scripts/sitestarlight.py +++ b/scripts/sitestarlight.py @@ -368,6 +368,17 @@ def split_title(markdown: str) -> tuple[str, str, str]: _CARD_NAME = re.compile(r']*class="rb-file-title"(?![^>]*data-pagefind-ignore)[^>]*>([^<]+)') +def search_field(key: str, words: list[str]) -> str: + """A search field of the page, held in an attribute of an empty + element: the text of an element is indexed and shown as the result's + excerpt (a run of 250 file names). Pagefind splits several fields at a + comma, so a value carries none.""" + value = " ".join(word.replace(",", " ") for word in words).strip() + if not value: + return "" + return f'\n\n' + + def file_names_meta(body: str) -> str: """The names of the files a system page holds cards for, as a search field of the page. A page of 250 cards is long, and the search weighs a @@ -375,9 +386,35 @@ def file_names_meta(body: str) -> str: after every short page citing the name. The field is weighted in the site's ranking (astro.config.mjs, metaWeights.files).""" names = sorted({unescape(name) for name in _CARD_NAME.findall(body)}) - if not names: - return "" - return f'\n\n' + return search_field("files", names) + + +# systems/ page -> the platforms' own ids for the consoles it holds, built +# on the first system page, once the generator has installed the sections. +_page_aliases: dict[str, list[str]] = {} +_page_aliases_built = [False] + + +def page_aliases(rel: str) -> list[str]: + """The names the platforms file the consoles of a system page under + (psx, dreamcast, gba), from siterender.system_search_aliases(): "psx + bios" finds the PlayStation page though the page never says psx.""" + if not _page_aliases_built[0]: + import siterender + + by_page: dict[str, set[str]] = {} + for sys_id in list(siterender._system_page_map): + section = siterender.system_section(sys_id) + names = siterender.system_search_aliases(sys_id) + if not section or not names: + continue + target = siterender.console_href(*section).partition("#")[0] + by_page.setdefault(urllib.parse.unquote(target), set()).update(names) + _page_aliases.clear() + _page_aliases.update({page: sorted(names, key=str.casefold) + for page, names in by_page.items()}) + _page_aliases_built[0] = bool(siterender._system_page_map) + return list(_page_aliases.get(rel, [])) _NEXT_STEPS = re.compile(r"^## Next steps\b[^\n]*\n+(?P(?:[ \t]*[-*] .*\n?)+)", re.M) @@ -407,9 +444,12 @@ def finalize_page( terms: dict[str, str], search: bool = True, logo: str = "", + parent: dict | None = None, ) -> tuple[str, str]: """The Starlight file for a page body: its path under the content - collection and its text.""" + collection and its text. *parent* ({label, link}, the link written + relative to the page) is the page a part page belongs to: the route + middleware makes it the last crumb and marks it in the sidebar.""" title, title_id, body = split_title(markdown) body = body.lstrip("\n") body = rewrite_links(body, rel) @@ -427,7 +467,7 @@ def finalize_page( body = re.sub(r'