UNPKG

@ichigo_san/graphing

Version:

A lightweight UML-style diagram editor built with React Flow and Tailwind CSS

229 lines (223 loc) 11.6 kB
"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;