From 863b1195280d50b05c7abdea60de07a66d2d03c3 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 10:56:35 +0200 Subject: [PATCH] feat: load tile logos past the first row lazily Home on a phone over 4G: 217.3 KiB to 134.5 KiB on first load, 19 images to 10. --- scripts/generate_site.py | 14 +++++++++----- scripts/sitemarkup.py | 22 ++++++++++++++++------ tests/test_site_r3_entry.py | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/scripts/generate_site.py b/scripts/generate_site.py index b620a626..441ce1ea 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -455,7 +455,7 @@ def _next_block(links: list[str]) -> list[str]: def _tiles(registry: dict, members: list[str], display: dict[str, str], prefix: str = "", - group: str = "") -> list[str]: + group: str = "", eager: int = 0) -> list[str]: """The setup tiles of one device group: logo, name and the hardware it runs on, then the group's other tiles: a kind of device that runs one of the setups (Android handhelds, Linux handhelds).""" @@ -465,13 +465,14 @@ def _tiles(registry: dict, members: list[str], display: dict[str, str], prefix: GUIDES[name].runs_on or _runs_on(registry.get(name, {}), GUIDES[name])) for name in members), *((tile.name, f"{prefix}{tile.link}", "", tile.text) for tile in GROUP_TILES.get(group, ())), - ]) + ], eager=eager) def setup_picker(registry: dict, display: dict[str, str], prefix: str = "") -> list[str]: """Every setup as a tile, under the device group it belongs to. The setups alone in their group share one row: "MiSTer FPGA" above - "MiSTer FPGA" said nothing.""" + "MiSTer FPGA" said nothing. Only the first row of logos loads with the + page: the 19 logos were most of the bytes of the home page.""" lines: list[str] = [] alone: list[str] = [] for group, (label, _description) in DEVICE_GROUPS.items(): @@ -479,9 +480,12 @@ def setup_picker(registry: dict, display: dict[str, str], prefix: str = "") -> l if len(members) == 1 and not GROUP_TILES.get(group): alone += members elif members: - lines += [f"**{label}**", "", *_tiles(registry, members, display, prefix, group)] + eager = 0 if lines else markup.FIRST_ROW_TILES + lines += [f"**{label}**", "", + *_tiles(registry, members, display, prefix, group, eager)] if alone: - lines += ["**Other setups**", "", *_tiles(registry, alone, display, prefix)] + eager = 0 if lines else markup.FIRST_ROW_TILES + lines += ["**Other setups**", "", *_tiles(registry, alone, display, prefix, eager=eager)] return lines diff --git a/scripts/sitemarkup.py b/scripts/sitemarkup.py index 207636bf..f6ae72a8 100644 --- a/scripts/sitemarkup.py +++ b/scripts/sitemarkup.py @@ -190,27 +190,37 @@ def initials(name: str) -> str: return "".join(capitals[:2]) or name[:2].upper() -def _tile_mark(name: str, logo: str) -> str: +def _tile_mark(name: str, logo: str, lazy: bool = False) -> str: + """A tile's logo, or its initials. *lazy* for a tile below the first + screen: the browser fetches its logo when the reader scrolls near it.""" if logo: - return f'' + loading = ' loading="lazy"' if lazy else "" + return (f'') # The same square as a logo, drawn on white like the logos are. return ('') -def platform_tiles(tiles: list[tuple[str, str, str, str]]) -> list[str]: +# Tiles in the first row of a grid at its widest, two columns of 15rem in +# the content column: the logos the reader may see without scrolling. +FIRST_ROW_TILES = 2 + + +def platform_tiles(tiles: list[tuple[str, str, str, str]], eager: int = 0) -> list[str]: """One link per setup: its logo (or its initials), its name and where it - runs. *tiles* are (name, target, logo, runs_on). + runs. *tiles* are (name, target, logo, runs_on). The first *eager* + logos load with the page, the others when the reader scrolls to them. One HTML line: a grid of links is a menu, not prose, and the Markdown around it reads none of it.""" links = "".join( f'' - f"{_tile_mark(name, logo)}" + f"{_tile_mark(name, logo, lazy=index >= eager)}" f'{html.escape(name)}' f'{inline_html(runs_on)}' - for name, target, logo, runs_on in tiles + for index, (name, target, logo, runs_on) in enumerate(tiles) ) return [f'
{links}
', ""] diff --git a/tests/test_site_r3_entry.py b/tests/test_site_r3_entry.py index 7732956a..08aefa5d 100644 --- a/tests/test_site_r3_entry.py +++ b/tests/test_site_r3_entry.py @@ -22,6 +22,7 @@ sys.path.insert(0, str(REPO_ROOT)) import generate_site # noqa: E402 import release_record # noqa: E402 import siteguides # noqa: E402 +import sitemarkup # noqa: E402 from common import load_platform_config, load_platform_registry # noqa: E402 from tests import sitepages # noqa: E402 @@ -270,6 +271,23 @@ class HomeCopy(unittest.TestCase): self.assertTrue(boot.get("hle_fallback")) +class TileLogosLoadWhenSeen(unittest.TestCase): + def test_the_helper(self): + tiles = [(f"S{i}", "x.md", f"{i}.png", "here") for i in range(4)] + html = "".join(sitemarkup.platform_tiles(tiles, eager=2)) + logos = re.findall(r"]*>", html) + self.assertEqual(['loading="lazy"' in logo for logo in logos], [False, False, True, True]) + self.assertNotIn("loading=", "".join(sitemarkup.platform_tiles(tiles[:1], eager=1))) + + def test_only_the_first_row_is_eager_on_entry_pages(self): + for name in ("index.md", "which-pack.md"): + logos = re.findall(r']*>', _page(name)) + with self.subTest(page=name): + self.assertGreater(len(logos), sitemarkup.FIRST_ROW_TILES) + eager = [logo for logo in logos if 'loading="lazy"' not in logo] + self.assertEqual(eager, logos[: sitemarkup.FIRST_ROW_TILES]) + + class DownloadLine(unittest.TestCase): def test_checksums_and_signature_read_as_two(self): record = release_record.load_record()