From 201f427f622fb13f60cdc62b0d894f7d4f57ae95 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 10 Jun 2026 17:02:58 +0700 Subject: [PATCH] fix(app): keep settings sidebar scrollable --- .../app/e2e/settings-sidebar-scroll.spec.ts | 61 +++++++++++++++++++ packages/app/src/screens/settings-screen.tsx | 59 +++++++++++------- 2 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 packages/app/e2e/settings-sidebar-scroll.spec.ts diff --git a/packages/app/e2e/settings-sidebar-scroll.spec.ts b/packages/app/e2e/settings-sidebar-scroll.spec.ts new file mode 100644 index 000000000..06c6b6b25 --- /dev/null +++ b/packages/app/e2e/settings-sidebar-scroll.spec.ts @@ -0,0 +1,61 @@ +import { test, expect } from "./fixtures"; +import { gotoAppShell, openSettings } from "./helpers/app"; + +test.describe("Settings sidebar scrolling", () => { + test.use({ viewport: { width: 900, height: 260 } }); + + test("desktop drag region does not cover the scroll body", async ({ page }) => { + await page.addInitScript(() => { + window.paseoDesktop = { + platform: "darwin", + events: { on: () => () => {} }, + invoke: async (command: string) => { + if (command === "get_desktop_settings") { + return { + releaseChannel: "stable", + daemon: { manageBuiltInDaemon: true, keepRunningAfterQuit: true }, + }; + } + return null; + }, + }; + }); + + await gotoAppShell(page); + await openSettings(page); + + const sidebar = page.getByTestId("settings-sidebar"); + await expect(sidebar).toBeVisible(); + + const geometry = await sidebar.evaluate((node) => { + let scroller: HTMLElement | null = null; + for (const element of node.querySelectorAll("*")) { + if (element.scrollHeight > element.clientHeight) { + scroller = element; + break; + } + } + if (!scroller) return null; + + const scrollerRect = scroller.getBoundingClientRect(); + const dragRegions = []; + for (const element of node.querySelectorAll("*")) { + if (getComputedStyle(element).getPropertyValue("-webkit-app-region") === "drag") { + const rect = element.getBoundingClientRect(); + dragRegions.push({ bottom: rect.bottom }); + } + } + + return { + scrollBodyTop: scrollerRect.top, + dragRegions, + }; + }); + + expect(geometry).not.toBeNull(); + expect(geometry!.dragRegions).not.toEqual([]); + for (const dragRegion of geometry!.dragRegions) { + expect(dragRegion.bottom).toBeLessThanOrEqual(geometry!.scrollBodyTop + 1); + } + }); +}); diff --git a/packages/app/src/screens/settings-screen.tsx b/packages/app/src/screens/settings-screen.tsx index 0c20713ec..8339c27db 100644 --- a/packages/app/src/screens/settings-screen.tsx +++ b/packages/app/src/screens/settings-screen.tsx @@ -996,11 +996,12 @@ function SettingsSidebar({ const insets = useSafeAreaInsets(); const padding = useWindowControlsPadding("sidebar"); const isDesktop = layout === "desktop"; - const containerStyle = useMemo( - () => [ - isDesktop ? sidebarStyles.desktopContainer : sidebarStyles.mobileContainer, - isDesktop ? { paddingTop: insets.top } : null, - ], + const outerContainerStyle = useMemo( + () => [isDesktop ? sidebarStyles.desktopContainer : sidebarStyles.mobileContainer], + [isDesktop], + ); + const innerContainerStyle = useMemo( + () => [{ flex: 1 }, isDesktop ? { paddingTop: insets.top } : null], [insets.top, isDesktop], ); const selectedSectionId = view.kind === "section" ? view.section : null; @@ -1008,22 +1009,8 @@ function SettingsSidebar({ const isProjectsSelected = view.kind === "projects" || view.kind === "project"; const paddingTopStyle = useMemo(() => ({ height: padding.top }), [padding.top]); - return ( - - {isDesktop ? ( - <> - - {padding.top > 0 ? : null} - - ) : null} - {isDesktop ? ( - - ) : null} + const sidebarBody = ( + <> App {items.map((item) => ( @@ -1079,6 +1066,30 @@ function SettingsSidebar({ )} + + ); + + return ( + + {isDesktop ? ( + + + + {padding.top > 0 ? : null} + + + + {sidebarBody} + + + ) : ( + sidebarBody + )} ); } @@ -1630,6 +1641,12 @@ const sidebarStyles = StyleSheet.create((theme) => ({ borderRightColor: theme.colors.border, backgroundColor: theme.colors.surfaceSidebar, }, + scrollBody: { + flex: 1, + }, + sidebarDragArea: { + position: "relative", + }, mobileContainer: { paddingVertical: theme.spacing[2], paddingHorizontal: theme.spacing[2],