From 7f951f4c58fec8f82b152b3eff1e8706ec63732c Mon Sep 17 00:00:00 2001 From: The Anh Nguyen Date: Fri, 24 Jul 2026 08:32:36 +0700 Subject: [PATCH] fix(print): flex-fallback grids with a grid-heading for WeasyPrint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WeasyPrint mis-sizes 1fr grid tracks when a full-width spanning grid-heading (grid-column: 1 / -1) is present, collapsing sibling cards to near-zero width — metric/ecosystem layouts render as narrow columns with text wrapping one character per line in the PDF. Fall back to flexbox for .grid:has(> .grid-heading) in @media print only; grids without a grid-heading keep the CSS grid path, and screen rendering is unchanged. Signed-off-by: The Anh Nguyen --- src/slidr/render/templates/base.css | 14 ++++++++++++++ tests/test_html.py | 17 ++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/slidr/render/templates/base.css b/src/slidr/render/templates/base.css index 8f3aa02..6776338 100644 --- a/src/slidr/render/templates/base.css +++ b/src/slidr/render/templates/base.css @@ -429,6 +429,20 @@ section[data-transition]:not([data-transition="none"]).outgoing { max-height: none; overflow: visible; } + + /* WeasyPrint mis-sizes 1fr grid tracks when a full-width spanning + grid-heading (grid-column: 1 / -1) is present, collapsing the + sibling cards to near-zero width. Fall back to flexbox for these + grids in print only; grids without a grid-heading are untouched. */ + .grid:has(> .grid-heading) { + display: flex !important; + flex-wrap: wrap; + align-items: flex-start; + gap: var(--gap); + } + .grid:has(> .grid-heading) > .grid-heading { flex: 0 0 100%; } + .grid:has(> .grid-heading) > .card:not(.grid-heading) { flex: 1 1 0; min-width: 0; } + .grid:has(> .grid-heading) > .card.side-image { flex: 0 0 auto; } } @page { diff --git a/tests/test_html.py b/tests/test_html.py index ab8c328..ae2a8f2 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -1,9 +1,24 @@ """Tests for the HTML renderer's element rendering.""" -from slidr.render.html import _render_elem +from slidr.render.html import _render_elem, base_css from slidr.render.ir import Elem +def test_print_css_flexes_grids_with_a_grid_heading(): + """Print stylesheet falls back to flexbox for grids with a grid-heading. + + WeasyPrint mis-sizes `1fr` grid tracks when a full-width spanning + grid-heading (`grid-column: 1 / -1`) is present, collapsing the sibling + cards to near-zero width. The print CSS must convert those grids to + flexbox; grids without a grid-heading must stay on the grid path. + """ + css = base_css() + assert ".grid:has(> .grid-heading)" in css + assert ".grid:has(> .grid-heading) > .grid-heading" in css + # The grid-heading spans a full row in the flex fallback. + assert "flex: 0 0 100%" in css + + def test_speaker_linkedin_uses_brand_svg_not_placeholder(): """linkedin= renders the inlined brand mark, never a Lucide placeholder.