import { useMemo } from "react"; import type { GridItemHTMLElement } from "@homarr/gridstack"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; import type { DynamicSectionItem, SectionItem } from "~/app/[locale]/boards/_types"; import { BoardItemContent } from "../items/item-content"; import { WidgetHoverOverlay } from "../items/widget-hover-overlay"; import { BoardDynamicSection } from "./dynamic-section"; import { GridStackItem } from "./gridstack/gridstack-item"; import { useSectionContext } from "./section-context"; import { useSectionItems } from "./use-section-items"; export const SectionContent = () => { const { innerSections, items, refs } = useSectionContext(); const { data: integrations } = clientApi.integration.all.useQuery(); /** * IMPORTANT: THE ORDER OF THE BELOW ITEMS HAS TO MATCH THE ORDER OF * THE ITEMS RENDERED WITH GRIDSTACK, OTHERWISE THE ITEMS WILL BE MIXED UP * @see https://github.com/homarr-labs/homarr/pull/1770 */ const sortedItems = useMemo(() => { return [...items, ...innerSections].toSorted((itemA, itemB) => { if (itemA.yOffset === itemB.yOffset) { return itemA.xOffset - itemB.xOffset; } return itemA.yOffset - itemB.yOffset; }); }, [items, innerSections]); return ( <> {sortedItems.map((item) => ( ))} ); }; interface ItemProps { item: DynamicSectionItem | SectionItem; innerRef: React.RefObject | undefined; integrations: RouterOutputs["integration"]["all"] | undefined; } const Item = ({ item, innerRef, integrations }: ItemProps) => { const minWidth = useMinSize(item, "x"); const minHeight = useMinSize(item, "y"); return ( {item.type === "item" && item.kind !== "app" && } {item.type === "item" ? : } ); }; /** * Calculates the min width / height of a section by taking the maximum of * the sum of the offset and size of all items and dynamic sections inside. * @param direction either "x" or "y" * @param items items of the section * @param sections sections of the board to look for dynamic sections * @param parentSectionId the id of the section we want to calculate the min size for * @returns the min size */ const useMinSize = (item: DynamicSectionItem | SectionItem, direction: "x" | "y") => { const { items, innerSections } = useSectionItems(item.id); if (item.type === "item") return undefined; const size = direction === "x" ? "width" : "height"; return Math.max( ...items.map((item) => item[`${direction}Offset`] + item[size]), ...innerSections.map((item) => item[`${direction}Offset`] + item[size]), ); };