@lv-x-software-house/x_view 1.2.2-dev.9 → 1.2.3-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1366 -890
- package/dist/index.mjs +821 -344
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import React23, { useCallback as
|
|
2
|
+
import React23, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef17, useState as useState23, useMemo as useMemo12 } from "react";
|
|
3
3
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
4
|
import { useSession } from "next-auth/react";
|
|
5
5
|
import CryptoJS from "crypto-js";
|
|
@@ -246,7 +246,7 @@ function ContextMenu({
|
|
|
246
246
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", null, "Conectar")), ability.can("create", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ React.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ React.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ React.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ React.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ React.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ React.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ React.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
247
247
|
onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
|
|
248
248
|
onClose();
|
|
249
|
-
}, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ React.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ React.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ React.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ React.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss")), /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () =>
|
|
249
|
+
}, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ React.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ React.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })), /* @__PURE__ */ React.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ React.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ React.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss")), /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("deleteConfirmation"), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React.createElement("span", null, "Excluir Node"))));
|
|
250
250
|
};
|
|
251
251
|
const renderVersionSubMenuView = () => {
|
|
252
252
|
const group = versionSubMenu;
|
|
@@ -338,6 +338,24 @@ function ContextMenu({
|
|
|
338
338
|
/* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, version.name)
|
|
339
339
|
))));
|
|
340
340
|
};
|
|
341
|
+
const renderDeleteConfirmationView = () => {
|
|
342
|
+
var _a2;
|
|
343
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React.createElement("strong", null, (_a2 = data.nodeData) == null ? void 0 : _a2.name), "?"), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] text-slate-400 leading-tight" }, "Todas as conex\xF5es associadas tamb\xE9m ser\xE3o apagadas.")), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React.createElement(
|
|
344
|
+
"button",
|
|
345
|
+
{
|
|
346
|
+
onClick: () => setMenuView("main"),
|
|
347
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
348
|
+
},
|
|
349
|
+
"Cancelar"
|
|
350
|
+
), /* @__PURE__ */ React.createElement(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
onClick: () => onDeleteNode == null ? void 0 : onDeleteNode(data.nodeData),
|
|
354
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
355
|
+
},
|
|
356
|
+
"Excluir"
|
|
357
|
+
)));
|
|
358
|
+
};
|
|
341
359
|
return /* @__PURE__ */ React.createElement(
|
|
342
360
|
"div",
|
|
343
361
|
{
|
|
@@ -353,7 +371,7 @@ function ContextMenu({
|
|
|
353
371
|
onDoubleClick: swallow
|
|
354
372
|
},
|
|
355
373
|
/* @__PURE__ */ React.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
356
|
-
/* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView())
|
|
374
|
+
/* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
|
|
357
375
|
);
|
|
358
376
|
}
|
|
359
377
|
|
|
@@ -735,7 +753,7 @@ function XViewSidebar({
|
|
|
735
753
|
}
|
|
736
754
|
|
|
737
755
|
// src/components/AncestryRelationshipPanel.jsx
|
|
738
|
-
import React8, { useState as
|
|
756
|
+
import React8, { useState as useState9, useEffect as useEffect8, useRef as useRef7 } from "react";
|
|
739
757
|
|
|
740
758
|
// node_modules/uuid/dist/esm-node/rng.js
|
|
741
759
|
import crypto from "crypto";
|
|
@@ -785,6 +803,7 @@ function v4(options, buf, offset) {
|
|
|
785
803
|
var v4_default = v4;
|
|
786
804
|
|
|
787
805
|
// src/logic/x_view_utils.js
|
|
806
|
+
import { useState as useState3, useCallback } from "react";
|
|
788
807
|
import * as THREE2 from "three";
|
|
789
808
|
|
|
790
809
|
// src/logic/x_view_config.js
|
|
@@ -1534,7 +1553,6 @@ var userActionHandlers = {
|
|
|
1534
1553
|
color: ghostColor,
|
|
1535
1554
|
emissive: ghostEmissive,
|
|
1536
1555
|
emissiveIntensity: MIN_VISIBILITY_INTENSITY,
|
|
1537
|
-
// <-- Forçamos o brilho mínimo
|
|
1538
1556
|
roughness: 0.6,
|
|
1539
1557
|
metalness: 0,
|
|
1540
1558
|
transparent: true,
|
|
@@ -1691,7 +1709,6 @@ var userActionHandlers = {
|
|
|
1691
1709
|
color: ghostColor,
|
|
1692
1710
|
emissive: ghostEmissive,
|
|
1693
1711
|
emissiveIntensity: MIN_VISIBILITY_INTENSITY,
|
|
1694
|
-
// <-- Forçamos o brilho mínimo
|
|
1695
1712
|
roughness: 0.6,
|
|
1696
1713
|
metalness: 0,
|
|
1697
1714
|
transparent: true,
|
|
@@ -1988,9 +2005,7 @@ var userActionHandlers = {
|
|
|
1988
2005
|
linkObject.visible = false;
|
|
1989
2006
|
controls.enabled = false;
|
|
1990
2007
|
if (mountRef.current) mountRef.current.style.cursor = "crosshair";
|
|
1991
|
-
const tempMat = new LineMaterial({
|
|
1992
|
-
/* ... material tracejado ... */
|
|
1993
|
-
});
|
|
2008
|
+
const tempMat = new LineMaterial({});
|
|
1994
2009
|
const tempGeom = new LineGeometry().setPositions([
|
|
1995
2010
|
...fixedNode.position.toArray(),
|
|
1996
2011
|
...fixedNode.position.toArray()
|
|
@@ -2119,9 +2134,6 @@ var userActionHandlers = {
|
|
|
2119
2134
|
const { parentFileId, ownerId } = parentInfo;
|
|
2120
2135
|
const srcName = ((_c = (_b = (_a = linkObject.userData) == null ? void 0 : _a.sourceNode) == null ? void 0 : _b.userData) == null ? void 0 : _c.name) ?? linkObject.userData.source;
|
|
2121
2136
|
const tgtName = ((_f = (_e = (_d = linkObject.userData) == null ? void 0 : _d.targetNode) == null ? void 0 : _e.userData) == null ? void 0 : _f.name) ?? linkObject.userData.target;
|
|
2122
|
-
if (!window.confirm(`Tem certeza que deseja excluir a conex\xE3o entre "${srcName}" \u2192 "${tgtName}"?`)) {
|
|
2123
|
-
return;
|
|
2124
|
-
}
|
|
2125
2137
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
2126
2138
|
const newLinks = (specificParentData.links || []).filter((l) => String(l.id) !== String(linkIdToDelete));
|
|
2127
2139
|
specificParentData.links = newLinks;
|
|
@@ -2275,9 +2287,6 @@ var userActionHandlers = {
|
|
|
2275
2287
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2276
2288
|
setters.setMultiContextMenu({ visible: false });
|
|
2277
2289
|
if (!nodeIds || nodeIds.size === 0 || !graphDataRef.current || !sceneDataRef.current) return;
|
|
2278
|
-
if (!window.confirm(`Tem certeza que deseja excluir ${nodeIds.size} Nodes e todas as suas conex\xF5es? Esta a\xE7\xE3o \xE9 irrevers\xEDvel.`)) {
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
2290
|
const strNodeIdsToDelete = Array.from(nodeIds).map(String);
|
|
2282
2291
|
if (actions.delete_file) {
|
|
2283
2292
|
strNodeIdsToDelete.forEach((id) => {
|
|
@@ -2358,9 +2367,6 @@ var userActionHandlers = {
|
|
|
2358
2367
|
}
|
|
2359
2368
|
setters.setContextMenu({ visible: false });
|
|
2360
2369
|
if (!nodeData || !graphDataRef.current || !sceneDataRef.current) return;
|
|
2361
|
-
if (!window.confirm(`Tem certeza que deseja excluir o Node "${nodeData.name}" e todas as sua conex\xF5es?`)) {
|
|
2362
|
-
return;
|
|
2363
|
-
}
|
|
2364
2370
|
const nodeIdToDelete = nodeData.id;
|
|
2365
2371
|
const strNodeId = String(nodeIdToDelete);
|
|
2366
2372
|
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeIdToDelete);
|
|
@@ -2999,9 +3005,36 @@ var extractFileUrlsFromProperties = (dataObject) => {
|
|
|
2999
3005
|
});
|
|
3000
3006
|
return urlsToDelete;
|
|
3001
3007
|
};
|
|
3008
|
+
function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
3009
|
+
const [width, setWidth] = useState3(initialWidth);
|
|
3010
|
+
const [isResizing, setIsResizing] = useState3(false);
|
|
3011
|
+
const handlePointerDown = useCallback((e) => {
|
|
3012
|
+
e.preventDefault();
|
|
3013
|
+
e.stopPropagation();
|
|
3014
|
+
setIsResizing(true);
|
|
3015
|
+
const startX = e.clientX;
|
|
3016
|
+
const startWidth = width;
|
|
3017
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
3018
|
+
document.body.style.userSelect = "none";
|
|
3019
|
+
const handlePointerMove = (moveEvent) => {
|
|
3020
|
+
const deltaX = startX - moveEvent.clientX;
|
|
3021
|
+
const newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);
|
|
3022
|
+
setWidth(newWidth);
|
|
3023
|
+
};
|
|
3024
|
+
const handlePointerUp = () => {
|
|
3025
|
+
setIsResizing(false);
|
|
3026
|
+
document.body.style.userSelect = originalUserSelect;
|
|
3027
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
3028
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
3029
|
+
};
|
|
3030
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
3031
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
3032
|
+
}, [width, minWidth, maxWidth]);
|
|
3033
|
+
return { width, isResizing, handlePointerDown, setWidth };
|
|
3034
|
+
}
|
|
3002
3035
|
|
|
3003
3036
|
// src/components/CustomPropertyDisplay.jsx
|
|
3004
|
-
import React3, { useState as
|
|
3037
|
+
import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
3005
3038
|
import { FiCheck, FiX, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
|
|
3006
3039
|
function CustomPropertyDisplay({
|
|
3007
3040
|
prop,
|
|
@@ -3016,12 +3049,12 @@ function CustomPropertyDisplay({
|
|
|
3016
3049
|
},
|
|
3017
3050
|
onUploadFile
|
|
3018
3051
|
}) {
|
|
3019
|
-
const [isEditing, setIsEditing] =
|
|
3020
|
-
const [tempProp, setTempProp] =
|
|
3021
|
-
const [isHovered, setIsHovered] =
|
|
3022
|
-
const [isTypeDropdownOpen, setIsTypeDropdownOpen] =
|
|
3052
|
+
const [isEditing, setIsEditing] = useState4(prop.isEditing ?? false);
|
|
3053
|
+
const [tempProp, setTempProp] = useState4(prop);
|
|
3054
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
3055
|
+
const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState4(false);
|
|
3023
3056
|
const dropdownRef = useRef3(null);
|
|
3024
|
-
const [uploadingItemIndex, setUploadingItemIndex] =
|
|
3057
|
+
const [uploadingItemIndex, setUploadingItemIndex] = useState4(null);
|
|
3025
3058
|
const fileInputRef = useRef3(null);
|
|
3026
3059
|
const currentUploadTargetRef = useRef3(null);
|
|
3027
3060
|
useEffect3(() => {
|
|
@@ -3144,8 +3177,8 @@ function CustomPropertyDisplay({
|
|
|
3144
3177
|
const availableOptions = [
|
|
3145
3178
|
{ value: "links", label: "Links", unique: true },
|
|
3146
3179
|
{ value: "images", label: "Images", unique: true },
|
|
3147
|
-
{ value: "documents", label: "Documents", unique: true },
|
|
3148
3180
|
{ value: "date", label: "Data", unique: true },
|
|
3181
|
+
{ value: "documents", label: "Documents", unique: true },
|
|
3149
3182
|
{ value: "text", label: "Texto", unique: false },
|
|
3150
3183
|
{ value: "number", label: "N\xFAmero", unique: false },
|
|
3151
3184
|
{ value: "list", label: "Lista", unique: false }
|
|
@@ -3367,15 +3400,15 @@ function CustomPropertyDisplay({
|
|
|
3367
3400
|
import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
|
|
3368
3401
|
|
|
3369
3402
|
// src/components/DescriptionEditModal.jsx
|
|
3370
|
-
import React5, { useState as
|
|
3371
|
-
import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage } from "react-icons/fi";
|
|
3403
|
+
import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
|
|
3404
|
+
import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage, FiCheckSquare } from "react-icons/fi";
|
|
3372
3405
|
|
|
3373
3406
|
// src/components/SectionImportModal.jsx
|
|
3374
|
-
import React4, { useState as
|
|
3407
|
+
import React4, { useState as useState5, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
3375
3408
|
import { FiSearch, FiLayers as FiLayers2, FiHexagon, FiClock, FiCheck as FiCheck2, FiCopy, FiTerminal, FiChevronDown as FiChevronDown2, FiChevronRight, FiDownload, FiLink } from "react-icons/fi";
|
|
3376
3409
|
var CodeBlock = ({ content, isActive, onClick }) => {
|
|
3377
|
-
const [isExpanded, setIsExpanded] =
|
|
3378
|
-
const [copied, setCopied] =
|
|
3410
|
+
const [isExpanded, setIsExpanded] = useState5(false);
|
|
3411
|
+
const [copied, setCopied] = useState5(false);
|
|
3379
3412
|
const cleanContent = content.replace(/^```|```$/g, "").trim();
|
|
3380
3413
|
const isLongCode = cleanContent.split("\n").length > 4;
|
|
3381
3414
|
const handleCopy = (e) => {
|
|
@@ -3438,12 +3471,14 @@ var formatLineContent = (line) => {
|
|
|
3438
3471
|
return /* @__PURE__ */ React4.createElement("span", { className: "break-words" }, line);
|
|
3439
3472
|
};
|
|
3440
3473
|
function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], availableAncestries = [] }) {
|
|
3441
|
-
const [searchTerm, setSearchTerm] =
|
|
3442
|
-
const [selectedItem, setSelectedItem] =
|
|
3443
|
-
const [searchHistory, setSearchHistory] =
|
|
3444
|
-
const [activeIndex, setActiveIndex] =
|
|
3474
|
+
const [searchTerm, setSearchTerm] = useState5("");
|
|
3475
|
+
const [selectedItem, setSelectedItem] = useState5(null);
|
|
3476
|
+
const [searchHistory, setSearchHistory] = useState5([]);
|
|
3477
|
+
const [activeIndex, setActiveIndex] = useState5(0);
|
|
3478
|
+
const [selectedIndices, setSelectedIndices] = useState5(/* @__PURE__ */ new Set([0]));
|
|
3479
|
+
const [lastSelectedIndex, setLastSelectedIndex] = useState5(0);
|
|
3445
3480
|
const sectionRefs = useRef4([]);
|
|
3446
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
3481
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState5(false);
|
|
3447
3482
|
const inputRef = useRef4(null);
|
|
3448
3483
|
useEffect4(() => {
|
|
3449
3484
|
if (!selectedItem) return;
|
|
@@ -3490,6 +3525,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3490
3525
|
}, [selectedItem]);
|
|
3491
3526
|
useEffect4(() => {
|
|
3492
3527
|
setActiveIndex(0);
|
|
3528
|
+
setSelectedIndices(/* @__PURE__ */ new Set([0]));
|
|
3529
|
+
setLastSelectedIndex(0);
|
|
3493
3530
|
}, [selectedItem]);
|
|
3494
3531
|
useEffect4(() => {
|
|
3495
3532
|
if (selectedItem && sectionRefs.current[activeIndex]) {
|
|
@@ -3506,22 +3543,64 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3506
3543
|
if (document.activeElement === inputRef.current) return;
|
|
3507
3544
|
if (e.key === "ArrowDown" || e.key === "ArrowRight") {
|
|
3508
3545
|
e.preventDefault();
|
|
3509
|
-
setActiveIndex((prev) =>
|
|
3546
|
+
setActiveIndex((prev) => {
|
|
3547
|
+
const next = Math.min(prev + 1, itemSections.length - 1);
|
|
3548
|
+
if (e.shiftKey) {
|
|
3549
|
+
setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
|
|
3550
|
+
} else if (!e.ctrlKey && !e.metaKey) {
|
|
3551
|
+
setSelectedIndices(/* @__PURE__ */ new Set([next]));
|
|
3552
|
+
setLastSelectedIndex(next);
|
|
3553
|
+
}
|
|
3554
|
+
return next;
|
|
3555
|
+
});
|
|
3510
3556
|
}
|
|
3511
3557
|
if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
|
|
3512
3558
|
e.preventDefault();
|
|
3513
|
-
setActiveIndex((prev) =>
|
|
3559
|
+
setActiveIndex((prev) => {
|
|
3560
|
+
const next = Math.max(prev - 1, 0);
|
|
3561
|
+
if (e.shiftKey) {
|
|
3562
|
+
setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
|
|
3563
|
+
} else if (!e.ctrlKey && !e.metaKey) {
|
|
3564
|
+
setSelectedIndices(/* @__PURE__ */ new Set([next]));
|
|
3565
|
+
setLastSelectedIndex(next);
|
|
3566
|
+
}
|
|
3567
|
+
return next;
|
|
3568
|
+
});
|
|
3514
3569
|
}
|
|
3515
3570
|
if (e.key === "Enter") {
|
|
3516
3571
|
e.preventDefault();
|
|
3517
|
-
|
|
3518
|
-
handleConfirmImport(itemSections[activeIndex]);
|
|
3519
|
-
}
|
|
3572
|
+
handleConfirmImport();
|
|
3520
3573
|
}
|
|
3521
3574
|
};
|
|
3522
3575
|
window.addEventListener("keydown", handleKeyDown);
|
|
3523
3576
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3524
|
-
}, [itemSections,
|
|
3577
|
+
}, [itemSections, selectedItem]);
|
|
3578
|
+
const handleSectionClick = (index, e) => {
|
|
3579
|
+
e.stopPropagation();
|
|
3580
|
+
if (e.shiftKey && lastSelectedIndex !== null) {
|
|
3581
|
+
const start = Math.min(lastSelectedIndex, index);
|
|
3582
|
+
const end = Math.max(lastSelectedIndex, index);
|
|
3583
|
+
const newSelection = new Set(selectedIndices);
|
|
3584
|
+
for (let i = start; i <= end; i++) {
|
|
3585
|
+
newSelection.add(i);
|
|
3586
|
+
}
|
|
3587
|
+
setSelectedIndices(newSelection);
|
|
3588
|
+
} else if (e.ctrlKey || e.metaKey) {
|
|
3589
|
+
const newSelection = new Set(selectedIndices);
|
|
3590
|
+
if (newSelection.has(index)) {
|
|
3591
|
+
newSelection.delete(index);
|
|
3592
|
+
if (newSelection.size === 0) newSelection.add(index);
|
|
3593
|
+
} else {
|
|
3594
|
+
newSelection.add(index);
|
|
3595
|
+
}
|
|
3596
|
+
setSelectedIndices(newSelection);
|
|
3597
|
+
setLastSelectedIndex(index);
|
|
3598
|
+
} else {
|
|
3599
|
+
setSelectedIndices(/* @__PURE__ */ new Set([index]));
|
|
3600
|
+
setLastSelectedIndex(index);
|
|
3601
|
+
}
|
|
3602
|
+
setActiveIndex(index);
|
|
3603
|
+
};
|
|
3525
3604
|
const handleSelectItem = (item) => {
|
|
3526
3605
|
setSelectedItem(item);
|
|
3527
3606
|
setSearchHistory((prev) => {
|
|
@@ -3535,16 +3614,22 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3535
3614
|
setSearchTerm("");
|
|
3536
3615
|
setIsDropdownOpen(false);
|
|
3537
3616
|
};
|
|
3538
|
-
const handleConfirmImport = (
|
|
3539
|
-
|
|
3540
|
-
if (!section) return;
|
|
3617
|
+
const handleConfirmImport = () => {
|
|
3618
|
+
if (selectedIndices.size === 0) return;
|
|
3541
3619
|
const type = selectedItem._type;
|
|
3542
3620
|
const itemId = selectedItem.id || selectedItem.ancestry_id;
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3621
|
+
const indicesToImport = Array.from(selectedIndices).sort((a, b) => a - b);
|
|
3622
|
+
const tagsToImport = [];
|
|
3623
|
+
indicesToImport.forEach((idx) => {
|
|
3624
|
+
const section = itemSections[idx];
|
|
3625
|
+
if (section && section.id) {
|
|
3626
|
+
tagsToImport.push(`[[REF:${type}:${itemId}:${section.id}]]`);
|
|
3627
|
+
}
|
|
3628
|
+
});
|
|
3629
|
+
if (tagsToImport.length > 0) {
|
|
3630
|
+
onSelect(tagsToImport);
|
|
3546
3631
|
} else {
|
|
3547
|
-
alert("
|
|
3632
|
+
alert("Nenhuma se\xE7\xE3o v\xE1lida selecionada.");
|
|
3548
3633
|
}
|
|
3549
3634
|
};
|
|
3550
3635
|
const renderSectionContent = (content) => {
|
|
@@ -3615,7 +3700,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3615
3700
|
/* @__PURE__ */ React4.createElement("div", { className: "truncate" }, /* @__PURE__ */ React4.createElement("div", { className: "text-sm font-medium text-slate-200 truncate" }, item.name), /* @__PURE__ */ React4.createElement("div", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, isNode ? ((_a = item.version_node) == null ? void 0 : _a.is_version) ? "Vers\xE3o" : "Node" : "Ancestralidade"))
|
|
3616
3701
|
);
|
|
3617
3702
|
}))), /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col bg-black/20 relative z-10" }, selectedItem ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 pr-8" }, /* @__PURE__ */ React4.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap" }, itemSections.map((section, index) => {
|
|
3618
|
-
const
|
|
3703
|
+
const isSelected = selectedIndices.has(index);
|
|
3704
|
+
const isFocused = index === activeIndex;
|
|
3619
3705
|
const match = section.content.match(/^(\s*)([\s\S]*?)(\s*)$/);
|
|
3620
3706
|
let leadingSpace = match ? match[1] : "";
|
|
3621
3707
|
const bodyText = match ? match[2] : section.content;
|
|
@@ -3633,10 +3719,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3633
3719
|
refAssigned = true;
|
|
3634
3720
|
}
|
|
3635
3721
|
},
|
|
3636
|
-
onClick: () =>
|
|
3722
|
+
onClick: (e) => handleSectionClick(index, e),
|
|
3637
3723
|
className: `
|
|
3638
3724
|
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
3639
|
-
${
|
|
3725
|
+
${isSelected ? "bg-indigo-500/30 ring-1 ring-indigo-500/50" : "hover:bg-white/5"}
|
|
3726
|
+
${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
|
|
3640
3727
|
`
|
|
3641
3728
|
},
|
|
3642
3729
|
renderSectionContent(bodyText)
|
|
@@ -3657,8 +3744,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3657
3744
|
CodeBlock,
|
|
3658
3745
|
{
|
|
3659
3746
|
content: part,
|
|
3660
|
-
isActive,
|
|
3661
|
-
onClick: () =>
|
|
3747
|
+
isActive: isSelected,
|
|
3748
|
+
onClick: (e) => handleSectionClick(index, e)
|
|
3662
3749
|
}
|
|
3663
3750
|
)
|
|
3664
3751
|
);
|
|
@@ -3668,7 +3755,7 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3668
3755
|
const isLastLine = lineIndex === lines.length - 1;
|
|
3669
3756
|
const isEmptyLine = line.trim() === "";
|
|
3670
3757
|
if (isEmptyLine) {
|
|
3671
|
-
return /* @__PURE__ */ React4.createElement(
|
|
3758
|
+
return /* @__PURE__ */ React4.createElement("br", { key: `${index}-${partIndex}-${lineIndex}` });
|
|
3672
3759
|
}
|
|
3673
3760
|
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: `${index}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React4.createElement(
|
|
3674
3761
|
"span",
|
|
@@ -3679,10 +3766,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3679
3766
|
refAssigned = true;
|
|
3680
3767
|
}
|
|
3681
3768
|
},
|
|
3682
|
-
onClick: () =>
|
|
3769
|
+
onClick: (e) => handleSectionClick(index, e),
|
|
3683
3770
|
className: `
|
|
3684
|
-
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
3685
|
-
${
|
|
3771
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone select-none
|
|
3772
|
+
${isSelected ? "bg-indigo-500/30 text-white ring-1 ring-indigo-500/50 shadow-sm" : "hover:bg-white/5 hover:text-slate-200"}
|
|
3773
|
+
${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
|
|
3686
3774
|
`
|
|
3687
3775
|
},
|
|
3688
3776
|
formatLineContent(line)
|
|
@@ -3696,7 +3784,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3696
3784
|
className: "flex items-center gap-2 px-6 py-2.5 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-semibold rounded-lg shadow-lg shadow-indigo-500/20 transition-all transform active:scale-95"
|
|
3697
3785
|
},
|
|
3698
3786
|
/* @__PURE__ */ React4.createElement(FiDownload, { className: "text-indigo-200" }),
|
|
3699
|
-
"Importar
|
|
3787
|
+
"Importar ",
|
|
3788
|
+
selectedIndices.size > 1 ? `${selectedIndices.size} Se\xE7\xF5es` : "Se\xE7\xE3o"
|
|
3700
3789
|
))) : /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col items-center justify-center text-slate-500" }, /* @__PURE__ */ React4.createElement("div", { className: "w-16 h-16 rounded-full bg-white/5 flex items-center justify-center mb-4" }, /* @__PURE__ */ React4.createElement(FiSearch, { size: 24, className: "opacity-50" })), /* @__PURE__ */ React4.createElement("p", null, "Selecione um item \xE0 esquerda para visualizar suas se\xE7\xF5es."))))
|
|
3701
3790
|
));
|
|
3702
3791
|
}
|
|
@@ -3728,16 +3817,22 @@ function DescriptionEditModal({
|
|
|
3728
3817
|
availableAncestries = [],
|
|
3729
3818
|
availableImages = []
|
|
3730
3819
|
}) {
|
|
3731
|
-
const
|
|
3820
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.9 : 1200;
|
|
3821
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize } = useResizablePanel({
|
|
3822
|
+
initialWidth: 700,
|
|
3823
|
+
minWidth: 400,
|
|
3824
|
+
maxWidth: maxPanelW
|
|
3825
|
+
});
|
|
3826
|
+
const [text, setText] = useState6(initialValue || "");
|
|
3732
3827
|
const textareaRef = useRef5(null);
|
|
3733
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
3734
|
-
const [isMentionModalOpen, setIsMentionModalOpen] =
|
|
3735
|
-
const [mentionSearch, setMentionSearch] =
|
|
3736
|
-
const [mentionTriggerIndex, setMentionTriggerIndex] =
|
|
3737
|
-
const [isImageModalOpen, setIsImageModalOpen] =
|
|
3738
|
-
const [manualImageUrl, setManualImageUrl] =
|
|
3828
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState6(false);
|
|
3829
|
+
const [isMentionModalOpen, setIsMentionModalOpen] = useState6(false);
|
|
3830
|
+
const [mentionSearch, setMentionSearch] = useState6("");
|
|
3831
|
+
const [mentionTriggerIndex, setMentionTriggerIndex] = useState6(null);
|
|
3832
|
+
const [isImageModalOpen, setIsImageModalOpen] = useState6(false);
|
|
3833
|
+
const [manualImageUrl, setManualImageUrl] = useState6("");
|
|
3739
3834
|
const hoverTimeoutRef = useRef5(null);
|
|
3740
|
-
const [tooltipData, setTooltipData] =
|
|
3835
|
+
const [tooltipData, setTooltipData] = useState6(null);
|
|
3741
3836
|
useEffect5(() => {
|
|
3742
3837
|
const handleKeyDown = (e) => {
|
|
3743
3838
|
if (e.key === "Escape") {
|
|
@@ -3830,12 +3925,28 @@ function DescriptionEditModal({
|
|
|
3830
3925
|
const uniqueSuffix = v4_default().slice(0, 4);
|
|
3831
3926
|
insertAtCursor(`*/${nextNum}:${uniqueSuffix}/ `);
|
|
3832
3927
|
};
|
|
3833
|
-
const handleImportSelect = (
|
|
3834
|
-
const
|
|
3835
|
-
const
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3928
|
+
const handleImportSelect = (tags) => {
|
|
3929
|
+
const tagsArray = Array.isArray(tags) ? tags : [tags];
|
|
3930
|
+
const el = textareaRef.current;
|
|
3931
|
+
if (!el) return;
|
|
3932
|
+
let currentText = text;
|
|
3933
|
+
let currentNum = getNextSectionNumber(currentText);
|
|
3934
|
+
let blockToInsert = "";
|
|
3935
|
+
tagsArray.forEach((tag) => {
|
|
3936
|
+
const uniqueSuffix = v4_default().slice(0, 4);
|
|
3937
|
+
blockToInsert += `
|
|
3938
|
+
*/${currentNum}:${uniqueSuffix}/ ${tag}
|
|
3939
|
+
`;
|
|
3940
|
+
currentNum++;
|
|
3941
|
+
});
|
|
3942
|
+
const start = el.selectionStart;
|
|
3943
|
+
const end = el.selectionEnd;
|
|
3944
|
+
const newText = currentText.substring(0, start) + blockToInsert + currentText.substring(end);
|
|
3945
|
+
el.value = newText;
|
|
3946
|
+
el.setSelectionRange(start + blockToInsert.length, start + blockToInsert.length);
|
|
3947
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3948
|
+
el.focus();
|
|
3949
|
+
setText(newText);
|
|
3839
3950
|
setIsImportModalOpen(false);
|
|
3840
3951
|
};
|
|
3841
3952
|
const handleMentionSelect = (node) => {
|
|
@@ -3871,6 +3982,70 @@ function DescriptionEditModal({
|
|
|
3871
3982
|
setIsMentionModalOpen(true);
|
|
3872
3983
|
}
|
|
3873
3984
|
};
|
|
3985
|
+
const handleKeyDownTextarea = (e) => {
|
|
3986
|
+
const el = textareaRef.current;
|
|
3987
|
+
if (!el) return;
|
|
3988
|
+
if (e.key === "Enter") {
|
|
3989
|
+
const cursorPosition = el.selectionStart;
|
|
3990
|
+
const textBeforeCursor = text.substring(0, cursorPosition);
|
|
3991
|
+
const linesBeforeCursor = textBeforeCursor.split("\n");
|
|
3992
|
+
const currentLine = linesBeforeCursor[linesBeforeCursor.length - 1];
|
|
3993
|
+
const numberMatch = currentLine.match(/^(\s*)(\d+)\.\s(.*)/);
|
|
3994
|
+
if (numberMatch) {
|
|
3995
|
+
e.preventDefault();
|
|
3996
|
+
const space = numberMatch[1];
|
|
3997
|
+
const number = parseInt(numberMatch[2], 10);
|
|
3998
|
+
const content = numberMatch[3];
|
|
3999
|
+
if (content.trim() === "") {
|
|
4000
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
4001
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
4002
|
+
el.value = newText;
|
|
4003
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
4004
|
+
setText(newText);
|
|
4005
|
+
return;
|
|
4006
|
+
}
|
|
4007
|
+
const nextNumber = number + 1;
|
|
4008
|
+
insertAtCursor(`
|
|
4009
|
+
${space}${nextNumber}. `);
|
|
4010
|
+
return;
|
|
4011
|
+
}
|
|
4012
|
+
const checklistMatch = currentLine.match(/^(\s*)- \[[ xX]\]\s(.*)/);
|
|
4013
|
+
if (checklistMatch) {
|
|
4014
|
+
e.preventDefault();
|
|
4015
|
+
const space = checklistMatch[1];
|
|
4016
|
+
const content = checklistMatch[2];
|
|
4017
|
+
if (content.trim() === "") {
|
|
4018
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
4019
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
4020
|
+
el.value = newText;
|
|
4021
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
4022
|
+
setText(newText);
|
|
4023
|
+
return;
|
|
4024
|
+
}
|
|
4025
|
+
insertAtCursor(`
|
|
4026
|
+
${space}- [ ] `);
|
|
4027
|
+
return;
|
|
4028
|
+
}
|
|
4029
|
+
const bulletMatch = currentLine.match(/^(\s*)([-*])\s(.*)/);
|
|
4030
|
+
if (bulletMatch) {
|
|
4031
|
+
e.preventDefault();
|
|
4032
|
+
const space = bulletMatch[1];
|
|
4033
|
+
const bullet = bulletMatch[2];
|
|
4034
|
+
const content = bulletMatch[3];
|
|
4035
|
+
if (content.trim() === "") {
|
|
4036
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
4037
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
4038
|
+
el.value = newText;
|
|
4039
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
4040
|
+
setText(newText);
|
|
4041
|
+
return;
|
|
4042
|
+
}
|
|
4043
|
+
insertAtCursor(`
|
|
4044
|
+
${space}${bullet} `);
|
|
4045
|
+
return;
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
};
|
|
3874
4049
|
const openMentionModalViaButton = () => {
|
|
3875
4050
|
setMentionTriggerIndex(null);
|
|
3876
4051
|
setIsMentionModalOpen(true);
|
|
@@ -3880,7 +4055,8 @@ function DescriptionEditModal({
|
|
|
3880
4055
|
return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement("div", { className: "fixed inset-0 z-[2000] flex justify-end pointer-events-none bg-transparent" }, /* @__PURE__ */ React5.createElement(
|
|
3881
4056
|
"div",
|
|
3882
4057
|
{
|
|
3883
|
-
className:
|
|
4058
|
+
className: `ui-overlay pointer-events-auto relative group h-full border-l border-white/10 bg-slate-950/95 shadow-2xl text-white flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
4059
|
+
style: { width: `${panelWidth}px`, maxWidth: "90vw" },
|
|
3884
4060
|
onClick: swallow,
|
|
3885
4061
|
onPointerDown: swallow,
|
|
3886
4062
|
onPointerMove: swallow,
|
|
@@ -3889,13 +4065,24 @@ function DescriptionEditModal({
|
|
|
3889
4065
|
onContextMenu: swallow,
|
|
3890
4066
|
onDoubleClick: swallow
|
|
3891
4067
|
},
|
|
4068
|
+
/* @__PURE__ */ React5.createElement(
|
|
4069
|
+
"div",
|
|
4070
|
+
{
|
|
4071
|
+
onPointerDown: (e) => {
|
|
4072
|
+
e.stopPropagation();
|
|
4073
|
+
handleResize(e);
|
|
4074
|
+
},
|
|
4075
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
4076
|
+
title: "Arraste para redimensionar"
|
|
4077
|
+
}
|
|
4078
|
+
),
|
|
3892
4079
|
/* @__PURE__ */ React5.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 shrink-0" }),
|
|
3893
4080
|
/* @__PURE__ */ React5.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React5.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80" }), /* @__PURE__ */ React5.createElement("p", { className: "text-sm font-medium text-slate-200" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ React5.createElement("button", { onClick: handleClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
|
|
3894
|
-
/* @__PURE__ */ React5.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2
|
|
4081
|
+
/* @__PURE__ */ React5.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ React5.createElement(
|
|
3895
4082
|
"button",
|
|
3896
4083
|
{
|
|
3897
4084
|
onClick: () => insertAtCursor("# "),
|
|
3898
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4085
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3899
4086
|
title: "T\xEDtulo Principal"
|
|
3900
4087
|
},
|
|
3901
4088
|
/* @__PURE__ */ React5.createElement(FiType, { size: 12 }),
|
|
@@ -3904,7 +4091,7 @@ function DescriptionEditModal({
|
|
|
3904
4091
|
"button",
|
|
3905
4092
|
{
|
|
3906
4093
|
onClick: () => insertAtCursor("## "),
|
|
3907
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4094
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3908
4095
|
title: "Subt\xEDtulo"
|
|
3909
4096
|
},
|
|
3910
4097
|
/* @__PURE__ */ React5.createElement(FiType, { size: 10 }),
|
|
@@ -3913,16 +4100,34 @@ function DescriptionEditModal({
|
|
|
3913
4100
|
"button",
|
|
3914
4101
|
{
|
|
3915
4102
|
onClick: () => insertAtCursor("- "),
|
|
3916
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4103
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3917
4104
|
title: "Lista com bullets"
|
|
3918
4105
|
},
|
|
3919
4106
|
/* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
|
|
3920
4107
|
" Lista"
|
|
4108
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4109
|
+
"button",
|
|
4110
|
+
{
|
|
4111
|
+
onClick: () => insertAtCursor("1. "),
|
|
4112
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
4113
|
+
title: "Lista Numerada"
|
|
4114
|
+
},
|
|
4115
|
+
/* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
|
|
4116
|
+
" Numerada"
|
|
4117
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4118
|
+
"button",
|
|
4119
|
+
{
|
|
4120
|
+
onClick: () => insertAtCursor("- [ ] "),
|
|
4121
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
4122
|
+
title: "Checklist (Checkbox)"
|
|
4123
|
+
},
|
|
4124
|
+
/* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
|
|
4125
|
+
" Checklist"
|
|
3921
4126
|
), /* @__PURE__ */ React5.createElement(
|
|
3922
4127
|
"button",
|
|
3923
4128
|
{
|
|
3924
4129
|
onClick: () => insertAtCursor("``` ```"),
|
|
3925
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4130
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3926
4131
|
title: "Inserir Code Block"
|
|
3927
4132
|
},
|
|
3928
4133
|
/* @__PURE__ */ React5.createElement(FiCode, { size: 12 }),
|
|
@@ -3931,21 +4136,21 @@ function DescriptionEditModal({
|
|
|
3931
4136
|
"button",
|
|
3932
4137
|
{
|
|
3933
4138
|
onClick: () => insertAtCursor("[Link Texto](https://)"),
|
|
3934
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4139
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3935
4140
|
title: "Inserir Link Web [Texto](Url)"
|
|
3936
4141
|
},
|
|
3937
4142
|
/* @__PURE__ */ React5.createElement(FiGlobe, { size: 12 }),
|
|
3938
4143
|
" Link"
|
|
3939
|
-
), /* @__PURE__ */ React5.createElement(
|
|
4144
|
+
)), /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ React5.createElement(
|
|
3940
4145
|
"button",
|
|
3941
4146
|
{
|
|
3942
4147
|
onClick: () => setIsImageModalOpen(true),
|
|
3943
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-
|
|
4148
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 border border-indigo-500/30 text-indigo-200 text-xs font-medium transition-colors whitespace-nowrap",
|
|
3944
4149
|
title: "Inserir Imagem (Propriedade ou URL)"
|
|
3945
4150
|
},
|
|
3946
4151
|
/* @__PURE__ */ React5.createElement(FiImage, { size: 12 }),
|
|
3947
4152
|
" Imagem"
|
|
3948
|
-
)
|
|
4153
|
+
), /* @__PURE__ */ React5.createElement(
|
|
3949
4154
|
"button",
|
|
3950
4155
|
{
|
|
3951
4156
|
onClick: openMentionModalViaButton,
|
|
@@ -3978,6 +4183,7 @@ function DescriptionEditModal({
|
|
|
3978
4183
|
ref: textareaRef,
|
|
3979
4184
|
value: text,
|
|
3980
4185
|
onChange: handleTextChange,
|
|
4186
|
+
onKeyDown: handleKeyDownTextarea,
|
|
3981
4187
|
placeholder: "Escreva aqui... Use *// para dividir o texto em 'Sess\xF5es'... Digite @ para mencionar...",
|
|
3982
4188
|
autoFocus: true,
|
|
3983
4189
|
className: "w-full flex-1 h-full bg-slate-800/70 p-4 text-sm leading-relaxed rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 custom-scrollbar font-mono resize-none"
|
|
@@ -4080,11 +4286,11 @@ function DescriptionEditModal({
|
|
|
4080
4286
|
}
|
|
4081
4287
|
|
|
4082
4288
|
// src/components/DescriptionDisplay.jsx
|
|
4083
|
-
import React6, { useMemo as useMemo5, useState as
|
|
4084
|
-
import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2 } from "react-icons/fi";
|
|
4289
|
+
import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
|
|
4290
|
+
import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2, FiSave } from "react-icons/fi";
|
|
4085
4291
|
var CodeBlock2 = ({ content, isActive, onClick }) => {
|
|
4086
|
-
const [isExpanded, setIsExpanded] =
|
|
4087
|
-
const [copied, setCopied] =
|
|
4292
|
+
const [isExpanded, setIsExpanded] = useState7(false);
|
|
4293
|
+
const [copied, setCopied] = useState7(false);
|
|
4088
4294
|
const cleanContent = content.replace(/^```|```$/g, "").trim();
|
|
4089
4295
|
const isLongCode = cleanContent.split("\n").length > 4;
|
|
4090
4296
|
const handleCopy = (e) => {
|
|
@@ -4118,8 +4324,7 @@ var CodeBlock2 = ({ content, isActive, onClick }) => {
|
|
|
4118
4324
|
"button",
|
|
4119
4325
|
{
|
|
4120
4326
|
onClick: handleCopy,
|
|
4121
|
-
className: "flex items-center gap-1.5 px-2 py-1 rounded hover:bg-white/10 transition-colors text-xs text-slate-400 hover:text-white"
|
|
4122
|
-
title: "Copiar c\xF3digo"
|
|
4327
|
+
className: "flex items-center gap-1.5 px-2 py-1 rounded hover:bg-white/10 transition-colors text-xs text-slate-400 hover:text-white"
|
|
4123
4328
|
},
|
|
4124
4329
|
copied ? /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-emerald-400" }) : /* @__PURE__ */ React6.createElement(FiCopy2, { size: 12 }),
|
|
4125
4330
|
copied ? /* @__PURE__ */ React6.createElement("span", { className: "text-emerald-400" }, "Copiado") : /* @__PURE__ */ React6.createElement("span", null, "Copiar")
|
|
@@ -4148,8 +4353,7 @@ var renderLinks = (text) => {
|
|
|
4148
4353
|
target: "_blank",
|
|
4149
4354
|
rel: "noopener noreferrer",
|
|
4150
4355
|
className: "inline-flex items-center gap-0.5 text-cyan-400 hover:text-cyan-300 hover:underline decoration-cyan-500/50 underline-offset-2 transition-colors cursor-pointer",
|
|
4151
|
-
onClick: (e) => e.stopPropagation()
|
|
4152
|
-
title: `Abrir link externo: ${url}`
|
|
4356
|
+
onClick: (e) => e.stopPropagation()
|
|
4153
4357
|
},
|
|
4154
4358
|
part,
|
|
4155
4359
|
/* @__PURE__ */ React6.createElement(FiExternalLink2, { size: 10, className: "opacity-70 mb-0.5" })
|
|
@@ -4178,8 +4382,7 @@ var renderTextWithImages = (text, onImageClick) => {
|
|
|
4178
4382
|
e.stopPropagation();
|
|
4179
4383
|
onImageClick == null ? void 0 : onImageClick(url, name);
|
|
4180
4384
|
},
|
|
4181
|
-
className: "inline-flex items-center gap-1 text-emerald-400 hover:text-emerald-300 hover:underline decoration-emerald-500/50 underline-offset-2 transition-colors cursor-pointer align-baseline mx-0.5"
|
|
4182
|
-
title: `Ver imagem: ${name}`
|
|
4385
|
+
className: "inline-flex items-center gap-1 text-emerald-400 hover:text-emerald-300 hover:underline decoration-emerald-500/50 underline-offset-2 transition-colors cursor-pointer align-baseline mx-0.5"
|
|
4183
4386
|
},
|
|
4184
4387
|
/* @__PURE__ */ React6.createElement(FiImage2, { size: 11 }),
|
|
4185
4388
|
/* @__PURE__ */ React6.createElement("span", null, name)
|
|
@@ -4199,7 +4402,18 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
|
|
|
4199
4402
|
}
|
|
4200
4403
|
const nodeId = part;
|
|
4201
4404
|
const node = availableNodes.find((n) => String(n.id) === String(nodeId));
|
|
4202
|
-
if (!node)
|
|
4405
|
+
if (!node) {
|
|
4406
|
+
return /* @__PURE__ */ React6.createElement(
|
|
4407
|
+
"span",
|
|
4408
|
+
{
|
|
4409
|
+
key: i,
|
|
4410
|
+
className: "inline-flex items-center gap-0.5 align-baseline font-medium px-1.5 rounded-md mx-0.5 select-none text-[0.95em] text-slate-400 bg-slate-800/40 border border-slate-600/50 border-dashed cursor-help",
|
|
4411
|
+
title: `Node externo ou n\xE3o carregado na view atual (ID: ${nodeId})`
|
|
4412
|
+
},
|
|
4413
|
+
/* @__PURE__ */ React6.createElement("span", { className: "opacity-60 text-[0.8em]" }, "@"),
|
|
4414
|
+
"Desconhecido"
|
|
4415
|
+
);
|
|
4416
|
+
}
|
|
4203
4417
|
const displayName = node.name;
|
|
4204
4418
|
const currentMentionIdx = mentionCounterRef.current;
|
|
4205
4419
|
const isMentionActive = activeMentionIndex === currentMentionIdx;
|
|
@@ -4216,15 +4430,14 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
|
|
|
4216
4430
|
className: `
|
|
4217
4431
|
inline-flex items-center gap-0.5 align-baseline font-medium px-1.5 rounded-md mx-0.5 select-none transition-all cursor-pointer text-[0.95em]
|
|
4218
4432
|
${isMentionActive ? "text-white bg-indigo-500 ring-2 ring-yellow-400 shadow-[0_0_10px_rgba(250,204,21,0.5)] z-10 relative" : "text-indigo-200 bg-indigo-600/30 border border-indigo-500/30 hover:bg-indigo-600/50 hover:text-white"}
|
|
4219
|
-
|
|
4220
|
-
title: `Clique para focar no Node: ${displayName}`
|
|
4433
|
+
`
|
|
4221
4434
|
},
|
|
4222
4435
|
/* @__PURE__ */ React6.createElement("span", { className: "opacity-60 text-[0.8em]" }, "@"),
|
|
4223
4436
|
displayName
|
|
4224
4437
|
);
|
|
4225
4438
|
});
|
|
4226
4439
|
};
|
|
4227
|
-
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
|
|
4440
|
+
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
|
|
4228
4441
|
const trimmedLine = line.replace(/\r$/, "");
|
|
4229
4442
|
const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
|
|
4230
4443
|
if (line.startsWith("# ")) {
|
|
@@ -4235,9 +4448,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
|
|
|
4235
4448
|
const content = line.replace("## ", "");
|
|
4236
4449
|
return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
|
|
4237
4450
|
}
|
|
4451
|
+
const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
|
|
4452
|
+
if (checkboxMatch) {
|
|
4453
|
+
const [_, space, state, content] = checkboxMatch;
|
|
4454
|
+
const isChecked = state.toLowerCase() === "x";
|
|
4455
|
+
const currentIdx = globalCheckboxCounterRef.current;
|
|
4456
|
+
globalCheckboxCounterRef.current += 1;
|
|
4457
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
|
|
4458
|
+
"div",
|
|
4459
|
+
{
|
|
4460
|
+
onClick: (e) => {
|
|
4461
|
+
e.stopPropagation();
|
|
4462
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4463
|
+
},
|
|
4464
|
+
className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
|
|
4465
|
+
${isChecked ? "bg-indigo-500 border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-slate-500 bg-slate-900/50 hover:border-slate-400 group-hover/checkbox:border-slate-400"}
|
|
4466
|
+
`
|
|
4467
|
+
},
|
|
4468
|
+
isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
|
|
4469
|
+
), /* @__PURE__ */ React6.createElement(
|
|
4470
|
+
"span",
|
|
4471
|
+
{
|
|
4472
|
+
className: `transition-all duration-200 cursor-pointer pt-[1px]
|
|
4473
|
+
${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
|
|
4474
|
+
`,
|
|
4475
|
+
onClick: (e) => {
|
|
4476
|
+
e.stopPropagation();
|
|
4477
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4478
|
+
}
|
|
4479
|
+
},
|
|
4480
|
+
processContent(content)
|
|
4481
|
+
));
|
|
4482
|
+
}
|
|
4483
|
+
const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
|
|
4484
|
+
if (numberMatch) {
|
|
4485
|
+
const [_, space, numberStr, content] = numberMatch;
|
|
4486
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-mono font-bold text-xs mt-[3px] shrink-0" }, numberStr), /* @__PURE__ */ React6.createElement("span", { className: "text-slate-200" }, processContent(content)));
|
|
4487
|
+
}
|
|
4238
4488
|
if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
|
|
4239
4489
|
const content = trimmedLine.trim().substring(2);
|
|
4240
|
-
return /* @__PURE__ */ React6.createElement("span", { className: "
|
|
4490
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1 text-slate-200" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold shrink-0 mt-[2px] text-xs" }, "\u2022"), /* @__PURE__ */ React6.createElement("span", null, processContent(content)));
|
|
4241
4491
|
}
|
|
4242
4492
|
return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
|
|
4243
4493
|
};
|
|
@@ -4249,14 +4499,33 @@ function DescriptionDisplay({
|
|
|
4249
4499
|
onOpenReference,
|
|
4250
4500
|
onMentionClick,
|
|
4251
4501
|
onImageClick,
|
|
4252
|
-
// <--- NOVA PROP RECEBIDA
|
|
4253
4502
|
onSectionChange,
|
|
4254
4503
|
onBranchNav,
|
|
4255
4504
|
onHighlightNode,
|
|
4256
4505
|
initialSectionId,
|
|
4257
|
-
currentBranchDirection = null
|
|
4506
|
+
currentBranchDirection = null,
|
|
4507
|
+
onSaveDescription,
|
|
4508
|
+
onStepChange
|
|
4509
|
+
// 1. Adicione a nova prop aqui
|
|
4258
4510
|
}) {
|
|
4259
|
-
const
|
|
4511
|
+
const [localDescription, setLocalDescription] = useState7(description || "");
|
|
4512
|
+
useEffect6(() => {
|
|
4513
|
+
setLocalDescription(description || "");
|
|
4514
|
+
}, [description]);
|
|
4515
|
+
const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
|
|
4516
|
+
const globalCheckboxCounterRef = useRef6(0);
|
|
4517
|
+
const handleToggleCheckbox = (targetIndex) => {
|
|
4518
|
+
let currentIndex = 0;
|
|
4519
|
+
const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
|
|
4520
|
+
if (currentIndex === targetIndex) {
|
|
4521
|
+
currentIndex++;
|
|
4522
|
+
return state === " " ? `${space}- [x]` : `${space}- [ ]`;
|
|
4523
|
+
}
|
|
4524
|
+
currentIndex++;
|
|
4525
|
+
return match;
|
|
4526
|
+
});
|
|
4527
|
+
setLocalDescription(newDesc);
|
|
4528
|
+
};
|
|
4260
4529
|
const flatNavigation = useMemo5(() => {
|
|
4261
4530
|
const navItems = [];
|
|
4262
4531
|
sections.forEach((section, sIdx) => {
|
|
@@ -4283,7 +4552,12 @@ function DescriptionDisplay({
|
|
|
4283
4552
|
});
|
|
4284
4553
|
return navItems;
|
|
4285
4554
|
}, [sections]);
|
|
4286
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
4555
|
+
const [currentStepIndex, setCurrentStepIndex] = useState7(0);
|
|
4556
|
+
useEffect6(() => {
|
|
4557
|
+
if (onStepChange) {
|
|
4558
|
+
onStepChange(currentStepIndex);
|
|
4559
|
+
}
|
|
4560
|
+
}, [currentStepIndex, onStepChange]);
|
|
4287
4561
|
const activeRef = useRef6(null);
|
|
4288
4562
|
const lastNotifiedSectionId = useRef6(null);
|
|
4289
4563
|
const isInitialMount = useRef6(true);
|
|
@@ -4397,26 +4671,27 @@ function DescriptionDisplay({
|
|
|
4397
4671
|
}
|
|
4398
4672
|
const lines = part.replace(/\n$/, "").split("\n");
|
|
4399
4673
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
|
|
4400
|
-
const isLastLine = lineIndex === lines.length - 1;
|
|
4401
4674
|
const isEmptyLine = line.trim() === "";
|
|
4402
4675
|
if (isEmptyLine) {
|
|
4403
4676
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
|
|
4404
4677
|
}
|
|
4405
4678
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
|
|
4406
|
-
"
|
|
4679
|
+
"div",
|
|
4407
4680
|
{
|
|
4408
4681
|
ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
|
|
4409
|
-
onClick: () => {
|
|
4410
|
-
|
|
4411
|
-
|
|
4682
|
+
onClick: (e) => {
|
|
4683
|
+
if (e.target.type !== "checkbox") {
|
|
4684
|
+
const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
|
|
4685
|
+
if (idx !== -1) setCurrentStepIndex(idx);
|
|
4686
|
+
}
|
|
4412
4687
|
},
|
|
4413
4688
|
className: `
|
|
4414
|
-
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
4415
|
-
${isActiveSection ? "bg-indigo-500/
|
|
4689
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
|
|
4690
|
+
${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
|
|
4416
4691
|
`
|
|
4417
4692
|
},
|
|
4418
|
-
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
|
|
4419
|
-
)
|
|
4693
|
+
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
|
|
4694
|
+
));
|
|
4420
4695
|
}));
|
|
4421
4696
|
});
|
|
4422
4697
|
};
|
|
@@ -4434,8 +4709,7 @@ function DescriptionDisplay({
|
|
|
4434
4709
|
if (onOpenReference) {
|
|
4435
4710
|
onOpenReference({ type: resolved.type, id: resolved.sourceId });
|
|
4436
4711
|
}
|
|
4437
|
-
}
|
|
4438
|
-
title: `Ir para ${resolved.type === "node" ? "Node" : "Ancestralidade"}: ${resolved.sourceName}`
|
|
4712
|
+
}
|
|
4439
4713
|
},
|
|
4440
4714
|
/* @__PURE__ */ React6.createElement(FiCornerDownRight, { size: 12, className: "text-indigo-400" }),
|
|
4441
4715
|
/* @__PURE__ */ React6.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wide flex items-center gap-1" }, "Importado de ", /* @__PURE__ */ React6.createElement("span", { className: "font-semibold text-indigo-300 hover:underline" }, resolved.sourceName), /* @__PURE__ */ React6.createElement(FiExternalLink2, { size: 10, className: "text-slate-600" }))
|
|
@@ -4444,7 +4718,9 @@ function DescriptionDisplay({
|
|
|
4444
4718
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4445
4719
|
` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
|
|
4446
4720
|
};
|
|
4447
|
-
|
|
4721
|
+
globalCheckboxCounterRef.current = 0;
|
|
4722
|
+
const hasUnsavedChanges = localDescription !== (description || "");
|
|
4723
|
+
return /* @__PURE__ */ React6.createElement("div", { className: "relative w-full h-full min-h-[100px]" }, /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-16 pr-9" }, sections.map((section, index) => {
|
|
4448
4724
|
const currentNavItem = flatNavigation[currentStepIndex];
|
|
4449
4725
|
const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
|
|
4450
4726
|
const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
|
|
@@ -4460,11 +4736,22 @@ function DescriptionDisplay({
|
|
|
4460
4736
|
if (index === 0) leadingSpace = "";
|
|
4461
4737
|
const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
|
|
4462
4738
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: index }, /* @__PURE__ */ React6.createElement("span", null, leadingSpace), isRef ? renderReferenceSection(bodyText, index, isSectionContextActive, setRef) : renderMixedContent(bodyText, index, isSectionContextActive, activeMentionIndex, setRef), /* @__PURE__ */ React6.createElement("span", null, trailingSpace));
|
|
4463
|
-
}))
|
|
4739
|
+
})), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ React6.createElement("div", { className: "absolute bottom-2 left-2 z-[100] animate-in slide-in-from-bottom-2 fade-in duration-300" }, /* @__PURE__ */ React6.createElement(
|
|
4740
|
+
"button",
|
|
4741
|
+
{
|
|
4742
|
+
onClick: (e) => {
|
|
4743
|
+
e.stopPropagation();
|
|
4744
|
+
onSaveDescription(localDescription);
|
|
4745
|
+
},
|
|
4746
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600/90 hover:bg-indigo-500 text-white rounded-md shadow-[0_4px_12px_rgba(99,102,241,0.3)] text-xs font-medium transition-all hover:scale-105 active:scale-95 border border-indigo-400/20 backdrop-blur-sm"
|
|
4747
|
+
},
|
|
4748
|
+
/* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
|
|
4749
|
+
" Salvar Checklist"
|
|
4750
|
+
)));
|
|
4464
4751
|
}
|
|
4465
4752
|
|
|
4466
4753
|
// src/components/DescriptionReadModePanel.jsx
|
|
4467
|
-
import React7, { useState as
|
|
4754
|
+
import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
|
|
4468
4755
|
import {
|
|
4469
4756
|
FiArrowLeft,
|
|
4470
4757
|
FiEdit2,
|
|
@@ -4543,7 +4830,6 @@ function DescriptionReadModePanel({
|
|
|
4543
4830
|
title,
|
|
4544
4831
|
description,
|
|
4545
4832
|
ancestryId,
|
|
4546
|
-
// <-- NOVO: Prop recebida do XViewScene
|
|
4547
4833
|
savedSections,
|
|
4548
4834
|
onBack,
|
|
4549
4835
|
onEdit,
|
|
@@ -4565,12 +4851,14 @@ function DescriptionReadModePanel({
|
|
|
4565
4851
|
userRole,
|
|
4566
4852
|
abstractionTree = null,
|
|
4567
4853
|
onRenderAbstractionTree = null,
|
|
4568
|
-
initialShowAbstraction = false
|
|
4854
|
+
initialShowAbstraction = false,
|
|
4855
|
+
onSaveDescription
|
|
4569
4856
|
}) {
|
|
4570
|
-
const [showProperties, setShowProperties] =
|
|
4571
|
-
const [showAbstraction, setShowAbstraction] =
|
|
4572
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
4573
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
4857
|
+
const [showProperties, setShowProperties] = useState8(false);
|
|
4858
|
+
const [showAbstraction, setShowAbstraction] = useState8(false);
|
|
4859
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
|
|
4860
|
+
const [isLinkCopied, setIsLinkCopied] = useState8(false);
|
|
4861
|
+
const [isAtStartOfBranch, setIsAtStartOfBranch] = useState8(true);
|
|
4574
4862
|
const handleCopyLink = (e) => {
|
|
4575
4863
|
e.stopPropagation();
|
|
4576
4864
|
if (!ancestryId) return;
|
|
@@ -4623,7 +4911,7 @@ function DescriptionReadModePanel({
|
|
|
4623
4911
|
onClick: () => onBranchNav(activeNodeBranches.nodeId, "open", "left")
|
|
4624
4912
|
};
|
|
4625
4913
|
}
|
|
4626
|
-
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "left") {
|
|
4914
|
+
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "left" && isAtStartOfBranch) {
|
|
4627
4915
|
return {
|
|
4628
4916
|
type: "back",
|
|
4629
4917
|
name: backNavigationInfo.name,
|
|
@@ -4631,7 +4919,7 @@ function DescriptionReadModePanel({
|
|
|
4631
4919
|
};
|
|
4632
4920
|
}
|
|
4633
4921
|
return null;
|
|
4634
|
-
}, [activeNodeBranches, backNavigationInfo, onBranchNav]);
|
|
4922
|
+
}, [activeNodeBranches, backNavigationInfo, onBranchNav, isAtStartOfBranch]);
|
|
4635
4923
|
const rightAction = useMemo6(() => {
|
|
4636
4924
|
if (activeNodeBranches == null ? void 0 : activeNodeBranches.right) {
|
|
4637
4925
|
return {
|
|
@@ -4640,7 +4928,7 @@ function DescriptionReadModePanel({
|
|
|
4640
4928
|
onClick: () => onBranchNav(activeNodeBranches.nodeId, "open", "right")
|
|
4641
4929
|
};
|
|
4642
4930
|
}
|
|
4643
|
-
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "right") {
|
|
4931
|
+
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "right" && isAtStartOfBranch) {
|
|
4644
4932
|
return {
|
|
4645
4933
|
type: "back",
|
|
4646
4934
|
name: backNavigationInfo.name,
|
|
@@ -4648,11 +4936,11 @@ function DescriptionReadModePanel({
|
|
|
4648
4936
|
};
|
|
4649
4937
|
}
|
|
4650
4938
|
return null;
|
|
4651
|
-
}, [activeNodeBranches, backNavigationInfo, onBranchNav]);
|
|
4939
|
+
}, [activeNodeBranches, backNavigationInfo, onBranchNav, isAtStartOfBranch]);
|
|
4652
4940
|
return /* @__PURE__ */ React7.createElement(
|
|
4653
4941
|
"div",
|
|
4654
4942
|
{
|
|
4655
|
-
className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
|
|
4943
|
+
className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
|
|
4656
4944
|
onPointerDown: swallow,
|
|
4657
4945
|
onClick: swallow
|
|
4658
4946
|
},
|
|
@@ -4724,7 +5012,7 @@ function DescriptionReadModePanel({
|
|
|
4724
5012
|
},
|
|
4725
5013
|
"\xD7"
|
|
4726
5014
|
))),
|
|
4727
|
-
/* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
|
|
5015
|
+
/* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10 min-h-0", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
|
|
4728
5016
|
"button",
|
|
4729
5017
|
{
|
|
4730
5018
|
onClick: (e) => {
|
|
@@ -4783,7 +5071,9 @@ function DescriptionReadModePanel({
|
|
|
4783
5071
|
onHighlightNode,
|
|
4784
5072
|
initialSectionId,
|
|
4785
5073
|
currentBranchDirection,
|
|
4786
|
-
onImageClick
|
|
5074
|
+
onImageClick,
|
|
5075
|
+
onSaveDescription,
|
|
5076
|
+
onStepChange: (stepIndex) => setIsAtStartOfBranch(stepIndex === 0)
|
|
4787
5077
|
}
|
|
4788
5078
|
)),
|
|
4789
5079
|
leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
|
|
@@ -4825,11 +5115,11 @@ function AncestryRelationshipPanel({
|
|
|
4825
5115
|
onMentionClick,
|
|
4826
5116
|
onUploadFile
|
|
4827
5117
|
}) {
|
|
4828
|
-
const [description, setDescription] =
|
|
4829
|
-
const [customProps, setCustomProps] =
|
|
4830
|
-
const [existingSections, setExistingSections] =
|
|
4831
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
4832
|
-
const [isReadMode, setIsReadMode] =
|
|
5118
|
+
const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
|
|
5119
|
+
const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
|
|
5120
|
+
const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
|
|
5121
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
|
|
5122
|
+
const [isReadMode, setIsReadMode] = useState9(false);
|
|
4833
5123
|
const propsEndRef = useRef7(null);
|
|
4834
5124
|
useEffect8(() => {
|
|
4835
5125
|
setDescription((data == null ? void 0 : data.description) ?? "");
|
|
@@ -4853,6 +5143,17 @@ function AncestryRelationshipPanel({
|
|
|
4853
5143
|
return newProps;
|
|
4854
5144
|
});
|
|
4855
5145
|
};
|
|
5146
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
5147
|
+
setDescription(newDescription);
|
|
5148
|
+
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
5149
|
+
const processedSections = processDescriptionForSave(newDescription, existingSections);
|
|
5150
|
+
const dataToSave = {
|
|
5151
|
+
description: newDescription,
|
|
5152
|
+
description_sections: processedSections,
|
|
5153
|
+
...extrasObj
|
|
5154
|
+
};
|
|
5155
|
+
onSave(dataToSave);
|
|
5156
|
+
};
|
|
4856
5157
|
const handleSave = () => {
|
|
4857
5158
|
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
4858
5159
|
const processedSections = processDescriptionForSave(description, existingSections);
|
|
@@ -4902,7 +5203,8 @@ function AncestryRelationshipPanel({
|
|
|
4902
5203
|
availableAncestries,
|
|
4903
5204
|
onOpenReference,
|
|
4904
5205
|
onMentionClick,
|
|
4905
|
-
onImageClick: handleImageClickFromText
|
|
5206
|
+
onImageClick: handleImageClickFromText,
|
|
5207
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4906
5208
|
}
|
|
4907
5209
|
) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React8.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-cyan-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React8.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o de Ancestralidade")), /* @__PURE__ */ React8.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Editar Rela\xE7\xE3o")), /* @__PURE__ */ React8.createElement("button", { onClick: onClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pb-4 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React8.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o da Rela\xE7\xE3o"), /* @__PURE__ */ React8.createElement("div", { className: "relative group min-h-[60px] bg-slate-800/40 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React8.createElement(
|
|
4908
5210
|
DescriptionDisplay,
|
|
@@ -4913,7 +5215,8 @@ function AncestryRelationshipPanel({
|
|
|
4913
5215
|
availableAncestries,
|
|
4914
5216
|
onOpenReference,
|
|
4915
5217
|
onMentionClick,
|
|
4916
|
-
onImageClick: handleImageClickFromText
|
|
5218
|
+
onImageClick: handleImageClickFromText,
|
|
5219
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4917
5220
|
}
|
|
4918
5221
|
), /* @__PURE__ */ React8.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React8.createElement(
|
|
4919
5222
|
"button",
|
|
@@ -4971,7 +5274,7 @@ function AncestryRelationshipPanel({
|
|
|
4971
5274
|
}
|
|
4972
5275
|
|
|
4973
5276
|
// src/components/CreateAncestryPanel.jsx
|
|
4974
|
-
import React10, { useState as
|
|
5277
|
+
import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
|
|
4975
5278
|
import {
|
|
4976
5279
|
FiEdit2 as FiEdit23,
|
|
4977
5280
|
FiBookOpen as FiBookOpen2,
|
|
@@ -4987,11 +5290,12 @@ import {
|
|
|
4987
5290
|
FiGitBranch as FiGitBranch2,
|
|
4988
5291
|
FiPlus as FiPlus2,
|
|
4989
5292
|
FiLock,
|
|
4990
|
-
FiLink as FiLink4
|
|
5293
|
+
FiLink as FiLink4,
|
|
5294
|
+
FiTrash2 as FiTrash22
|
|
4991
5295
|
} from "react-icons/fi";
|
|
4992
5296
|
|
|
4993
5297
|
// src/components/AncestryPickerModal.jsx
|
|
4994
|
-
import React9, { useState as
|
|
5298
|
+
import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
|
|
4995
5299
|
import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
|
|
4996
5300
|
function AncestryPickerModal({
|
|
4997
5301
|
isOpen,
|
|
@@ -5001,7 +5305,7 @@ function AncestryPickerModal({
|
|
|
5001
5305
|
availableNodes = [],
|
|
5002
5306
|
currentAncestryId
|
|
5003
5307
|
}) {
|
|
5004
|
-
const [searchTerm, setSearchTerm] =
|
|
5308
|
+
const [searchTerm, setSearchTerm] = useState10("");
|
|
5005
5309
|
useEffect9(() => {
|
|
5006
5310
|
if (!isOpen) return;
|
|
5007
5311
|
const handleKeyDown = (e) => {
|
|
@@ -5086,7 +5390,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
|
|
|
5086
5390
|
var _a, _b;
|
|
5087
5391
|
const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
|
|
5088
5392
|
const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
|
|
5089
|
-
const [isDragOver, setIsDragOver] =
|
|
5393
|
+
const [isDragOver, setIsDragOver] = useState11(false);
|
|
5090
5394
|
const isSelectedParent = String(selectedParentId) === String(itemId);
|
|
5091
5395
|
const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
|
|
5092
5396
|
const isHighlightedPath = highlightedPathIds.includes(String(itemId));
|
|
@@ -5222,8 +5526,9 @@ function CreateAncestryPanel({
|
|
|
5222
5526
|
isAddingNodes,
|
|
5223
5527
|
currentAncestryId
|
|
5224
5528
|
} = ancestryMode;
|
|
5225
|
-
const [isSaving, setIsSaving] =
|
|
5226
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
5529
|
+
const [isSaving, setIsSaving] = useState11(false);
|
|
5530
|
+
const [isLinkCopied, setIsLinkCopied] = useState11(false);
|
|
5531
|
+
const [showDeleteBranchConfirm, setShowDeleteBranchConfirm] = useState11(false);
|
|
5227
5532
|
const handleCopyLink = (e) => {
|
|
5228
5533
|
e.stopPropagation();
|
|
5229
5534
|
if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
|
|
@@ -5237,11 +5542,14 @@ function CreateAncestryPanel({
|
|
|
5237
5542
|
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
5238
5543
|
}).catch((err) => console.error("Erro ao copiar link:", err));
|
|
5239
5544
|
};
|
|
5240
|
-
const [isPickerOpen, setIsPickerOpen] =
|
|
5241
|
-
const [customProps, setCustomProps] =
|
|
5545
|
+
const [isPickerOpen, setIsPickerOpen] = useState11(false);
|
|
5546
|
+
const [customProps, setCustomProps] = useState11([]);
|
|
5242
5547
|
const propsEndRef = useRef8(null);
|
|
5243
|
-
const [branchStack, setBranchStack] =
|
|
5244
|
-
|
|
5548
|
+
const [branchStack, setBranchStack] = useState11([]);
|
|
5549
|
+
useEffect10(() => {
|
|
5550
|
+
setShowDeleteBranchConfirm(false);
|
|
5551
|
+
}, [branchStack]);
|
|
5552
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
|
|
5245
5553
|
const highlightedPathIds = useMemo8(() => {
|
|
5246
5554
|
var _a, _b;
|
|
5247
5555
|
if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
|
|
@@ -5255,17 +5563,27 @@ function CreateAncestryPanel({
|
|
|
5255
5563
|
}
|
|
5256
5564
|
return ids;
|
|
5257
5565
|
}, [targetRenderNodeId, ancestryMode.abstraction_tree]);
|
|
5258
|
-
const [targetScrollSectionId, setTargetScrollSectionId] =
|
|
5259
|
-
const [internalHighlightedNodeId, setInternalHighlightedNodeId] =
|
|
5260
|
-
const [
|
|
5261
|
-
const [
|
|
5262
|
-
const [
|
|
5263
|
-
const [
|
|
5264
|
-
const [
|
|
5566
|
+
const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
|
|
5567
|
+
const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
|
|
5568
|
+
const [isAtStartOfBranch, setIsAtStartOfBranch] = useState11(true);
|
|
5569
|
+
const [ancestryName, setAncestryName] = useState11(initialName);
|
|
5570
|
+
const [description, setDescription] = useState11(initialDescription || "");
|
|
5571
|
+
const [existingSections, setExistingSections] = useState11(initialSections || []);
|
|
5572
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
|
|
5573
|
+
const [isReadMode, setIsReadMode] = useState11(false);
|
|
5574
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
5575
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
5576
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
5577
|
+
minWidth: 320,
|
|
5578
|
+
maxWidth: maxPanelW
|
|
5579
|
+
});
|
|
5580
|
+
useEffect10(() => {
|
|
5581
|
+
setWidth(isReadMode ? 700 : 440);
|
|
5582
|
+
}, [isReadMode, setWidth]);
|
|
5265
5583
|
const currentMaxRenderIndexRef = useRef8(0);
|
|
5266
5584
|
const branchProgressMapRef = useRef8({});
|
|
5267
|
-
const [lastSavedSnapshot, setLastSavedSnapshot] =
|
|
5268
|
-
const [isPrivate, setIsPrivate] =
|
|
5585
|
+
const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
|
|
5586
|
+
const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
|
|
5269
5587
|
const initializedContextIdRef = useRef8(null);
|
|
5270
5588
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
5271
5589
|
const handleImageClickFromText = (url, name) => {
|
|
@@ -5284,7 +5602,7 @@ function CreateAncestryPanel({
|
|
|
5284
5602
|
}
|
|
5285
5603
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5286
5604
|
};
|
|
5287
|
-
const handleRemoveNode =
|
|
5605
|
+
const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
|
|
5288
5606
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5289
5607
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5290
5608
|
setAncestryMode((prev) => {
|
|
@@ -5641,6 +5959,59 @@ function CreateAncestryPanel({
|
|
|
5641
5959
|
}
|
|
5642
5960
|
}
|
|
5643
5961
|
};
|
|
5962
|
+
const handleDeleteBranch = async () => {
|
|
5963
|
+
if (branchStack.length === 0) return;
|
|
5964
|
+
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
5965
|
+
let ptr = rootTreeClone;
|
|
5966
|
+
for (let i = 0; i < branchStack.length - 1; i++) {
|
|
5967
|
+
const step = branchStack[i];
|
|
5968
|
+
const found = findNodePath2(ptr, step.nodeId);
|
|
5969
|
+
if (found && found.node.parallel_branches) {
|
|
5970
|
+
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5971
|
+
if (branch) ptr = branch.tree;
|
|
5972
|
+
}
|
|
5973
|
+
}
|
|
5974
|
+
const currentStep = branchStack[branchStack.length - 1];
|
|
5975
|
+
const foundParentPath = findNodePath2(ptr, currentStep.nodeId);
|
|
5976
|
+
if (foundParentPath && foundParentPath.node && foundParentPath.node.parallel_branches) {
|
|
5977
|
+
const branchIndex = foundParentPath.node.parallel_branches.findIndex((b) => b.id === currentStep.branchId);
|
|
5978
|
+
if (branchIndex !== -1) {
|
|
5979
|
+
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
5980
|
+
updateGlobalTree(rootTreeClone);
|
|
5981
|
+
try {
|
|
5982
|
+
setIsSaving(true);
|
|
5983
|
+
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
5984
|
+
const rootExtras = toObjectFromCustomProps(currentRootProps);
|
|
5985
|
+
await onSave(
|
|
5986
|
+
ancestryMode.ancestryName,
|
|
5987
|
+
ancestryMode.ancestryDescription,
|
|
5988
|
+
ancestryMode.ancestryDescriptionSections,
|
|
5989
|
+
true,
|
|
5990
|
+
rootTreeClone,
|
|
5991
|
+
rootExtras
|
|
5992
|
+
);
|
|
5993
|
+
setLastSavedSnapshot(takeSnapshot(
|
|
5994
|
+
rootTreeClone,
|
|
5995
|
+
ancestryMode.ancestryName,
|
|
5996
|
+
ancestryMode.ancestryDescription,
|
|
5997
|
+
ancestryMode.ancestryDescriptionSections,
|
|
5998
|
+
currentRootProps,
|
|
5999
|
+
isPrivate,
|
|
6000
|
+
ancestryMode.abstraction_tree
|
|
6001
|
+
));
|
|
6002
|
+
if (onClearAncestryVisuals) {
|
|
6003
|
+
onClearAncestryVisuals(currentStep.branchId);
|
|
6004
|
+
}
|
|
6005
|
+
handleNavigateUp();
|
|
6006
|
+
} catch (err) {
|
|
6007
|
+
console.error("Erro ao remover a ramifica\xE7\xE3o:", err);
|
|
6008
|
+
alert("Erro ao remover a ramifica\xE7\xE3o.");
|
|
6009
|
+
} finally {
|
|
6010
|
+
setIsSaving(false);
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
};
|
|
5644
6015
|
const sideActions = useMemo8(() => {
|
|
5645
6016
|
const actions = { left: null, right: null };
|
|
5646
6017
|
const isInBranch = branchStack.length > 0;
|
|
@@ -5679,7 +6050,7 @@ function CreateAncestryPanel({
|
|
|
5679
6050
|
}
|
|
5680
6051
|
return actions;
|
|
5681
6052
|
}
|
|
5682
|
-
if (isInBranch) {
|
|
6053
|
+
if (isInBranch && isAtStartOfBranch) {
|
|
5683
6054
|
const lastStep = branchStack[branchStack.length - 1];
|
|
5684
6055
|
const entryDir = lastStep.entryDirection || "right";
|
|
5685
6056
|
const backSide = entryDir === "right" ? "left" : "right";
|
|
@@ -5690,7 +6061,7 @@ function CreateAncestryPanel({
|
|
|
5690
6061
|
};
|
|
5691
6062
|
}
|
|
5692
6063
|
return actions;
|
|
5693
|
-
}, [internalHighlightedNodeId, branchStack, activeTree]);
|
|
6064
|
+
}, [internalHighlightedNodeId, branchStack, activeTree, isAtStartOfBranch]);
|
|
5694
6065
|
const applyDescriptionToTree = (baseTree, descText, descSections) => {
|
|
5695
6066
|
const rootTreeClone = JSON.parse(JSON.stringify(baseTree));
|
|
5696
6067
|
let targetTree = rootTreeClone;
|
|
@@ -6168,6 +6539,10 @@ function CreateAncestryPanel({
|
|
|
6168
6539
|
setInternalHighlightedNodeId(id);
|
|
6169
6540
|
if (onHighlightNode) onHighlightNode(id);
|
|
6170
6541
|
};
|
|
6542
|
+
const handleSaveDescriptionInline = (newDesc) => {
|
|
6543
|
+
setDescription(newDesc);
|
|
6544
|
+
handleLocalSave(true, { description: newDesc });
|
|
6545
|
+
};
|
|
6171
6546
|
const swallow = (e) => e.stopPropagation();
|
|
6172
6547
|
const getSelectedParentName = () => {
|
|
6173
6548
|
if (!activeTree || !selectedParentId) return "";
|
|
@@ -6240,10 +6615,8 @@ function CreateAncestryPanel({
|
|
|
6240
6615
|
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
6241
6616
|
"div",
|
|
6242
6617
|
{
|
|
6243
|
-
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col transition-all duration-300 ease-out
|
|
6244
|
-
|
|
6245
|
-
`,
|
|
6246
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" },
|
|
6618
|
+
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
6619
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
6247
6620
|
onPointerDown: swallow,
|
|
6248
6621
|
onPointerMove: swallow,
|
|
6249
6622
|
onPointerUp: swallow,
|
|
@@ -6252,6 +6625,17 @@ function CreateAncestryPanel({
|
|
|
6252
6625
|
onContextMenu: swallow,
|
|
6253
6626
|
onDoubleClick: swallow
|
|
6254
6627
|
},
|
|
6628
|
+
/* @__PURE__ */ React10.createElement(
|
|
6629
|
+
"div",
|
|
6630
|
+
{
|
|
6631
|
+
onPointerDown: (e) => {
|
|
6632
|
+
e.stopPropagation();
|
|
6633
|
+
handleResize(e);
|
|
6634
|
+
},
|
|
6635
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
6636
|
+
title: "Arraste para redimensionar"
|
|
6637
|
+
}
|
|
6638
|
+
),
|
|
6255
6639
|
isReadMode ? /* @__PURE__ */ React10.createElement(
|
|
6256
6640
|
DescriptionReadModePanel,
|
|
6257
6641
|
{
|
|
@@ -6270,7 +6654,8 @@ function CreateAncestryPanel({
|
|
|
6270
6654
|
onMentionClick,
|
|
6271
6655
|
onSectionChange: handleSectionChangeWrapper,
|
|
6272
6656
|
onHighlightNode,
|
|
6273
|
-
onImageClick: handleImageClickFromText
|
|
6657
|
+
onImageClick: handleImageClickFromText,
|
|
6658
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6274
6659
|
}
|
|
6275
6660
|
) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 flex-shrink-0" }, /* @__PURE__ */ React10.createElement("div", { className: "w-full" }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React10.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React10.createElement("p", { className: "text-xs/relaxed text-slate-300" }, branchStack.length > 0 ? `Ramifica\xE7\xE3o (N\xEDvel ${branchStack.length})` : isEditMode ? "Editar Ancestralidade" : "Criar Ancestralidade"), currentAncestryId && currentAncestryId !== "temp_creating" && currentAncestryId !== "temp_root" && /* @__PURE__ */ React10.createElement(
|
|
6276
6661
|
"button",
|
|
@@ -6289,7 +6674,7 @@ function CreateAncestryPanel({
|
|
|
6289
6674
|
placeholder: "Nome da Ancestralidade",
|
|
6290
6675
|
className: "text-xl sm:text-2xl font-semibold tracking-tight bg-transparent border-none p-0 focus:ring-2 focus:ring-indigo-500 rounded-md -ml-1.5 px-1.5 w-full outline-none transition-all focus:bg-slate-800/70"
|
|
6291
6676
|
}
|
|
6292
|
-
)), /* @__PURE__ */ React10.createElement("button", { onClick: onClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl flex-shrink-0", title: "Cancelar" }, "\xD7")), branchStack.length > 0 && /* @__PURE__ */ React10.createElement("div", { className: "px-6 pb-2" }, /* @__PURE__ */ React10.createElement(
|
|
6677
|
+
)), /* @__PURE__ */ React10.createElement("button", { onClick: onClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl flex-shrink-0", title: "Cancelar" }, "\xD7")), branchStack.length > 0 && /* @__PURE__ */ React10.createElement("div", { className: "px-6 pb-2 flex items-center justify-between" }, /* @__PURE__ */ React10.createElement(
|
|
6293
6678
|
"button",
|
|
6294
6679
|
{
|
|
6295
6680
|
onClick: handleNavigateUp,
|
|
@@ -6297,7 +6682,33 @@ function CreateAncestryPanel({
|
|
|
6297
6682
|
},
|
|
6298
6683
|
/* @__PURE__ */ React10.createElement(FiArrowLeft2, null),
|
|
6299
6684
|
" Voltar para Principal / N\xEDvel Anterior"
|
|
6300
|
-
)
|
|
6685
|
+
), !isContextLinked && /* @__PURE__ */ React10.createElement("div", { className: "relative animate-in fade-in duration-200" }, showDeleteBranchConfirm ? /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-3 bg-rose-500/10 border border-rose-500/30 px-3 py-1 rounded-md shadow-inner" }, /* @__PURE__ */ React10.createElement("span", { className: "text-xs text-rose-300 font-medium" }, "Excluir?"), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement(
|
|
6686
|
+
"button",
|
|
6687
|
+
{
|
|
6688
|
+
onClick: () => {
|
|
6689
|
+
setShowDeleteBranchConfirm(false);
|
|
6690
|
+
handleDeleteBranch();
|
|
6691
|
+
},
|
|
6692
|
+
className: "text-xs font-bold text-rose-400 hover:text-rose-200 transition-colors"
|
|
6693
|
+
},
|
|
6694
|
+
"Sim"
|
|
6695
|
+
), /* @__PURE__ */ React10.createElement("span", { className: "text-slate-600/50" }, "|"), /* @__PURE__ */ React10.createElement(
|
|
6696
|
+
"button",
|
|
6697
|
+
{
|
|
6698
|
+
onClick: () => setShowDeleteBranchConfirm(false),
|
|
6699
|
+
className: "text-xs text-slate-400 hover:text-white transition-colors"
|
|
6700
|
+
},
|
|
6701
|
+
"N\xE3o"
|
|
6702
|
+
))) : /* @__PURE__ */ React10.createElement(
|
|
6703
|
+
"button",
|
|
6704
|
+
{
|
|
6705
|
+
onClick: () => setShowDeleteBranchConfirm(true),
|
|
6706
|
+
className: "flex items-center gap-1.5 text-xs text-rose-400/80 hover:text-white hover:bg-rose-500/20 px-2 py-1 rounded transition-colors",
|
|
6707
|
+
title: "Excluir permanentemente esta ramifica\xE7\xE3o e seu conte\xFAdo"
|
|
6708
|
+
},
|
|
6709
|
+
/* @__PURE__ */ React10.createElement(FiTrash22, null),
|
|
6710
|
+
" Excluir Ramifica\xE7\xE3o"
|
|
6711
|
+
))), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pb-4 pt-2 overflow-y-auto flex-grow custom-scrollbar" }, branchStack.length > 0 && /* @__PURE__ */ React10.createElement("div", { className: "mb-4" }, isContextLinked ? /* @__PURE__ */ React10.createElement("div", { className: "p-3 rounded-lg bg-indigo-500/10 border border-indigo-500/30 flex items-center justify-between" }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React10.createElement("div", { className: "w-8 h-8 rounded bg-indigo-500/20 text-indigo-300 grid place-content-center" }, /* @__PURE__ */ React10.createElement(FiLayers5, null)), /* @__PURE__ */ React10.createElement("div", null, /* @__PURE__ */ React10.createElement("div", { className: "text-xs text-indigo-200 font-semibold uppercase tracking-wider" }, "Ancestralidade Vinculada"), /* @__PURE__ */ React10.createElement("div", { className: "text-sm text-white font-medium truncate max-w-[200px]" }, currentContext.name.replace("[REF] ", "")))), /* @__PURE__ */ React10.createElement(
|
|
6301
6712
|
"button",
|
|
6302
6713
|
{
|
|
6303
6714
|
onClick: handleUnlinkAncestry,
|
|
@@ -6327,7 +6738,9 @@ function CreateAncestryPanel({
|
|
|
6327
6738
|
onHighlightNode: handleHighlightWrapper,
|
|
6328
6739
|
initialSectionId: targetScrollSectionId,
|
|
6329
6740
|
currentBranchDirection: currentContext ? currentContext.direction : null,
|
|
6330
|
-
onImageClick: handleImageClickFromText
|
|
6741
|
+
onImageClick: handleImageClickFromText,
|
|
6742
|
+
onSaveDescription: handleSaveDescriptionInline,
|
|
6743
|
+
onStepChange: (stepIndex) => setIsAtStartOfBranch(stepIndex === 0)
|
|
6331
6744
|
}
|
|
6332
6745
|
), /* @__PURE__ */ React10.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5 z-30" }, /* @__PURE__ */ React10.createElement(
|
|
6333
6746
|
"button",
|
|
@@ -6548,25 +6961,25 @@ function CreateAncestryPanel({
|
|
|
6548
6961
|
}
|
|
6549
6962
|
|
|
6550
6963
|
// src/components/ImageViewer.jsx
|
|
6551
|
-
import React11, { useState as
|
|
6964
|
+
import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
|
|
6552
6965
|
import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
6553
6966
|
function ImageViewer({ data, onClose }) {
|
|
6554
6967
|
var _a;
|
|
6555
6968
|
const { images = [], startIndex = 0, visible } = data;
|
|
6556
|
-
const [currentIndex, setCurrentIndex] =
|
|
6557
|
-
const [isLoading, setIsLoading] =
|
|
6558
|
-
const [loadedSrc, setLoadedSrc] =
|
|
6969
|
+
const [currentIndex, setCurrentIndex] = useState12(startIndex);
|
|
6970
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
6971
|
+
const [loadedSrc, setLoadedSrc] = useState12(null);
|
|
6559
6972
|
useLayoutEffect2(() => {
|
|
6560
6973
|
if (visible) {
|
|
6561
6974
|
setCurrentIndex(startIndex);
|
|
6562
6975
|
}
|
|
6563
6976
|
}, [visible, startIndex]);
|
|
6564
|
-
const handleNext =
|
|
6977
|
+
const handleNext = useCallback3(() => {
|
|
6565
6978
|
if (images.length > 1) {
|
|
6566
6979
|
setCurrentIndex((prev) => (prev + 1) % images.length);
|
|
6567
6980
|
}
|
|
6568
6981
|
}, [images.length]);
|
|
6569
|
-
const handlePrev =
|
|
6982
|
+
const handlePrev = useCallback3(() => {
|
|
6570
6983
|
if (images.length > 1) {
|
|
6571
6984
|
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
|
6572
6985
|
}
|
|
@@ -6671,10 +7084,10 @@ function ImageViewer({ data, onClose }) {
|
|
|
6671
7084
|
}
|
|
6672
7085
|
|
|
6673
7086
|
// src/components/InSceneCreationForm.jsx
|
|
6674
|
-
import React13, { useState as
|
|
7087
|
+
import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
6675
7088
|
|
|
6676
7089
|
// src/components/ColorPicker.jsx
|
|
6677
|
-
import React12, { useState as
|
|
7090
|
+
import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
|
|
6678
7091
|
import { HexColorPicker } from "react-colorful";
|
|
6679
7092
|
import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
|
|
6680
7093
|
var PRESET_COLORS = [
|
|
@@ -6695,7 +7108,7 @@ var PRESET_COLORS = [
|
|
|
6695
7108
|
"#000000"
|
|
6696
7109
|
];
|
|
6697
7110
|
function ColorPicker({ color, onChange, disabled }) {
|
|
6698
|
-
const [isOpen, setIsOpen] =
|
|
7111
|
+
const [isOpen, setIsOpen] = useState13(false);
|
|
6699
7112
|
const popoverRef = useRef9(null);
|
|
6700
7113
|
useEffect12(() => {
|
|
6701
7114
|
const handleClickOutside = (event) => {
|
|
@@ -6794,21 +7207,21 @@ function InSceneCreationForm({
|
|
|
6794
7207
|
viewType
|
|
6795
7208
|
}) {
|
|
6796
7209
|
var _a;
|
|
6797
|
-
const [name, setName] =
|
|
6798
|
-
const [types, setTypes] =
|
|
6799
|
-
const [typeInput, setTypeInput] =
|
|
6800
|
-
const [color, setColor] =
|
|
6801
|
-
const [size, setSize] =
|
|
6802
|
-
const [intensity, setIntensity] =
|
|
6803
|
-
const [description, setDescription] =
|
|
6804
|
-
const [customProps, setCustomProps] =
|
|
6805
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
6806
|
-
const [filteredTypes, setFilteredTypes] =
|
|
6807
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
6808
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
6809
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
6810
|
-
const [targetDatasetId, setTargetDatasetId] =
|
|
6811
|
-
const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] =
|
|
7210
|
+
const [name, setName] = useState14("");
|
|
7211
|
+
const [types, setTypes] = useState14([]);
|
|
7212
|
+
const [typeInput, setTypeInput] = useState14("");
|
|
7213
|
+
const [color, setColor] = useState14(initialColor || "#cccccc");
|
|
7214
|
+
const [size, setSize] = useState14("medium");
|
|
7215
|
+
const [intensity, setIntensity] = useState14(0);
|
|
7216
|
+
const [description, setDescription] = useState14("");
|
|
7217
|
+
const [customProps, setCustomProps] = useState14([]);
|
|
7218
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
|
|
7219
|
+
const [filteredTypes, setFilteredTypes] = useState14([]);
|
|
7220
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
|
|
7221
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
|
|
7222
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
|
|
7223
|
+
const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
|
|
7224
|
+
const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
|
|
6812
7225
|
const datasetDropdownRef = useRef10(null);
|
|
6813
7226
|
useEffect13(() => {
|
|
6814
7227
|
if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
|
|
@@ -7050,7 +7463,8 @@ function InSceneCreationForm({
|
|
|
7050
7463
|
availableNodes,
|
|
7051
7464
|
availableAncestries,
|
|
7052
7465
|
onMentionClick,
|
|
7053
|
-
onImageClick: handleImageClickFromText
|
|
7466
|
+
onImageClick: handleImageClickFromText,
|
|
7467
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7054
7468
|
}
|
|
7055
7469
|
), /* @__PURE__ */ React13.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React13.createElement(
|
|
7056
7470
|
"button",
|
|
@@ -7141,7 +7555,7 @@ function InSceneCreationForm({
|
|
|
7141
7555
|
}
|
|
7142
7556
|
|
|
7143
7557
|
// src/components/InSceneVersionForm.jsx
|
|
7144
|
-
import React14, { useState as
|
|
7558
|
+
import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
|
|
7145
7559
|
import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
|
|
7146
7560
|
function InSceneVersionForm({
|
|
7147
7561
|
onSave,
|
|
@@ -7159,14 +7573,14 @@ function InSceneVersionForm({
|
|
|
7159
7573
|
onMentionClick,
|
|
7160
7574
|
onUploadFile
|
|
7161
7575
|
}) {
|
|
7162
|
-
const [name, setName] =
|
|
7163
|
-
const [size, setSize] =
|
|
7164
|
-
const [description, setDescription] =
|
|
7165
|
-
const [customProps, setCustomProps] =
|
|
7166
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7576
|
+
const [name, setName] = useState15("");
|
|
7577
|
+
const [size, setSize] = useState15("medium");
|
|
7578
|
+
const [description, setDescription] = useState15("");
|
|
7579
|
+
const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
|
|
7580
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
|
|
7167
7581
|
const propsEndRef = useRef11(null);
|
|
7168
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7169
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7582
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
|
|
7583
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
|
|
7170
7584
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
7171
7585
|
useEffect14(() => {
|
|
7172
7586
|
if (!hasImages && useImageAsTexture) {
|
|
@@ -7287,7 +7701,8 @@ function InSceneVersionForm({
|
|
|
7287
7701
|
availableNodes,
|
|
7288
7702
|
availableAncestries,
|
|
7289
7703
|
onMentionClick,
|
|
7290
|
-
onImageClick: handleImageClickFromText
|
|
7704
|
+
onImageClick: handleImageClickFromText,
|
|
7705
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7291
7706
|
}
|
|
7292
7707
|
), /* @__PURE__ */ React14.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React14.createElement(
|
|
7293
7708
|
"button",
|
|
@@ -7359,7 +7774,7 @@ function InSceneVersionForm({
|
|
|
7359
7774
|
}
|
|
7360
7775
|
|
|
7361
7776
|
// src/components/NodeDetailsPanel.jsx
|
|
7362
|
-
import React15, { useState as
|
|
7777
|
+
import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
|
|
7363
7778
|
import { FiPlus as FiPlus5, FiMaximize2 as FiMaximize23, FiX as FiX4, FiCheck as FiCheck9, FiImage as FiImage3, FiEdit2 as FiEdit26, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
|
|
7364
7779
|
function NodeDetailsPanel({
|
|
7365
7780
|
node,
|
|
@@ -7381,27 +7796,36 @@ function NodeDetailsPanel({
|
|
|
7381
7796
|
userRole,
|
|
7382
7797
|
currentDatasetName
|
|
7383
7798
|
}) {
|
|
7384
|
-
const [name, setName] =
|
|
7385
|
-
const [types, setTypes] =
|
|
7386
|
-
const [typeInput, setTypeInput] =
|
|
7387
|
-
const [color, setColor] =
|
|
7388
|
-
const [size, setSize] =
|
|
7389
|
-
const [description, setDescription] =
|
|
7390
|
-
const [intensity, setIntensity] =
|
|
7391
|
-
const [customProps, setCustomProps] =
|
|
7392
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
7393
|
-
const [filteredTypes, setFilteredTypes] =
|
|
7394
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7395
|
-
const [isReadMode, setIsReadMode] =
|
|
7396
|
-
const [existingSections, setExistingSections] =
|
|
7397
|
-
const [isSaving, setIsSaving] =
|
|
7398
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
7399
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7799
|
+
const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
|
|
7800
|
+
const [types, setTypes] = useState16([]);
|
|
7801
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7802
|
+
const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
7803
|
+
const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
|
|
7804
|
+
const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
|
|
7805
|
+
const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
7806
|
+
const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
|
|
7807
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
|
|
7808
|
+
const [filteredTypes, setFilteredTypes] = useState16([]);
|
|
7809
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7810
|
+
const [isReadMode, setIsReadMode] = useState16(false);
|
|
7811
|
+
const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
|
|
7812
|
+
const [isSaving, setIsSaving] = useState16(false);
|
|
7813
|
+
const [isLinkCopied, setIsLinkCopied] = useState16(false);
|
|
7814
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
|
|
7400
7815
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7401
7816
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7402
7817
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7403
7818
|
});
|
|
7404
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7819
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7820
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7821
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7822
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
7823
|
+
minWidth: 320,
|
|
7824
|
+
maxWidth: maxPanelW
|
|
7825
|
+
});
|
|
7826
|
+
useEffect15(() => {
|
|
7827
|
+
setWidth(isReadMode ? 700 : 440);
|
|
7828
|
+
}, [isReadMode, setWidth]);
|
|
7405
7829
|
const prevNodeIdRef = useRef12(null);
|
|
7406
7830
|
const propsEndRef = useRef12(null);
|
|
7407
7831
|
const canEdit = userRole !== "viewer";
|
|
@@ -7554,6 +7978,11 @@ function NodeDetailsPanel({
|
|
|
7554
7978
|
textureImageUrl: url
|
|
7555
7979
|
});
|
|
7556
7980
|
};
|
|
7981
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
7982
|
+
setDescription(newDescription);
|
|
7983
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
7984
|
+
triggerAutoSave({ description: newDescription });
|
|
7985
|
+
};
|
|
7557
7986
|
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
7558
7987
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
7559
7988
|
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
@@ -7609,10 +8038,8 @@ function NodeDetailsPanel({
|
|
|
7609
8038
|
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
7610
8039
|
"div",
|
|
7611
8040
|
{
|
|
7612
|
-
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden transition-all duration-300 ease-out
|
|
7613
|
-
|
|
7614
|
-
`,
|
|
7615
|
-
style: { top: 16, right: 16, zIndex: 1100 },
|
|
8041
|
+
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
8042
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
7616
8043
|
onPointerDown: swallow,
|
|
7617
8044
|
onPointerMove: swallow,
|
|
7618
8045
|
onPointerUp: swallow,
|
|
@@ -7621,6 +8048,17 @@ function NodeDetailsPanel({
|
|
|
7621
8048
|
onContextMenu: swallow,
|
|
7622
8049
|
onDoubleClick: swallow
|
|
7623
8050
|
},
|
|
8051
|
+
/* @__PURE__ */ React15.createElement(
|
|
8052
|
+
"div",
|
|
8053
|
+
{
|
|
8054
|
+
onPointerDown: (e) => {
|
|
8055
|
+
e.stopPropagation();
|
|
8056
|
+
handleResize(e);
|
|
8057
|
+
},
|
|
8058
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
8059
|
+
title: "Arraste para redimensionar"
|
|
8060
|
+
}
|
|
8061
|
+
),
|
|
7624
8062
|
isReadMode ? /* @__PURE__ */ React15.createElement(
|
|
7625
8063
|
DescriptionReadModePanel,
|
|
7626
8064
|
{
|
|
@@ -7639,7 +8077,8 @@ function NodeDetailsPanel({
|
|
|
7639
8077
|
availableAncestries,
|
|
7640
8078
|
onOpenReference,
|
|
7641
8079
|
onMentionClick,
|
|
7642
|
-
onImageClick: handleImageClickFromText
|
|
8080
|
+
onImageClick: handleImageClickFromText,
|
|
8081
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7643
8082
|
}
|
|
7644
8083
|
) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React15.createElement(
|
|
7645
8084
|
"button",
|
|
@@ -7707,7 +8146,8 @@ function NodeDetailsPanel({
|
|
|
7707
8146
|
availableAncestries,
|
|
7708
8147
|
onOpenReference,
|
|
7709
8148
|
onMentionClick,
|
|
7710
|
-
onImageClick: handleImageClickFromText
|
|
8149
|
+
onImageClick: handleImageClickFromText,
|
|
8150
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7711
8151
|
}
|
|
7712
8152
|
), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement(
|
|
7713
8153
|
"button",
|
|
@@ -7790,7 +8230,7 @@ function NodeDetailsPanel({
|
|
|
7790
8230
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
7791
8231
|
readOnly: !canEdit
|
|
7792
8232
|
}
|
|
7793
|
-
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React15.createElement("div", { className: "pt-3 mt-4 border-t border-white/10 flex items-center gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React15.createElement(
|
|
8233
|
+
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React15.createElement("div", { className: "pt-3 mt-4 border-t border-white/10 flex items-center justify-end gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React15.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm disabled:opacity-50" }, canEdit ? "Cancelar" : "Fechar"), canEdit && /* @__PURE__ */ React15.createElement(
|
|
7794
8234
|
"button",
|
|
7795
8235
|
{
|
|
7796
8236
|
onClick: () => handleSave(false),
|
|
@@ -7822,18 +8262,18 @@ function NodeDetailsPanel({
|
|
|
7822
8262
|
}
|
|
7823
8263
|
|
|
7824
8264
|
// src/components/MultiNodeContextMenu.jsx
|
|
7825
|
-
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as
|
|
8265
|
+
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
|
|
7826
8266
|
function MultiNodeContextMenu({
|
|
7827
8267
|
data,
|
|
7828
8268
|
userRole,
|
|
7829
|
-
// 2. Recebendo a role do usuário nas props
|
|
7830
8269
|
onClose,
|
|
7831
8270
|
onDismissNodes,
|
|
7832
8271
|
onDismissOtherNodes,
|
|
7833
8272
|
onDeleteNodes
|
|
7834
8273
|
}) {
|
|
7835
8274
|
const menuRef = useRef13(null);
|
|
7836
|
-
const [menuPos, setMenuPos] =
|
|
8275
|
+
const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
|
|
8276
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState17(false);
|
|
7837
8277
|
const ability = defineAbilityFor(userRole);
|
|
7838
8278
|
const canDelete = ability.can("delete", "Node");
|
|
7839
8279
|
useLayoutEffect3(() => {
|
|
@@ -7850,7 +8290,9 @@ function MultiNodeContextMenu({
|
|
|
7850
8290
|
setMenuPos({ left, top });
|
|
7851
8291
|
}, [data]);
|
|
7852
8292
|
useEffect16(() => {
|
|
7853
|
-
if (
|
|
8293
|
+
if (data.visible) {
|
|
8294
|
+
setIsConfirmingDelete(false);
|
|
8295
|
+
}
|
|
7854
8296
|
const handleClickOutside = (e) => {
|
|
7855
8297
|
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
7856
8298
|
};
|
|
@@ -7877,12 +8319,26 @@ function MultiNodeContextMenu({
|
|
|
7877
8319
|
onDoubleClick: swallow
|
|
7878
8320
|
},
|
|
7879
8321
|
/* @__PURE__ */ React16.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
7880
|
-
/* @__PURE__ */ React16.createElement("div", { className: "p-1.5" },
|
|
8322
|
+
/* @__PURE__ */ React16.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React16.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ React16.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React16.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React16.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React16.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React16.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ React16.createElement("p", { className: "text-[11px] text-slate-400 leading-tight" }, "Esta a\xE7\xE3o \xE9 irrevers\xEDvel. Todas as conex\xF5es associadas a eles ser\xE3o apagadas.")), /* @__PURE__ */ React16.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React16.createElement(
|
|
8323
|
+
"button",
|
|
8324
|
+
{
|
|
8325
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
8326
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8327
|
+
},
|
|
8328
|
+
"Cancelar"
|
|
8329
|
+
), /* @__PURE__ */ React16.createElement(
|
|
8330
|
+
"button",
|
|
8331
|
+
{
|
|
8332
|
+
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8333
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8334
|
+
},
|
|
8335
|
+
"Excluir"
|
|
8336
|
+
))) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React16.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React16.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React16.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React16.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React16.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React16.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ React16.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ React16.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React16.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ React16.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React16.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React16.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React16.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React16.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React16.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React16.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React16.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React16.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ React16.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React16.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React16.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React16.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React16.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React16.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
|
|
7881
8337
|
);
|
|
7882
8338
|
}
|
|
7883
8339
|
|
|
7884
8340
|
// src/components/RelationshipDetailsPanel.jsx
|
|
7885
|
-
import React17, { useState as
|
|
8341
|
+
import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
|
|
7886
8342
|
import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
7887
8343
|
function RelationshipDetailsPanel({
|
|
7888
8344
|
link,
|
|
@@ -7896,15 +8352,14 @@ function RelationshipDetailsPanel({
|
|
|
7896
8352
|
onMentionClick,
|
|
7897
8353
|
onUploadFile,
|
|
7898
8354
|
userRole
|
|
7899
|
-
// Recebendo userRole via props
|
|
7900
8355
|
}) {
|
|
7901
|
-
const [name, setName] =
|
|
7902
|
-
const [description, setDescription] =
|
|
7903
|
-
const [customProps, setCustomProps] =
|
|
7904
|
-
const [existingSections, setExistingSections] =
|
|
7905
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7906
|
-
const [isSaving, setIsSaving] =
|
|
7907
|
-
const [isReadMode, setIsReadMode] =
|
|
8356
|
+
const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
|
|
8357
|
+
const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
|
|
8358
|
+
const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
|
|
8359
|
+
const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
|
|
8360
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
|
|
8361
|
+
const [isSaving, setIsSaving] = useState18(false);
|
|
8362
|
+
const [isReadMode, setIsReadMode] = useState18(false);
|
|
7908
8363
|
const propsEndRef = useRef14(null);
|
|
7909
8364
|
const canEdit = useMemo9(() => {
|
|
7910
8365
|
const ability = defineAbilityFor(userRole);
|
|
@@ -7959,6 +8414,12 @@ function RelationshipDetailsPanel({
|
|
|
7959
8414
|
const triggerAutoSave = (overrides = {}) => {
|
|
7960
8415
|
if (canEdit) handleSave(true, overrides);
|
|
7961
8416
|
};
|
|
8417
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8418
|
+
if (!canEdit) return;
|
|
8419
|
+
setDescription(newDescription);
|
|
8420
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8421
|
+
triggerAutoSave({ description: newDescription });
|
|
8422
|
+
};
|
|
7962
8423
|
const handleRemoveProp = (i) => {
|
|
7963
8424
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
7964
8425
|
setCustomProps(newProps);
|
|
@@ -8012,7 +8473,8 @@ function RelationshipDetailsPanel({
|
|
|
8012
8473
|
availableAncestries,
|
|
8013
8474
|
onOpenReference,
|
|
8014
8475
|
onMentionClick,
|
|
8015
|
-
onImageClick: handleImageClickFromText
|
|
8476
|
+
onImageClick: handleImageClickFromText,
|
|
8477
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
8016
8478
|
}
|
|
8017
8479
|
) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-teal-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("button", { onClick: onClose, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Fechar" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React17.createElement(
|
|
8018
8480
|
"input",
|
|
@@ -8035,7 +8497,8 @@ function RelationshipDetailsPanel({
|
|
|
8035
8497
|
availableAncestries,
|
|
8036
8498
|
onOpenReference,
|
|
8037
8499
|
onMentionClick,
|
|
8038
|
-
onImageClick: handleImageClickFromText
|
|
8500
|
+
onImageClick: handleImageClickFromText,
|
|
8501
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
8039
8502
|
}
|
|
8040
8503
|
), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React17.createElement(
|
|
8041
8504
|
"button",
|
|
@@ -8107,11 +8570,10 @@ function RelationshipDetailsPanel({
|
|
|
8107
8570
|
}
|
|
8108
8571
|
|
|
8109
8572
|
// src/components/RelationshipContextMenu.jsx
|
|
8110
|
-
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as
|
|
8573
|
+
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8111
8574
|
function RelationshipContextMenu({
|
|
8112
8575
|
data,
|
|
8113
8576
|
userRole,
|
|
8114
|
-
// Recebemos a role do usuário para verificar permissões
|
|
8115
8577
|
onRelinkSource,
|
|
8116
8578
|
onRelinkTarget,
|
|
8117
8579
|
onOpenDetails,
|
|
@@ -8119,7 +8581,8 @@ function RelationshipContextMenu({
|
|
|
8119
8581
|
onClose
|
|
8120
8582
|
}) {
|
|
8121
8583
|
const menuRef = useRef15(null);
|
|
8122
|
-
const [menuPos, setMenuPos] =
|
|
8584
|
+
const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
|
|
8585
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState19(false);
|
|
8123
8586
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8124
8587
|
const sourceName = useMemo10(
|
|
8125
8588
|
() => {
|
|
@@ -8149,7 +8612,9 @@ function RelationshipContextMenu({
|
|
|
8149
8612
|
setMenuPos({ left, top });
|
|
8150
8613
|
}, [data]);
|
|
8151
8614
|
useEffect18(() => {
|
|
8152
|
-
if (
|
|
8615
|
+
if (data.visible) {
|
|
8616
|
+
setIsConfirmingDelete(false);
|
|
8617
|
+
}
|
|
8153
8618
|
const handleClickOutside = (e) => {
|
|
8154
8619
|
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
8155
8620
|
};
|
|
@@ -8177,7 +8642,21 @@ function RelationshipContextMenu({
|
|
|
8177
8642
|
onDoubleClick: swallow
|
|
8178
8643
|
},
|
|
8179
8644
|
/* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
8180
|
-
/* @__PURE__ */ React18.createElement("div", { className: "p-1.5" }, /* @__PURE__ */ React18.createElement("div", { className: "flex
|
|
8645
|
+
/* @__PURE__ */ React18.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React18.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ React18.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React18.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React18.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ React18.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ React18.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ React18.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React18.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ React18.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ React18.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ React18.createElement("strong", null, targetName), ".")), /* @__PURE__ */ React18.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React18.createElement(
|
|
8646
|
+
"button",
|
|
8647
|
+
{
|
|
8648
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
8649
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8650
|
+
},
|
|
8651
|
+
"Cancelar"
|
|
8652
|
+
), /* @__PURE__ */ React18.createElement(
|
|
8653
|
+
"button",
|
|
8654
|
+
{
|
|
8655
|
+
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8656
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8657
|
+
},
|
|
8658
|
+
"Excluir"
|
|
8659
|
+
))) : /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React18.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-teal-400/80 shadow-[0_0_12px_1px_rgba(45,212,191,0.5)]" }), /* @__PURE__ */ React18.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
|
|
8181
8660
|
"button",
|
|
8182
8661
|
{
|
|
8183
8662
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
@@ -8256,7 +8735,7 @@ function RelationshipContextMenu({
|
|
|
8256
8735
|
), canDelete && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React18.createElement(
|
|
8257
8736
|
"button",
|
|
8258
8737
|
{
|
|
8259
|
-
onClick: () =>
|
|
8738
|
+
onClick: () => setIsConfirmingDelete(true),
|
|
8260
8739
|
className: dangerButtonClass,
|
|
8261
8740
|
title: "Excluir esta conex\xE3o"
|
|
8262
8741
|
},
|
|
@@ -8280,7 +8759,7 @@ function RelationshipContextMenu({
|
|
|
8280
8759
|
/* @__PURE__ */ React18.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
8281
8760
|
),
|
|
8282
8761
|
/* @__PURE__ */ React18.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
8283
|
-
))))
|
|
8762
|
+
)))))
|
|
8284
8763
|
);
|
|
8285
8764
|
}
|
|
8286
8765
|
|
|
@@ -8321,7 +8800,7 @@ function LoadingScreen() {
|
|
|
8321
8800
|
}
|
|
8322
8801
|
|
|
8323
8802
|
// src/components/ImportParentFileModal.jsx
|
|
8324
|
-
import React20, { useEffect as useEffect19, useState as
|
|
8803
|
+
import React20, { useEffect as useEffect19, useState as useState20 } from "react";
|
|
8325
8804
|
function ImportParentFileModal({
|
|
8326
8805
|
isOpen,
|
|
8327
8806
|
onClose,
|
|
@@ -8332,11 +8811,11 @@ function ImportParentFileModal({
|
|
|
8332
8811
|
onFetchAvailableFiles,
|
|
8333
8812
|
currentViewName
|
|
8334
8813
|
}) {
|
|
8335
|
-
const [activeTab, setActiveTab] =
|
|
8336
|
-
const [availableDbs, setAvailableDbs] =
|
|
8337
|
-
const [availableViews, setAvailableViews] =
|
|
8338
|
-
const [selectedItem, setSelectedItem] =
|
|
8339
|
-
const [isLoading, setIsLoading] =
|
|
8814
|
+
const [activeTab, setActiveTab] = useState20("databases");
|
|
8815
|
+
const [availableDbs, setAvailableDbs] = useState20([]);
|
|
8816
|
+
const [availableViews, setAvailableViews] = useState20([]);
|
|
8817
|
+
const [selectedItem, setSelectedItem] = useState20(null);
|
|
8818
|
+
const [isLoading, setIsLoading] = useState20(false);
|
|
8340
8819
|
useEffect19(() => {
|
|
8341
8820
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8342
8821
|
const fetchData = async () => {
|
|
@@ -8482,7 +8961,7 @@ function ImportParentFileModal({
|
|
|
8482
8961
|
}
|
|
8483
8962
|
|
|
8484
8963
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
8485
|
-
import React21, { useState as
|
|
8964
|
+
import React21, { useState as useState21 } from "react";
|
|
8486
8965
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
8487
8966
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
8488
8967
|
var _a, _b, _c, _d;
|
|
@@ -8492,7 +8971,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8492
8971
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
8493
8972
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
8494
8973
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
8495
|
-
const [isReadMode, setIsReadMode] =
|
|
8974
|
+
const [isReadMode, setIsReadMode] = useState21(false);
|
|
8496
8975
|
const swallow = (e) => e.stopPropagation();
|
|
8497
8976
|
const handleImageClickFromText = (url, name) => {
|
|
8498
8977
|
if (onOpenImageViewer) {
|
|
@@ -8558,14 +9037,14 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8558
9037
|
}
|
|
8559
9038
|
|
|
8560
9039
|
// src/components/AncestryBoard.jsx
|
|
8561
|
-
import React22, { useState as
|
|
9040
|
+
import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
|
|
8562
9041
|
import {
|
|
8563
9042
|
FiSearch as FiSearch4,
|
|
8564
9043
|
FiLayers as FiLayers6,
|
|
8565
9044
|
FiCornerUpRight as FiCornerUpRight4,
|
|
8566
9045
|
FiPlay,
|
|
8567
9046
|
FiPlus as FiPlus7,
|
|
8568
|
-
FiTrash2 as
|
|
9047
|
+
FiTrash2 as FiTrash23,
|
|
8569
9048
|
FiArrowLeft as FiArrowLeft3,
|
|
8570
9049
|
FiArrowRight,
|
|
8571
9050
|
FiCheckCircle,
|
|
@@ -8702,7 +9181,7 @@ var GroupItem = ({
|
|
|
8702
9181
|
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
8703
9182
|
title: "Remover Grupo"
|
|
8704
9183
|
},
|
|
8705
|
-
/* @__PURE__ */ React22.createElement(
|
|
9184
|
+
/* @__PURE__ */ React22.createElement(FiTrash23, { size: 14 })
|
|
8706
9185
|
)))), group.children && group.children.length > 0 && /* @__PURE__ */ React22.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React22.createElement(
|
|
8707
9186
|
GroupItem,
|
|
8708
9187
|
{
|
|
@@ -8735,11 +9214,11 @@ function AncestryBoard({
|
|
|
8735
9214
|
userRole
|
|
8736
9215
|
// [NOVO] Recebe a role do usuário
|
|
8737
9216
|
}) {
|
|
8738
|
-
const [searchTerm, setSearchTerm] =
|
|
8739
|
-
const [groups, setGroups] =
|
|
8740
|
-
const [isLoaded, setIsLoaded] =
|
|
8741
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
8742
|
-
const [saveStatus, setSaveStatus] =
|
|
9217
|
+
const [searchTerm, setSearchTerm] = useState22("");
|
|
9218
|
+
const [groups, setGroups] = useState22([]);
|
|
9219
|
+
const [isLoaded, setIsLoaded] = useState22(false);
|
|
9220
|
+
const [pickingGroupId, setPickingGroupId] = useState22(null);
|
|
9221
|
+
const [saveStatus, setSaveStatus] = useState22("idle");
|
|
8743
9222
|
const canEdit = useMemo11(() => {
|
|
8744
9223
|
return userRole !== "viewer";
|
|
8745
9224
|
}, [userRole]);
|
|
@@ -9189,37 +9668,37 @@ function XViewScene({
|
|
|
9189
9668
|
const sceneDataRef = useRef17(null);
|
|
9190
9669
|
const parentDataRef = useRef17(null);
|
|
9191
9670
|
const ancestryDataRef = useRef17(null);
|
|
9192
|
-
const [isLoading, setIsLoading] =
|
|
9193
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9194
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9195
|
-
const [isInitialized, setIsInitialized] =
|
|
9196
|
-
const [sceneVersion, setSceneVersion] =
|
|
9197
|
-
const [contextMenu, setContextMenu] =
|
|
9198
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9199
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9200
|
-
const [creationMode, setCreationMode] =
|
|
9201
|
-
const [versionMode, setVersionMode] =
|
|
9202
|
-
const [hasFocusedInitial, setHasFocusedInitial] =
|
|
9203
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] =
|
|
9204
|
-
const [ancestryMode, setAncestryMode] =
|
|
9205
|
-
const [readingMode, setReadingMode] =
|
|
9671
|
+
const [isLoading, setIsLoading] = useState23(true);
|
|
9672
|
+
const [permissionStatus, setPermissionStatus] = useState23("loading");
|
|
9673
|
+
const [userPermissionRole, setUserPermissionRole] = useState23(null);
|
|
9674
|
+
const [isInitialized, setIsInitialized] = useState23(false);
|
|
9675
|
+
const [sceneVersion, setSceneVersion] = useState23(0);
|
|
9676
|
+
const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
|
|
9677
|
+
const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
9678
|
+
const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
|
|
9679
|
+
const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9680
|
+
const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9681
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
|
|
9682
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
|
|
9683
|
+
const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
9684
|
+
const [readingMode, setReadingMode] = useState23({
|
|
9206
9685
|
isActive: false,
|
|
9207
9686
|
ancestry: null,
|
|
9208
9687
|
branchStack: [],
|
|
9209
9688
|
autoAbstraction: false
|
|
9210
9689
|
});
|
|
9211
|
-
const [formPosition, setFormPosition] =
|
|
9212
|
-
const [detailsNode, setDetailsNode] =
|
|
9213
|
-
const [detailsLink, setDetailsLink] =
|
|
9214
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9215
|
-
const [imageViewer, setImageViewer] =
|
|
9216
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9217
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9218
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9219
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9220
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9221
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9222
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9690
|
+
const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
|
|
9691
|
+
const [detailsNode, setDetailsNode] = useState23(null);
|
|
9692
|
+
const [detailsLink, setDetailsLink] = useState23(null);
|
|
9693
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
|
|
9694
|
+
const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
|
|
9695
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
|
|
9696
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
|
|
9697
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState23("");
|
|
9698
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
|
|
9699
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
|
|
9700
|
+
const [ancestryBoardData, setAncestryBoardData] = useState23([]);
|
|
9701
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
|
|
9223
9702
|
const mountRef = useRef17(null);
|
|
9224
9703
|
const tooltipRef = useRef17(null);
|
|
9225
9704
|
const formRef = useRef17(null);
|
|
@@ -9262,6 +9741,12 @@ function XViewScene({
|
|
|
9262
9741
|
lastDescriptionLength: 0,
|
|
9263
9742
|
highlightedNodeId: null
|
|
9264
9743
|
});
|
|
9744
|
+
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9745
|
+
const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
|
|
9746
|
+
initialWidth: 700,
|
|
9747
|
+
minWidth: 320,
|
|
9748
|
+
maxWidth: maxReadPanelW
|
|
9749
|
+
});
|
|
9265
9750
|
useEffect21(() => {
|
|
9266
9751
|
stateRef.current.ancestry = ancestryMode;
|
|
9267
9752
|
}, [ancestryMode]);
|
|
@@ -9286,10 +9771,10 @@ function XViewScene({
|
|
|
9286
9771
|
}
|
|
9287
9772
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
9288
9773
|
}, [isInitialized, sceneVersion]);
|
|
9289
|
-
const handleNavigateBack =
|
|
9774
|
+
const handleNavigateBack = useCallback4(() => {
|
|
9290
9775
|
router.push("/dashboard/scenes");
|
|
9291
9776
|
}, [router]);
|
|
9292
|
-
const handleConfirmImport =
|
|
9777
|
+
const handleConfirmImport = useCallback4(
|
|
9293
9778
|
async (importPayload) => {
|
|
9294
9779
|
var _a2, _b2;
|
|
9295
9780
|
let files = [];
|
|
@@ -9337,7 +9822,6 @@ function XViewScene({
|
|
|
9337
9822
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
9338
9823
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
9339
9824
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
9340
|
-
// <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
|
|
9341
9825
|
);
|
|
9342
9826
|
const processedAncestries = viewSpecificAncestries.map((anc) => ({
|
|
9343
9827
|
...anc,
|
|
@@ -9388,7 +9872,7 @@ function XViewScene({
|
|
|
9388
9872
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
9389
9873
|
setImageViewer({ visible: true, images, startIndex });
|
|
9390
9874
|
};
|
|
9391
|
-
const tweenToTarget =
|
|
9875
|
+
const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
|
|
9392
9876
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
9393
9877
|
if (!camera || !controls || !tweenGroup) return;
|
|
9394
9878
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -9411,7 +9895,7 @@ function XViewScene({
|
|
|
9411
9895
|
if (!t || typeof t.closest !== "function") return false;
|
|
9412
9896
|
return !!t.closest(".ui-overlay");
|
|
9413
9897
|
};
|
|
9414
|
-
const buildFullAncestryTree =
|
|
9898
|
+
const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
|
|
9415
9899
|
if (!idTree) return null;
|
|
9416
9900
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
9417
9901
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -9437,14 +9921,10 @@ function XViewScene({
|
|
|
9437
9921
|
return {
|
|
9438
9922
|
...branch,
|
|
9439
9923
|
name: linkedAncestry.name,
|
|
9440
|
-
// Sobrescreve nome para exibição
|
|
9441
9924
|
description: linkedAncestry.description,
|
|
9442
|
-
// Sobrescreve descrição
|
|
9443
9925
|
description_sections: linkedAncestry.description_sections,
|
|
9444
9926
|
tree: graftedTree,
|
|
9445
|
-
// ENXERTA A ÁRVORE AQUI
|
|
9446
9927
|
isLinked: true
|
|
9447
|
-
// Flag útil
|
|
9448
9928
|
};
|
|
9449
9929
|
}
|
|
9450
9930
|
}
|
|
@@ -9491,7 +9971,7 @@ function XViewScene({
|
|
|
9491
9971
|
}
|
|
9492
9972
|
return recursiveBuild(idTree);
|
|
9493
9973
|
}, []);
|
|
9494
|
-
const handleActivateTimeline =
|
|
9974
|
+
const handleActivateTimeline = useCallback4(() => {
|
|
9495
9975
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9496
9976
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
9497
9977
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -9644,7 +10124,7 @@ function XViewScene({
|
|
|
9644
10124
|
}
|
|
9645
10125
|
});
|
|
9646
10126
|
}, []);
|
|
9647
|
-
const handleVersionTimeline =
|
|
10127
|
+
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
9648
10128
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9649
10129
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
9650
10130
|
versionMeshes.forEach((mesh) => {
|
|
@@ -9837,16 +10317,14 @@ function XViewScene({
|
|
|
9837
10317
|
isInitialized,
|
|
9838
10318
|
permissionStatus,
|
|
9839
10319
|
focusNodeId,
|
|
9840
|
-
// <-- MANTIDO
|
|
9841
10320
|
focusAncestryId
|
|
9842
|
-
// <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
|
|
9843
10321
|
]);
|
|
9844
|
-
const isNodeInView =
|
|
10322
|
+
const isNodeInView = useCallback4((id) => {
|
|
9845
10323
|
const key = String(id);
|
|
9846
10324
|
const objs = stateRef.current.nodeObjects || {};
|
|
9847
10325
|
return !!objs[key];
|
|
9848
10326
|
}, []);
|
|
9849
|
-
const addOrUpdateNodeMesh =
|
|
10327
|
+
const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
|
|
9850
10328
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
9851
10329
|
const nodeId = String(nodeData.id);
|
|
9852
10330
|
if (nodeObjects[nodeId]) {
|
|
@@ -10495,7 +10973,7 @@ function XViewScene({
|
|
|
10495
10973
|
}
|
|
10496
10974
|
};
|
|
10497
10975
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
10498
|
-
const handleGhostNodeImageChange =
|
|
10976
|
+
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
10499
10977
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10500
10978
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
10501
10979
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -10537,7 +11015,7 @@ function XViewScene({
|
|
|
10537
11015
|
aura: newGhostNode.getObjectByName("aura")
|
|
10538
11016
|
};
|
|
10539
11017
|
}, []);
|
|
10540
|
-
const handleGhostNodeIntensityChange =
|
|
11018
|
+
const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
|
|
10541
11019
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10542
11020
|
if (!ghostNode) return;
|
|
10543
11021
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10558,7 +11036,7 @@ function XViewScene({
|
|
|
10558
11036
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
10559
11037
|
}
|
|
10560
11038
|
}, []);
|
|
10561
|
-
const handleDetailNodeIntensityChange =
|
|
11039
|
+
const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
|
|
10562
11040
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10563
11041
|
if (!mesh) return;
|
|
10564
11042
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10704,7 +11182,7 @@ function XViewScene({
|
|
|
10704
11182
|
mountRef.current.style.cursor = "default";
|
|
10705
11183
|
}
|
|
10706
11184
|
};
|
|
10707
|
-
const handleAncestryTreeUpdate =
|
|
11185
|
+
const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
|
|
10708
11186
|
setAncestryMode((prev) => {
|
|
10709
11187
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
10710
11188
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -10774,7 +11252,7 @@ function XViewScene({
|
|
|
10774
11252
|
const handleStartVersioning = (nodeData) => {
|
|
10775
11253
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
10776
11254
|
};
|
|
10777
|
-
const handleClearAncestryVisuals =
|
|
11255
|
+
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
10778
11256
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
10779
11257
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
10780
11258
|
if (renderIndex !== -1) {
|
|
@@ -10788,7 +11266,7 @@ function XViewScene({
|
|
|
10788
11266
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10789
11267
|
}
|
|
10790
11268
|
}, []);
|
|
10791
|
-
const handleRenderAncestry =
|
|
11269
|
+
const handleRenderAncestry = useCallback4(
|
|
10792
11270
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
10793
11271
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10794
11272
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11204,7 +11682,7 @@ function XViewScene({
|
|
|
11204
11682
|
},
|
|
11205
11683
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
11206
11684
|
);
|
|
11207
|
-
const handleRenderAbstractionTree =
|
|
11685
|
+
const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
|
|
11208
11686
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11209
11687
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
11210
11688
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -11265,7 +11743,7 @@ function XViewScene({
|
|
|
11265
11743
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11266
11744
|
tweenToTarget(rootTargetPos, 0.7);
|
|
11267
11745
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
11268
|
-
const handleReadModeBranchNav =
|
|
11746
|
+
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
11269
11747
|
const { ancestry, branchStack } = readingMode;
|
|
11270
11748
|
if (!ancestry || !ancestry.tree) return;
|
|
11271
11749
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -11303,9 +11781,7 @@ function XViewScene({
|
|
|
11303
11781
|
description_sections: branchToOpen.description_sections,
|
|
11304
11782
|
tree: branchToOpen.tree,
|
|
11305
11783
|
_originNodeId: nodeId,
|
|
11306
|
-
// <--- ID do node pai (link visual)
|
|
11307
11784
|
_branchDirection: direction
|
|
11308
|
-
// <--- Direção para cálculo de posição
|
|
11309
11785
|
};
|
|
11310
11786
|
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
11311
11787
|
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
@@ -11361,7 +11837,6 @@ function XViewScene({
|
|
|
11361
11837
|
const parentAncestryObj = {
|
|
11362
11838
|
...targetAncestryInfo,
|
|
11363
11839
|
tree: targetTreeToRender,
|
|
11364
|
-
// Re-injeta a origem se o pai também for uma branch aninhada
|
|
11365
11840
|
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
11366
11841
|
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
11367
11842
|
};
|
|
@@ -11409,7 +11884,7 @@ function XViewScene({
|
|
|
11409
11884
|
}));
|
|
11410
11885
|
}
|
|
11411
11886
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
11412
|
-
const handleReadModeHighlight =
|
|
11887
|
+
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
11413
11888
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
11414
11889
|
stateRef.current.highlightedNodeId = nodeId;
|
|
11415
11890
|
}
|
|
@@ -11421,7 +11896,6 @@ function XViewScene({
|
|
|
11421
11896
|
readingMode.ancestry.tree,
|
|
11422
11897
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
11423
11898
|
ancestryDataRef.current
|
|
11424
|
-
// <--- Adicionar
|
|
11425
11899
|
);
|
|
11426
11900
|
const findNodeInTree = (tree, targetId) => {
|
|
11427
11901
|
if (!tree) return null;
|
|
@@ -11475,7 +11949,6 @@ function XViewScene({
|
|
|
11475
11949
|
description_sections: ancestry.description_sections,
|
|
11476
11950
|
direction: null,
|
|
11477
11951
|
customProperties: rootProps
|
|
11478
|
-
// <--- ADICIONADO
|
|
11479
11952
|
};
|
|
11480
11953
|
}
|
|
11481
11954
|
const fullTree = buildFullAncestryTree(
|
|
@@ -11504,7 +11977,6 @@ function XViewScene({
|
|
|
11504
11977
|
description_sections: currentMeta.description_sections,
|
|
11505
11978
|
direction: currentDirection,
|
|
11506
11979
|
customProperties: branchProps
|
|
11507
|
-
// <--- ADICIONADO
|
|
11508
11980
|
};
|
|
11509
11981
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11510
11982
|
const readModeAbstractionTree = useMemo12(() => {
|
|
@@ -11519,7 +11991,7 @@ function XViewScene({
|
|
|
11519
11991
|
allAncestries
|
|
11520
11992
|
);
|
|
11521
11993
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
11522
|
-
const handleStartReadingAncestry =
|
|
11994
|
+
const handleStartReadingAncestry = useCallback4(
|
|
11523
11995
|
async (ancestryObject) => {
|
|
11524
11996
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11525
11997
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11540,7 +12012,6 @@ function XViewScene({
|
|
|
11540
12012
|
ancestry: ancestryObject,
|
|
11541
12013
|
branchStack: [],
|
|
11542
12014
|
autoAbstraction: shouldAutoRenderAbstraction
|
|
11543
|
-
// <--- FLAG ENVIADA PARA A UI
|
|
11544
12015
|
});
|
|
11545
12016
|
if (shouldAutoRenderAbstraction) {
|
|
11546
12017
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
@@ -11554,9 +12025,8 @@ function XViewScene({
|
|
|
11554
12025
|
}
|
|
11555
12026
|
},
|
|
11556
12027
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
11557
|
-
// <--- DEPENDÊNCIA ADICIONADA
|
|
11558
12028
|
);
|
|
11559
|
-
const handleReadModeSectionChange =
|
|
12029
|
+
const handleReadModeSectionChange = useCallback4((activeSectionId) => {
|
|
11560
12030
|
const { ancestry, branchStack } = readingMode;
|
|
11561
12031
|
if (!ancestry || !readingMode.isActive) return;
|
|
11562
12032
|
let targetObj = ancestry;
|
|
@@ -11625,10 +12095,10 @@ function XViewScene({
|
|
|
11625
12095
|
}, 0);
|
|
11626
12096
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11627
12097
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11628
|
-
const handleCloseReadMode =
|
|
12098
|
+
const handleCloseReadMode = useCallback4(() => {
|
|
11629
12099
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
11630
12100
|
}, []);
|
|
11631
|
-
const handleAncestrySectionChange =
|
|
12101
|
+
const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
11632
12102
|
var _a2, _b2;
|
|
11633
12103
|
const currentMode = stateRef.current.ancestry;
|
|
11634
12104
|
let targetObj = ancestryOverride;
|
|
@@ -11680,7 +12150,7 @@ function XViewScene({
|
|
|
11680
12150
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
11681
12151
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11682
12152
|
}, [handleRenderAncestry]);
|
|
11683
|
-
const handleEditAncestry =
|
|
12153
|
+
const handleEditAncestry = useCallback4(
|
|
11684
12154
|
async (ancestryObject) => {
|
|
11685
12155
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11686
12156
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11703,10 +12173,8 @@ function XViewScene({
|
|
|
11703
12173
|
...ancestryObject,
|
|
11704
12174
|
tree: fullTree,
|
|
11705
12175
|
abstraction_tree: fullAbstractionTree,
|
|
11706
|
-
// NOVO
|
|
11707
12176
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11708
12177
|
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11709
|
-
// NOVO
|
|
11710
12178
|
isEditMode: true,
|
|
11711
12179
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11712
12180
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
@@ -11714,7 +12182,6 @@ function XViewScene({
|
|
|
11714
12182
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11715
12183
|
isAddingNodes: false,
|
|
11716
12184
|
isAddingAbstractionNodes: false
|
|
11717
|
-
// NOVO
|
|
11718
12185
|
});
|
|
11719
12186
|
},
|
|
11720
12187
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11722,7 +12189,7 @@ function XViewScene({
|
|
|
11722
12189
|
const handleSelectAncestryParent = (nodeId) => {
|
|
11723
12190
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
11724
12191
|
};
|
|
11725
|
-
const handleRemoveFromAncestry =
|
|
12192
|
+
const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
|
|
11726
12193
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
11727
12194
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
11728
12195
|
return;
|
|
@@ -11747,7 +12214,7 @@ function XViewScene({
|
|
|
11747
12214
|
return { ...prev, tree: newTree };
|
|
11748
12215
|
});
|
|
11749
12216
|
}, []);
|
|
11750
|
-
const handleSaveAncestry =
|
|
12217
|
+
const handleSaveAncestry = useCallback4(
|
|
11751
12218
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
11752
12219
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
11753
12220
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -11951,7 +12418,7 @@ function XViewScene({
|
|
|
11951
12418
|
});
|
|
11952
12419
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
11953
12420
|
};
|
|
11954
|
-
const handleDeleteAncestry =
|
|
12421
|
+
const handleDeleteAncestry = useCallback4(
|
|
11955
12422
|
async (ancestryIdToDelete) => {
|
|
11956
12423
|
if (!ancestryIdToDelete) {
|
|
11957
12424
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -12013,15 +12480,15 @@ function XViewScene({
|
|
|
12013
12480
|
},
|
|
12014
12481
|
[save_view_data, delete_file_action]
|
|
12015
12482
|
);
|
|
12016
|
-
const handleOpenAncestryBoard =
|
|
12483
|
+
const handleOpenAncestryBoard = useCallback4(() => {
|
|
12017
12484
|
setIsAncestryBoardOpen(true);
|
|
12018
12485
|
}, []);
|
|
12019
|
-
const handleSelectAncestryFromBoard =
|
|
12486
|
+
const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
|
|
12020
12487
|
setIsAncestryBoardOpen(false);
|
|
12021
12488
|
setIsSidebarOpen(false);
|
|
12022
12489
|
handleStartReadingAncestry(ancestry);
|
|
12023
12490
|
}, [handleStartReadingAncestry]);
|
|
12024
|
-
const handleSaveAncestryBoard =
|
|
12491
|
+
const handleSaveAncestryBoard = useCallback4(async (groups) => {
|
|
12025
12492
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
12026
12493
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
12027
12494
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
@@ -12045,13 +12512,13 @@ function XViewScene({
|
|
|
12045
12512
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
12046
12513
|
});
|
|
12047
12514
|
}, [parentDataRef.current, sceneVersion]);
|
|
12048
|
-
const handleAddExistingNode =
|
|
12515
|
+
const handleAddExistingNode = useCallback4(
|
|
12049
12516
|
(nodeId) => {
|
|
12050
12517
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
12051
12518
|
},
|
|
12052
12519
|
[actionHandlerContext]
|
|
12053
12520
|
);
|
|
12054
|
-
const handleSaveCurrentView =
|
|
12521
|
+
const handleSaveCurrentView = useCallback4(async () => {
|
|
12055
12522
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12056
12523
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12057
12524
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12091,7 +12558,7 @@ function XViewScene({
|
|
|
12091
12558
|
const allAvailableAncestries = useMemo12(() => {
|
|
12092
12559
|
return ancestryDataRef.current || [];
|
|
12093
12560
|
}, [sceneVersion, isInitialized]);
|
|
12094
|
-
const handleOpenReference =
|
|
12561
|
+
const handleOpenReference = useCallback4((referenceData) => {
|
|
12095
12562
|
const { type, id } = referenceData;
|
|
12096
12563
|
if (type === "node") {
|
|
12097
12564
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -12118,10 +12585,10 @@ function XViewScene({
|
|
|
12118
12585
|
}
|
|
12119
12586
|
}
|
|
12120
12587
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
12121
|
-
const handleToggleAncestryAddMode =
|
|
12588
|
+
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
12122
12589
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
12123
12590
|
}, []);
|
|
12124
|
-
const handleFocusNode =
|
|
12591
|
+
const handleFocusNode = useCallback4((nodeData) => {
|
|
12125
12592
|
if (!nodeData) return;
|
|
12126
12593
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
12127
12594
|
if (nodeMesh) {
|
|
@@ -12191,7 +12658,6 @@ function XViewScene({
|
|
|
12191
12658
|
height: "100vh",
|
|
12192
12659
|
position: "relative",
|
|
12193
12660
|
overflow: "hidden",
|
|
12194
|
-
// <--- ADICIONE ESTA LINHA
|
|
12195
12661
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12196
12662
|
}
|
|
12197
12663
|
},
|
|
@@ -12258,9 +12724,20 @@ function XViewScene({
|
|
|
12258
12724
|
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
|
|
12259
12725
|
"div",
|
|
12260
12726
|
{
|
|
12261
|
-
className:
|
|
12262
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
|
|
12727
|
+
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
12728
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12263
12729
|
},
|
|
12730
|
+
/* @__PURE__ */ React23.createElement(
|
|
12731
|
+
"div",
|
|
12732
|
+
{
|
|
12733
|
+
onPointerDown: (e) => {
|
|
12734
|
+
e.stopPropagation();
|
|
12735
|
+
handleReadModeResize(e);
|
|
12736
|
+
},
|
|
12737
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
12738
|
+
title: "Arraste para redimensionar"
|
|
12739
|
+
}
|
|
12740
|
+
),
|
|
12264
12741
|
/* @__PURE__ */ React23.createElement(
|
|
12265
12742
|
DescriptionReadModePanel,
|
|
12266
12743
|
{
|