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.