From 82a50de40382fe51b23f535beb101c64ee752312 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Sun, 9 Aug 2026 15:43:05 +0200 Subject: [PATCH] fix: size dashboard rails to viewport --- apps/docs/docs/management/boards/index.mdx | 2 +- .../src/app/[locale]/boards/(content)/_client.module.css | 1 + apps/nextjs/src/components/board/layout/README.md | 6 +++--- .../src/components/board/sections/grid/section-grid.tsx | 5 +---- e2e/board-grid.spec.ts | 5 +++++ 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/docs/docs/management/boards/index.mdx b/apps/docs/docs/management/boards/index.mdx index f26196adf..cfc02a4d5 100644 --- a/apps/docs/docs/management/boards/index.mdx +++ b/apps/docs/docs/management/boards/index.mdx @@ -39,7 +39,7 @@ Underscores and hyphen-minus are allowed. The column count defines how many fixed-width cells are available in each row. One cell contains a `200 × 200` logical-pixel tile. Homarr scales the whole board uniformly instead of changing widget proportions, and always fits it to the available width without horizontal scrolling. -The main canvas stays at least one viewport tall and grows automatically while you drag or resize items near its lower edge. +The main canvas and enabled rails stay at least one viewport tall, and the canvas grows automatically while you drag or resize items near its lower edge. ### Public diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_client.module.css b/apps/nextjs/src/app/[locale]/boards/(content)/_client.module.css index d0f0252e6..cafa491f0 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_client.module.css +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_client.module.css @@ -21,6 +21,7 @@ height: var(--board-gutter-viewport-height); padding-top: 24px; margin-top: -24px; + overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; diff --git a/apps/nextjs/src/components/board/layout/README.md b/apps/nextjs/src/components/board/layout/README.md index 6957e0136..12ac371d0 100644 --- a/apps/nextjs/src/components/board/layout/README.md +++ b/apps/nextjs/src/components/board/layout/README.md @@ -10,9 +10,9 @@ The board uses fixed logical units: Items keep the same logical dimensions at every viewport. The viewport reserves the painted size while the inner canvas remains at its logical dimensions, so a widget's `clientWidth`, `clientHeight`, and `ResizeObserver` measurements stay -stable. The visual canvas always fits the available width, the main root keeps -at least one viewport of height, and edit-mode previews extend it downward as -needed. +stable. The visual canvas always fits the available width, every root lane +keeps at least one viewport of height, and edit-mode previews extend it downward +as needed. The read-only renderer should: diff --git a/apps/nextjs/src/components/board/sections/grid/section-grid.tsx b/apps/nextjs/src/components/board/sections/grid/section-grid.tsx index 6b98efc0c..ab1b1fb4b 100644 --- a/apps/nextjs/src/components/board/sections/grid/section-grid.tsx +++ b/apps/nextjs/src/components/board/sections/grid/section-grid.tsx @@ -147,10 +147,7 @@ export const SectionGrid = ({ ); const displayedItems = items.map((item) => withPlacement(item, placementById.get(item.id))); const displayedInnerSections = innerSections.map((item) => withPlacement(item, placementById.get(item.id))); - const minimumViewportRowCount = useMinimumViewportRowCount( - section.kind === "empty" && railPlacement === "main", - canvasScale, - ); + const minimumViewportRowCount = useMinimumViewportRowCount(section.kind === "empty", canvasScale); const contentRowCount = Math.max(1, getLayoutRowCount(displayPlacements)); const rowCount = Math.max(contentRowCount, requestedRowCount, minimumViewportRowCount); const logicalWidth = getLogicalTrackSize(columnCount); diff --git a/e2e/board-grid.spec.ts b/e2e/board-grid.spec.ts index 88fb0b2de..0839ac527 100644 --- a/e2e/board-grid.spec.ts +++ b/e2e/board-grid.spec.ts @@ -95,6 +95,11 @@ describe("Board grid", () => { await expect(rail).toBeVisible(); await expect(rail).toHaveAttribute("data-board-gutter", "left"); await expect(railRootSection).toHaveAttribute("data-rail-placement", "left"); + await expect(rail).toHaveCSS("overflow-x", "hidden"); + const initialRailBox = await expectBoundingBoxAsync(rail); + const initialRailRootBox = await expectBoundingBoxAsync(railRootSection); + expect(initialRailRootBox.width).toBeCloseTo(initialRailBox.width, 1); + expect(initialRailRootBox.height).toBeGreaterThanOrEqual(initialRailBox.height - 1); await expect(railItem).toHaveAttribute("data-grid-x", "0"); await expect(containerSection).toHaveAttribute("data-grid-w", "2"); await expect(containerSection).toHaveAttribute("data-grid-h", "2");