sokko-g/website/src/features/toolboxes/modules/ToolboxModules.jsx
Shinuwa 808610dcf2
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s
Add planner-aware memos and unified tool configuration panels
2026-10-03 15:58:33 +02:00

87 lines
4.2 KiB
JavaScript

// Rôle : répartit les modules de l'espace actif dans leurs colonnes et cibles de dépôt.
import { useMemo } from "react";
import { encodeSpaceColumn } from "../toolboxSpaceUtils.js";
import { ModuleShell } from "./ModuleShell.jsx";
const MODULE_COLUMN_IDS = ["left", "right"];
function getModulesByIds(modules, ids) {
const moduleMap = new Map(modules.map((module) => [module.id, module]));
return (Array.isArray(ids) ? ids : []).map((id) => moduleMap.get(id)).filter(Boolean);
}
export function ToolboxModules({ toolbox, space, moduleColumns, context, reorder, spacesText, configurationText, scrollToModuleId = "", onModuleScrolled, onRename, onUpdateModule, onDelete, onMoveToSpace }) {
const twoColumnOrder = useMemo(() => space.moduleOrder?.two || [[], []], [space.moduleOrder?.two]);
const orderedModules = useMemo(() => getModulesByIds(toolbox.modules, space.moduleOrder?.one || []), [toolbox.modules, space.moduleOrder?.one]);
const columns = useMemo(() => [
getModulesByIds(toolbox.modules, twoColumnOrder[0]),
getModulesByIds(toolbox.modules, twoColumnOrder[1])
], [toolbox.modules, twoColumnOrder]);
if (moduleColumns === 1) {
return (
<section className="modules" data-toolbox-id={toolbox.id} data-layout-cols={moduleColumns}>
{!orderedModules.length && <div className="empty toolbox-space-empty nds-empty-state"><p>{spacesText.emptyText}</p></div>}
{orderedModules.map((module) => (
<ModuleShell
key={module.id}
toolbox={toolbox}
module={module}
context={context}
reorder={reorder}
itemGroup={encodeSpaceColumn(space.id, "one")}
spaces={toolbox.spaces}
activeSpaceId={space.id}
moveText={spacesText.moveLabel}
configurationText={configurationText}
onMoveToSpace={onMoveToSpace}
scrollIntoView={module.id === scrollToModuleId}
onScrolledIntoView={onModuleScrolled}
onRename={onRename}
onUpdateModule={onUpdateModule}
onDelete={onDelete}
/>
))}
</section>
);
}
const hasEmptyColumn = orderedModules.length > 1 && columns.some((modules) => modules.length === 0);
return (
<section className="modules" data-toolbox-id={toolbox.id} data-layout-cols={moduleColumns}>
{columns.map((modules, index) => (
<div className={`module-column ${hasEmptyColumn && !modules.length ? "is-empty-warning" : ""}`} key={MODULE_COLUMN_IDS[index]}>
<div
className={`module-column-boundary-drop-zone ${reorder.isBoundaryDropTarget({ groupId: encodeSpaceColumn(space.id, MODULE_COLUMN_IDS[index]), parentId: toolbox.id, placement: "before" }) ? "is-drop-target" : ""}`}
{...reorder.getGroupBoundaryProps({ groupId: encodeSpaceColumn(space.id, MODULE_COLUMN_IDS[index]), parentId: toolbox.id, placement: "before" })}
/>
{modules.map((module) => (
<ModuleShell
key={module.id}
toolbox={toolbox}
module={module}
context={context}
reorder={reorder}
itemGroup={encodeSpaceColumn(space.id, MODULE_COLUMN_IDS[index])}
spaces={toolbox.spaces}
activeSpaceId={space.id}
moveText={spacesText.moveLabel}
configurationText={configurationText}
onMoveToSpace={onMoveToSpace}
scrollIntoView={module.id === scrollToModuleId}
onScrolledIntoView={onModuleScrolled}
onRename={onRename}
onUpdateModule={onUpdateModule}
onDelete={onDelete}
/>
))}
<div
className={`module-column-boundary-drop-zone ${reorder.isBoundaryDropTarget({ groupId: encodeSpaceColumn(space.id, MODULE_COLUMN_IDS[index]), parentId: toolbox.id, placement: "after" }) ? "is-drop-target" : ""}`}
{...reorder.getGroupBoundaryProps({ groupId: encodeSpaceColumn(space.id, MODULE_COLUMN_IDS[index]), parentId: toolbox.id, placement: "after" })}
/>
</div>
))}
{!orderedModules.length && <div className="empty toolbox-space-empty nds-empty-state"><p>{spacesText.emptyText}</p></div>}
</section>
);
}