Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.d/safari-sidebar-workspace-list-height.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Fixed
- In Safari, the sidebar's workspace list shows its workspaces again instead of a single row with a
scrollbar beside it.
30 changes: 28 additions & 2 deletions scripts/sidebar-split-demo-regression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ const metrics = (page: Page) => page.evaluate(() => {
agentsFolded: document.querySelector(".agent-section-toggle")!.getAttribute("aria-expanded") === "false",
};
});
// The PCs' list holds its rows, or as many as the room up to the line (or the footer) leaves it (issue 3267)
const pcListLayout = (page: Page) => page.evaluate(() => {
const pcs = document.querySelector<HTMLElement>(".pcs-sidebar")!;
const list = document.querySelector<HTMLElement>(".machine-list")!;
const grouped = document.querySelector(".sidebar-shell")!.classList.contains("is-agents-first");
const end = document.querySelector<HTMLElement>(grouped ? ".sidebar-footer" : ".sidebar-split")!.getBoundingClientRect().top;
const style = getComputedStyle(pcs);
const room = Math.max(0, end - pcs.getBoundingClientRect().top - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom));
list.scrollTop = 0;
const viewport = list.getBoundingClientRect();
const first = list.querySelector(".workspace-group")?.getBoundingClientRect();
return {
clientHeight: list.clientHeight,
expectedHeight: Math.min(list.scrollHeight, room),
firstVisible: first !== undefined && first.top >= viewport.top - 1 && first.bottom <= viewport.bottom + 1,
display: style.display,
};
});

try {
await buildDemoApp(app);
Expand Down Expand Up @@ -77,6 +95,11 @@ try {
await open();
const line = page.getByRole("separator", { name: "Resize PCs and Agents", exact: true });
const original = await metrics(page);
const defaultPcs = await pcListLayout(page);
// Chromium shows the rows with a column flexbox too; Safari caps its list at one row, so pin the grid
assert.equal(defaultPcs.display, "grid", `${label} the PCs section stays a grid, or Safari draws its list one row tall`);
assert.ok(Math.abs(defaultPcs.clientHeight - defaultPcs.expectedHeight) <= 1, `${label} the PCs' list takes its rows' height or the room it has (${defaultPcs.clientHeight}/${defaultPcs.expectedHeight}px)`);
assert.ok(defaultPcs.firstVisible, `${label} the first PC row is in view by default`);
assert.equal(await page.evaluate((key) => localStorage.getItem(key), key), null, `${label} opening the sidebar does not save a split`);
assert.ok(original.agents.height <= original.shell.height / 2 + 1, `${label} the default starts at no more than today's half-shell allocation`);
const controls = await line.getAttribute("aria-controls");
Expand Down Expand Up @@ -190,8 +213,11 @@ try {
if (!grouped) assert.ok(Math.abs(preview.bottom.height - preview.bottomHead) <= 1, `${label} the lower snap preview reaches its heading before release`);
else assert.equal(await page.locator(".sidebar-split.is-snapping, .will-fold").count(), 0, `${label} no snap preview over the PCs`);
});
if (!grouped) await page.waitForFunction(() => document.querySelector(".agents-sidebar")!.classList.contains("is-collapsed"));
else assert.equal(await page.locator(".pcs-sidebar.is-collapsed, .agents-sidebar.is-collapsed").count(), 0, `${label} a drag to the PCs' foot folds nothing`);
if (!grouped) {
await page.waitForFunction(() => document.querySelector(".agents-sidebar")!.classList.contains("is-collapsed"));
const folded = await pcListLayout(page);
assert.ok(Math.abs(folded.clientHeight - folded.expectedHeight) <= 1, `${label} with Agents folded the PCs' list takes its rows' height or the room it has (${folded.clientHeight}/${folded.expectedHeight}px)`);
} else assert.equal(await page.locator(".pcs-sidebar.is-collapsed, .agents-sidebar.is-collapsed").count(), 0, `${label} a drag to the PCs' foot folds nothing`);
await line.focus(); await page.keyboard.press("Enter");
await page.waitForFunction(() => !document.querySelector(".pcs-sidebar.is-collapsed, .agents-sidebar.is-collapsed"));
// A caret can override the divider's last fold request. Reordering must not replay that old request.
Expand Down
10 changes: 5 additions & 5 deletions src/components/SidebarSections.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* The sidebar's two sections, PCs and Agents (MachineSidebar.tsx, AgentSidebar.tsx): the PCs a list that
starts right under the logo, Agents a head that stays put and a list that scrolls under it. */

/* The rows keep their own scroll viewport, the section's one grid row. A grid, not a column flexbox:
Safari sizes a column flexbox's max-content (Sidebar.css caps the section at it) from its 0 flex
basis, which left the list one row tall (issue 3267). */
.pcs-sidebar {
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: minmax(0, 1fr);
min-height: 0;
padding-top: var(--space-2);
}

/* The rows keep their own scroll viewport. */
.pcs-sidebar > .machine-list { flex: 1 1 auto; }

/* A list fades at an edge only while rows lie past it (lib/useEdgeFades.ts): at its top it fades its foot
alone, scrolled to its end its head alone, and a list that holds all its rows fades neither. A mask,
so the fade is the panel's whatever lies under it (a selected row, the pinned card); the mask reads
Expand Down
Loading