diff --git a/apps/nextjs/src/components/board/sections/container-section.tsx b/apps/nextjs/src/components/board/sections/container-section.tsx index 7e4e180ed..dff3d3f7c 100644 --- a/apps/nextjs/src/components/board/sections/container-section.tsx +++ b/apps/nextjs/src/components/board/sections/container-section.tsx @@ -8,6 +8,7 @@ import { useEditMode } from "@homarr/boards/edit-mode"; import { useI18n } from "@homarr/translation/client"; import type { ContainerSectionItem } from "~/app/[locale]/boards/_types"; +import { COLLAPSED_SECTION_ROW_COUNT } from "~/components/board/layout"; import { SectionGrid } from "./grid/section-grid"; import { useSectionCollapse } from "./section-collapse"; import { useOpenSectionApps } from "./use-open-section-apps"; @@ -149,7 +150,13 @@ export const BoardContainerSection = ({ section }: Props) => { aria-hidden={isVisuallyCollapsed} inert={isVisuallyCollapsed} > - + {isEditMode && } 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 23a584d6b..d606e30db 100644 --- a/apps/nextjs/src/components/board/sections/grid/section-grid.tsx +++ b/apps/nextjs/src/components/board/sections/grid/section-grid.tsx @@ -33,6 +33,7 @@ interface SectionGridProps { section: Exclude | ContainerSectionItem; columnCount: number; requestedRowCount?: number; + viewportRowCountOverride?: number; label: string; railPlacement?: "main" | "left" | "right"; className?: string; @@ -42,6 +43,7 @@ export const SectionGrid = ({ section, columnCount, requestedRowCount = 0, + viewportRowCountOverride, label, railPlacement = "main", className, @@ -67,6 +69,8 @@ export const SectionGrid = ({ () => [...items, ...innerSections].map((item): SectionGridPlacement => { const minimum = item.type === "section" ? minimumBySectionId.get(item.id) : undefined; + const isNonScrollableContainer = item.type === "section" && !item.options.scrollable; + const height = isNonScrollableContainer && minimum ? Math.max(item.height, minimum.height) : item.height; return normalizeGridPlacement( { id: item.id, @@ -74,7 +78,7 @@ export const SectionGrid = ({ x: item.xOffset, y: item.yOffset, w: item.width, - h: item.height, + h: height, minW: minimum?.width, minH: minimum?.height, }, @@ -137,7 +141,8 @@ export const SectionGrid = ({ // A scrollable container isn't forced to grow with its content - it scrolls internally instead // of expanding to fit every widget, so its viewport height is capped independently of rowCount. const isScrollableContainer = section.kind === "container" && section.options.scrollable; - const viewportRowCount = isScrollableContainer ? Math.max(requestedRowCount, 1) : rowCount; + const viewportRowCount = + viewportRowCountOverride ?? (isScrollableContainer ? Math.max(requestedRowCount, 1) : rowCount); // A container's own visible card is inset from its allocated board cell by the board's // standard per-item gap (see the base, non-container `.staticItem[data-type="item"] > // .contentMount` rule in section-grid.module.css - a container is placed as an "item" like @@ -159,14 +164,9 @@ export const SectionGrid = ({ // all, the header bar covers the first row of the container's content instead of sitting // above it. Only the vertical axis is affected - the toggle spans the full width already. const collapsibleHeaderInset = - section.kind === "container" && section.options.collapsible - ? CONTAINER_HEADER_HEIGHT / effectiveCanvasScale - : 0; + section.kind === "container" && section.options.collapsible ? CONTAINER_HEADER_HEIGHT / effectiveCanvasScale : 0; const logicalWidth = getLogicalGridSize(columnCount) - outerCardInset; - const viewportHeight = Math.max( - 1, - getLogicalGridSize(viewportRowCount) - outerCardInset - collapsibleHeaderInset, - ); + const viewportHeight = Math.max(1, getLogicalGridSize(viewportRowCount) - outerCardInset - collapsibleHeaderInset); // Items are positioned in a coordinate space sized to the *un-inset* column/row count // (fullGridWidth/Height below - see getLogicalItemStyle), but logicalWidth/Height above are // deliberately smaller by outerCardInset to match the container's actual visible card size.