@ichigo_san/graphing
Version:
A lightweight UML-style diagram editor built with React Flow and Tailwind CSS
229 lines (223 loc) • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _lucideReact = require("lucide-react");
var _autoLayout = require("../utils/autoLayout");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const LayoutSettingsPanel = ({
nodes,
setNodes,
isOpen,
onClose,
currentLayoutAlgorithm = 'hierarchical',
onLayoutChange
}) => {
var _layoutAlgorithms$sel;
const [selectedAlgorithm, setSelectedAlgorithm] = (0, _react.useState)(currentLayoutAlgorithm);
const [previewMode, setPreviewMode] = (0, _react.useState)(false);
// Group algorithms by category
const algorithmsByCategory = Object.entries(_autoLayout.layoutAlgorithms).reduce((acc, [key, config]) => {
if (!acc[config.category]) {
acc[config.category] = [];
}
acc[config.category].push({
key,
...config
});
return acc;
}, {});
// Get icon for category
const getCategoryIcon = category => {
switch (category) {
case 'Basic':
return /*#__PURE__*/_react.default.createElement(_lucideReact.Grid, {
className: "w-4 h-4"
});
case 'Organization':
return /*#__PURE__*/_react.default.createElement(_lucideReact.Layers, {
className: "w-4 h-4"
});
case 'Tree':
return /*#__PURE__*/_react.default.createElement(_lucideReact.TreePine, {
className: "w-4 h-4"
});
case 'Special':
return /*#__PURE__*/_react.default.createElement(_lucideReact.Zap, {
className: "w-4 h-4"
});
default:
return /*#__PURE__*/_react.default.createElement(_lucideReact.Layout, {
className: "w-4 h-4"
});
}
};
// Get icon for specific algorithm
const getAlgorithmIcon = algorithm => {
if (algorithm.includes('circular') || algorithm.includes('radial')) {
return /*#__PURE__*/_react.default.createElement(_lucideReact.Circle, {
className: "w-4 h-4"
});
}
if (algorithm.includes('grid') || algorithm.includes('hanger')) {
return /*#__PURE__*/_react.default.createElement(_lucideReact.Grid, {
className: "w-4 h-4"
});
}
if (algorithm.includes('force') || algorithm.includes('organic')) {
return /*#__PURE__*/_react.default.createElement(_lucideReact.Zap, {
className: "w-4 h-4"
});
}
if (algorithm.includes('tree')) {
return /*#__PURE__*/_react.default.createElement(_lucideReact.TreePine, {
className: "w-4 h-4"
});
}
return /*#__PURE__*/_react.default.createElement(_lucideReact.Layout, {
className: "w-4 h-4"
});
};
const handleAlgorithmSelect = (0, _react.useCallback)(algorithmKey => {
setSelectedAlgorithm(algorithmKey);
if (previewMode) {
// Apply layout immediately for preview
const updatedNodes = (0, _autoLayout.applyLayoutAlgorithm)([...nodes], algorithmKey);
setNodes(updatedNodes);
}
}, [nodes, setNodes, previewMode]);
const handleApplyLayout = (0, _react.useCallback)(() => {
const updatedNodes = (0, _autoLayout.applyLayoutAlgorithm)([...nodes], selectedAlgorithm);
setNodes(updatedNodes);
if (onLayoutChange) {
onLayoutChange(selectedAlgorithm);
}
onClose();
}, [nodes, setNodes, selectedAlgorithm, onLayoutChange, onClose]);
const handlePreviewToggle = (0, _react.useCallback)(() => {
setPreviewMode(!previewMode);
}, [previewMode]);
if (!isOpen) return null;
return /*#__PURE__*/_react.default.createElement("div", {
className: "fixed inset-0 bg-black bg-opacity-30 flex items-center justify-center z-50"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-3xl w-full mx-4 max-h-[75vh] overflow-hidden"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center gap-2"
}, /*#__PURE__*/_react.default.createElement(_lucideReact.Settings2, {
className: "w-5 h-5 text-blue-600"
}), /*#__PURE__*/_react.default.createElement("h2", {
className: "text-lg font-semibold text-gray-900 dark:text-white"
}, "Layout Settings")), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center gap-2"
}, /*#__PURE__*/_react.default.createElement("label", {
className: "flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300"
}, /*#__PURE__*/_react.default.createElement("input", {
type: "checkbox",
checked: previewMode,
onChange: handlePreviewToggle,
className: "rounded border-gray-300 text-blue-600 focus:ring-blue-500"
}), "Live Preview"), /*#__PURE__*/_react.default.createElement("button", {
onClick: onClose,
className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
}, "\u2715"))), /*#__PURE__*/_react.default.createElement("div", {
className: "p-4 overflow-y-auto max-h-[calc(75vh-120px)]"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "space-y-4"
}, Object.entries(algorithmsByCategory).map(([category, algorithms]) => /*#__PURE__*/_react.default.createElement("div", {
key: category,
className: "space-y-3"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-center gap-2 pb-2 border-b border-gray-100 dark:border-gray-700"
}, getCategoryIcon(category), /*#__PURE__*/_react.default.createElement("h3", {
className: "text-md font-medium text-gray-900 dark:text-white"
}, category, " Layouts"), /*#__PURE__*/_react.default.createElement("span", {
className: "text-xs text-gray-500 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded-full"
}, algorithms.length, " options")), /*#__PURE__*/_react.default.createElement("div", {
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2"
}, algorithms.map(algorithm => /*#__PURE__*/_react.default.createElement("div", {
key: algorithm.key,
onClick: () => handleAlgorithmSelect(algorithm.key),
className: `
relative p-3 rounded-md border cursor-pointer transition-all duration-200
${selectedAlgorithm === algorithm.key ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20 shadow-md' : 'border-gray-200 dark:border-gray-600 hover:border-gray-300 dark:hover:border-gray-500 hover:shadow-sm'}
`
}, selectedAlgorithm === algorithm.key && /*#__PURE__*/_react.default.createElement("div", {
className: "absolute top-1 right-1 w-2 h-2 bg-blue-500 rounded-full"
}), /*#__PURE__*/_react.default.createElement("div", {
className: "flex items-start gap-2"
}, /*#__PURE__*/_react.default.createElement("div", {
className: `
p-1.5 rounded-sm
${selectedAlgorithm === algorithm.key ? 'bg-blue-100 dark:bg-blue-800 text-blue-600 dark:text-blue-300' : 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300'}
`
}, getAlgorithmIcon(algorithm.key)), /*#__PURE__*/_react.default.createElement("div", {
className: "flex-1 min-w-0"
}, /*#__PURE__*/_react.default.createElement("h4", {
className: `
font-medium text-xs leading-tight
${selectedAlgorithm === algorithm.key ? 'text-blue-900 dark:text-blue-100' : 'text-gray-900 dark:text-white'}
`
}, algorithm.name), /*#__PURE__*/_react.default.createElement("p", {
className: "text-xs text-gray-500 dark:text-gray-400 mt-0.5 leading-tight line-clamp-2"
}, getAlgorithmDescription(algorithm.key))))))))))), /*#__PURE__*/_react.default.createElement("div", {
className: "px-6 py-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750 flex items-center justify-between"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "text-sm text-gray-600 dark:text-gray-300"
}, "Selected: ", /*#__PURE__*/_react.default.createElement("span", {
className: "font-medium"
}, (_layoutAlgorithms$sel = _autoLayout.layoutAlgorithms[selectedAlgorithm]) === null || _layoutAlgorithms$sel === void 0 ? void 0 : _layoutAlgorithms$sel.name)), /*#__PURE__*/_react.default.createElement("div", {
className: "flex gap-3"
}, /*#__PURE__*/_react.default.createElement("button", {
onClick: onClose,
className: "px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
}, "Cancel"), /*#__PURE__*/_react.default.createElement("button", {
onClick: handleApplyLayout,
className: "px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
}, "Apply Layout")))));
};
// Helper function to get algorithm descriptions
const getAlgorithmDescription = algorithmKey => {
const descriptions = {
'hierarchical': 'Arranges nodes in levels with containers first, then components below',
'grid': 'Organizes nodes in a regular grid pattern with optimal spacing',
'circular': 'Places nodes in a circle around a center point',
'force-directed': 'Uses physics simulation to position nodes naturally',
'org-linear': 'Vertical linear arrangement, ideal for simple hierarchies',
'org-hanger2': '2-column layout for medium-sized organizations',
'org-hanger4': '4-column layout for larger organizational structures',
'org-fishbone1': 'Alternating left-right branching pattern',
'org-fishbone2': 'Four-quadrant radial branching layout',
'tree-vertical': 'Top-down tree structure with clear hierarchy',
'tree-horizontal': 'Left-to-right tree structure',
'radial': 'Radial arrangement with equal angular spacing',
'compact': 'Space-efficient grid with minimal gaps',
'organic': 'Natural, organic positioning with collision avoidance'
};
return descriptions[algorithmKey] || 'Layout algorithm for node arrangement';
};
// Helper function to get layout preview icons
const getLayoutPreview = algorithmKey => {
const previews = {
'hierarchical': '□□□\n □□',
'grid': '□□□\n□□□',
'circular': ' □\n□○□\n □',
'force-directed': '□ □\n ○\n □',
'org-linear': '□\n□\n□',
'org-hanger2': '□□\n□□',
'org-hanger4': '□□□□',
'org-fishbone1': '□ □\n□ □',
'org-fishbone2': '□ □\n ○\n□ □',
'tree-vertical': ' □\n□□□',
'tree-horizontal': '□─□□',
'radial': '□□□',
'compact': '□□\n□□',
'organic': '□ □\n ○'
};
return previews[algorithmKey] || '□□□';
};
var _default = exports.default = LayoutSettingsPanel;