feat: rebuild board grid with dnd-kit

This commit is contained in:
Thomas Camlong authored and ajnart committed 2026-08-13 19:52:59 +02:00
1 parent 5bde4d3cc5
commit 1f5311e93b
107 files changed
+5628 -3209

No files matched your search

@@ -42,18 +42,18 @@ export const generateResponsiveGridFor = ({
const newItems: GridAlgorithmItem[] = [];
// Fix height of dynamic sections
const dynamicSectionHeightMap = new Map<string, number>();
const dynamicSectionsOfCurrentSection = normalizedItems.filter((item) => item.type === "section");
for (const dynamicSection of dynamicSectionsOfCurrentSection) {
// A container must remain tall enough for its recursively reflowed contents.
const containerHeightMap = new Map<string, number>();
const containersOfCurrentSection = normalizedItems.filter((item) => item.type === "section");
for (const container of containersOfCurrentSection) {
const result = generateResponsiveGridFor({
items,
previousWidth: dynamicSection.previousWidth,
width: dynamicSection.width,
sectionId: dynamicSection.id,
previousWidth: container.previousWidth,
width: container.width,
sectionId: container.id,
});
newItems.push(...result.items);
dynamicSectionHeightMap.set(dynamicSection.id, result.height);
containerHeightMap.set(container.id, result.height);
}
// Return same positions for items in the current section
@@ -69,7 +69,7 @@ export const generateResponsiveGridFor = ({
for (const item of normalizedItems) {
const itemWithHeight = {
...item,
height: item.type === "section" ? Math.max(dynamicSectionHeightMap.get(item.id) ?? 1, item.height) : item.height,
height: item.type === "section" ? Math.max(containerHeightMap.get(item.id) ?? 1, item.height) : item.height,
};
const position = nextFreeSpot(occupied2d, itemWithHeight, width);
if (!position) throw new Error("No free spot available");
@@ -25,34 +25,34 @@ describe("Grid Algorithm", () => {
expect(output).toBe(item.output);
});
test.each(dynamicSectionTests)(
"should convert a grid with dynamic sections from 16 columns to %i columns",
test.each(containerTests)(
"should convert a grid with nested containers from 16 columns to %i columns",
(_, testInput) => {
const outerDynamicSectionId = "b";
const innerDynamicSectionId = "f";
const outerContainerId = "b";
const innerContainerId = "f";
const items = [
algoItem({ id: "a", width: 2, height: 2 }),
algoItem({ id: outerDynamicSectionId, type: "section", width: 12, height: 3, yOffset: 2 }),
algoItem({ id: "a", width: 2, sectionId: outerDynamicSectionId }),
algoItem({ id: "b", width: 4, sectionId: outerDynamicSectionId, xOffset: 2 }),
algoItem({ id: "c", width: 2, sectionId: outerDynamicSectionId, xOffset: 6 }),
algoItem({ id: "d", width: 1, sectionId: outerDynamicSectionId, xOffset: 8 }),
algoItem({ id: "e", width: 3, sectionId: outerDynamicSectionId, xOffset: 9 }),
algoItem({ id: outerContainerId, type: "section", width: 12, height: 3, yOffset: 2 }),
algoItem({ id: "a", width: 2, sectionId: outerContainerId }),
algoItem({ id: "b", width: 4, sectionId: outerContainerId, xOffset: 2 }),
algoItem({ id: "c", width: 2, sectionId: outerContainerId, xOffset: 6 }),
algoItem({ id: "d", width: 1, sectionId: outerContainerId, xOffset: 8 }),
algoItem({ id: "e", width: 3, sectionId: outerContainerId, xOffset: 9 }),
algoItem({
id: innerDynamicSectionId,
id: innerContainerId,
type: "section",
width: 8,
height: 2,
yOffset: 1,
sectionId: outerDynamicSectionId,
sectionId: outerContainerId,
}),
algoItem({ id: "a", width: 2, sectionId: innerDynamicSectionId }),
algoItem({ id: "b", width: 5, xOffset: 2, sectionId: innerDynamicSectionId }),
algoItem({ id: "c", width: 1, height: 2, xOffset: 7, sectionId: innerDynamicSectionId }),
algoItem({ id: "d", width: 7, yOffset: 1, sectionId: innerDynamicSectionId }),
algoItem({ id: "g", width: 4, yOffset: 1, sectionId: outerDynamicSectionId, xOffset: 8 }),
algoItem({ id: "h", width: 3, yOffset: 2, sectionId: outerDynamicSectionId, xOffset: 8 }),
algoItem({ id: "i", width: 1, yOffset: 2, sectionId: outerDynamicSectionId, xOffset: 11 }),
algoItem({ id: "a", width: 2, sectionId: innerContainerId }),
algoItem({ id: "b", width: 5, xOffset: 2, sectionId: innerContainerId }),
algoItem({ id: "c", width: 1, height: 2, xOffset: 7, sectionId: innerContainerId }),
algoItem({ id: "d", width: 7, yOffset: 1, sectionId: innerContainerId }),
algoItem({ id: "g", width: 4, yOffset: 1, sectionId: outerContainerId, xOffset: 8 }),
algoItem({ id: "h", width: 3, yOffset: 2, sectionId: outerContainerId, xOffset: 8 }),
algoItem({ id: "i", width: 1, yOffset: 2, sectionId: outerContainerId, xOffset: 11 }),
algoItem({ id: "c", width: 5, yOffset: 5 }),
];
@@ -64,10 +64,10 @@ describe("Grid Algorithm", () => {
});
const rootItems = newItems.items.filter((item) => item.sectionId === ROOT_SECTION_ID);
const outerSection = items.find((item) => item.id === outerDynamicSectionId);
const outerItems = newItems.items.filter((item) => item.sectionId === outerDynamicSectionId);
const innerSection = items.find((item) => item.id === innerDynamicSectionId);
const innerItems = newItems.items.filter((item) => item.sectionId === innerDynamicSectionId);
const outerSection = items.find((item) => item.id === outerContainerId);
const outerItems = newItems.items.filter((item) => item.sectionId === outerContainerId);
const innerSection = items.find((item) => item.id === innerContainerId);
const innerItems = newItems.items.filter((item) => item.sectionId === innerContainerId);
expect(generateOutputText(rootItems, testInput.outputColumns)).toBe(testInput.root);
expect(generateOutputText(outerItems, Math.min(testInput.outputColumns, outerSection?.width ?? 999))).toBe(
@@ -192,7 +192,7 @@ const itemTests = [
},
].map((item) => [item.inputColumnCount, item.outputColumnCount, item] as const);
const dynamicSectionTests = [
const containerTests = [
{
outputColumns: 16,
root: `