History

Fit the empty Toolkits grid to the viewport (#1897)

yingchao committed 2 months ago

Commit f1930dd1 parent c7af9bb3 files · +63 −9Browse files

Unified · Split

3 files
  1. .changeset/toolkits-empty-grid.md +5 −0
  2. e2e/selfhost/toolkits-empty-grid.test.ts +56 −0
  3. packages/plugins/toolkits/src/page.tsx +2 −9
.changeset/toolkits-empty-grid.md+5−0
@@ -0,0 +1,5 @@
1+---
2+"executor": patch
3+---
4+
5+Prevent the empty Toolkits page from scrolling past its visible add cards.
e2e/selfhost/toolkits-empty-grid.test.ts+56−0
@@ -0,0 +1,56 @@
1+// An empty Toolkits grid must fit the viewport: with no toolkits in either
2+// scope, both the Workspace and Personal add cards sit above the fold and the
3+// grid does not scroll. Regression: each shelf reserved a fixed ~3-row
4+// min-height, so two empty shelves stacked past the viewport and the page
5+// scrolled with nothing to see.
6+import { expect } from "@effect/vitest";
7+import { Effect } from "effect";
8+
9+import { scenario } from "../src/scenario";
10+import { Browser, Target } from "../src/services";
11+import { visit } from "../src/surfaces/browser";
12+
13+scenario(
14+ "Toolkits · empty grid fits the viewport without scrolling",
15+ { timeout: 120_000 },
16+ Effect.gen(function* () {
17+ const target = yield* Target;
18+ const browser = yield* Browser;
19+ const identity = yield* target.newIdentity();
20+
21+ yield* browser.session(identity, async ({ page, step }) => {
22+ await step("Open the Toolkits page with no toolkits in either scope", async () => {
23+ await visit(page, "/default/toolkits/");
24+ await page.getByRole("heading", { name: "Toolkits", level: 1 }).waitFor();
25+ await page.getByRole("heading", { name: "Workspace" }).waitFor();
26+ await page.getByRole("heading", { name: "Personal" }).waitFor();
27+ await page.getByRole("button", { name: "Add workspace toolkit" }).waitFor();
28+ await page.getByRole("button", { name: "Add personal toolkit" }).waitFor();
29+ await page.locator('main [data-slot="skeleton"]').first().waitFor({ state: "detached" });
30+ });
31+
32+ await step("The empty grid does not overflow its scroll container", async () => {
33+ // Walk up from the Personal add card to its nearest scrollable
34+ // ancestor; on an empty grid that ancestor must have nothing to
35+ // scroll. This is the user-visible contract — both add cards are
36+ // reachable without scrolling — measured at the scroll boundary.
37+ const overflow = await page.evaluate(() => {
38+ const addCard = [...document.querySelectorAll("button")].find(
39+ (button) => button.getAttribute("aria-label") === "Add personal toolkit",
40+ );
41+ let node: HTMLElement | null = addCard ?? null;
42+ while (node && node.scrollHeight <= node.clientHeight + 1) {
43+ node = node.parentElement;
44+ }
45+ if (!node) return null;
46+ return {
47+ tag: node.tagName,
48+ scrollHeight: node.scrollHeight,
49+ clientHeight: node.clientHeight,
50+ };
51+ });
52+ expect(overflow, "no scrollable ancestor overflows for an empty grid").toBeNull();
53+ });
54+ });
55+ }),
56+);
packages/plugins/toolkits/src/page.tsx+2−9
@@ -181,7 +181,6 @@ const toolkitByRouteSlug = ( · 180 unmodified lines
181181 };
182182
183183 const toolkitCardStyle = { minHeight: "9rem" };
184−const toolkitShelfStyle = { minHeight: "28.5rem" };
185184 const toolkitGridContainerStyle = { maxWidth: "80rem" };
186185 const toolkitToolTreeStyle = { width: "24rem" };
187186
@@ -636,10 +635,7 @@ function ToolkitSection(props: { · 448 unmodified lines
636635 </div>
637636 ) : null}
638637
639− <div
640− className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3"
641− style={toolkitShelfStyle}
642− >
638+ <div className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
643639 {rows.map((toolkit) => (
644640 <ToolkitTile key={toolkit.id} showOwnerLabels={props.showOwnerLabels} toolkit={toolkit} />
645641 ))}
@@ -1204,10 +1200,7 @@ function ToolkitSectionSkeleton(props: { title?: string }) { · 558 unmodified lines
12041200 </div>
12051201 ) : null}
12061202
1207− <div
1208− className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3"
1209− style={toolkitShelfStyle}
1210− >
1203+ <div className="grid content-start grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3">
12111204 <ToolkitTileSkeleton />
12121205 </div>
12131206 </section>