Draw the sample's pane divider only between panes that show
.site-pane + .site-pane still matches a pane whose neighbour site.js has hidden: a hidden element is a sibling all the same. So every pane after Overview, shown alone, opened with a 24px gap, 20px of padding and a rule, an empty band above its heading that Overview did not have. The divider is for the page with no script, where every pane shows one under the next, so it now names a shown pane on both sides and keeps that page as it was. The new browser test shows each pane alone at 1280 and 390 and holds both its offset down the column and its heading's offset inside it to Overview's: a margin moves the first and padding the second. Against the old rule it failed for all four panes at both widths (40px down the column with the heading 21px in, against Overview's 16 and 0). It passes now, beside TestTheLandingReadsWithNoScript and TestEverySamplePaneAndCourseSwitches. Its weight is a guess from its docs-t1 time, level with the pane-switching test's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 files changed,
+51
−1
hack/test-weights.txt+1 −0internal/www/landing_browser_test.go+44 −0site/static/site.css+6 −1
Intent
diff --git a/hack/test-weights.txt b/hack/test-weights.txt| index 4fd6d11..059b1fc 100644 |
| --- a/hack/test-weights.txt |
| +++ b/hack/test-weights.txt |
| @@ -207,6 +207,7 @@ browser internal/www TestTheLandingReadsWithNoScript 8 |
| browser internal/www TestTheSiteServesFromItsOwnOrigin 8 |
| browser internal/www TestReducedMotionIgnoresScrolling 7 |
| browser internal/www TestEverySamplePaneAndCourseSwitches 7 |
| +browser internal/www TestEverySamplePaneStartsLikeTheFirst 7 |
| browser internal/www TestTheBuntingFollowsTheTheme 7 |
| browser internal/www TestTheSampleSwitchDrags 7 |
| browser internal/www TestTheStillBuntingMatchesTheMovingOne 7 |
diff --git a/internal/www/landing_browser_test.go b/internal/www/landing_browser_test.go| index 071c725..3fa9705 100644 |
| --- a/internal/www/landing_browser_test.go |
| +++ b/internal/www/landing_browser_test.go |
| @@ -724,6 +724,50 @@ func TestEverySamplePaneAndCourseSwitches(t *testing.T) { |
| rig.Screen("#pane-guests", "the Guests pane") |
| } |
| +// paneTopJS measures the pane that is showing: where it starts below |
| +// the top of the column that holds every pane, and where its heading |
| +// starts below the pane's own top. Both, because a gap above a pane |
| +// can be its margin, outside its box, or its padding, inside it. |
| +const paneTopJS = `(() => { const p = [...document.querySelectorAll("#sample .site-pane")].find(p => p.getClientRects().length > 0), c = p.parentElement.getBoundingClientRect(), r = p.getBoundingClientRect(), h = p.querySelector("h2").getBoundingClientRect(); |
| + return JSON.stringify({ID: p.id, Pane: r.top - c.top, Heading: h.top - r.top}); })()` |
| + |
| +// TestEverySamplePaneStartsLikeTheFirst: each sample pane, shown on its |
| +// own, starts its heading as high in the window as Overview does, on a |
| +// desktop and on a phone. A divider written between neighbouring panes |
| +// still matches when the pane before is hidden, which drew a gap and a |
| +// rule above every pane but the first. |
| +func TestEverySamplePaneStartsLikeTheFirst(t *testing.T) { |
| + rig, _ := siteRig(t) |
| + ctx, cancel := context.WithTimeout(rig.Context(), 2*time.Minute) |
| + defer cancel() |
| + type top struct { |
| + ID string |
| + Pane, Heading float64 |
| + } |
| + for _, w := range []int64{1280, 390} { |
| + open(t, ctx, rig, w, 900) |
| + mustRun(t, ctx, soon(".site-themebar")) |
| + var first top |
| + at(t, ctx, paneTopJS, &first) |
| + if first.ID != "pane-overview" { |
| + t.Fatalf("at %d the sample opens on %s; want pane-overview", w, first.ID) |
| + } |
| + for _, id := range []string{"pane-guests", "pane-menu", "pane-music", "pane-settings"} { |
| + showPane(t, ctx, id) |
| + var got top |
| + at(t, ctx, paneTopJS, &got) |
| + if got.ID != id { |
| + t.Fatalf("at %d, after pressing %s the sample shows %s", w, id, got.ID) |
| + } |
| + if math.Abs(got.Pane-first.Pane) > 0.5 || math.Abs(got.Heading-first.Heading) > 0.5 { |
| + t.Errorf("at %d, %s starts %.0fpx down its column with its heading %.0fpx below that; Overview starts at %.0f with its heading at %.0f", |
| + w, id, got.Pane, got.Heading, first.Pane, first.Heading) |
| + } |
| + } |
| + rig.Screen("#pane-settings", fmt.Sprintf("the last pane at %d", w)) |
| + } |
| +} |
| + |
| // liveText is the text of the live region inside sel. |
| func liveText(t *testing.T, ctx context.Context, sel string) string { |
| t.Helper() |
diff --git a/site/static/site.css b/site/static/site.css| index 0122c5f..2294419 100644 |
| --- a/site/static/site.css |
| +++ b/site/static/site.css |
| @@ -62,7 +62,12 @@ |
| holds them. */ |
| .site-pane { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-content: start; } |
| .site-pane[hidden] { display: none; } |
| -.site-pane + .site-pane { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--rst-line); } |
| +/* With no script every pane shows, one under the next, and a rule |
| + divides them. A hidden pane is still a sibling, so the divider names |
| + shown panes on both sides: written as .site-pane + .site-pane it |
| + drew a gap and a rule above every pane but the first when site.js |
| + showed it alone. */ |
| +.site-pane:not([hidden]) ~ .site-pane:not([hidden]) { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--rst-line); } |
| .site-pane h2 { margin: 0; font-size: 1.05rem; } |
| .site-pane h3 { margin: 0 0 4px; font-size: 0.95rem; } |
| .site-pane p { margin: 0; font-size: 0.85rem; color: var(--rst-text-muted); } |