@lv-x-software-house/x_view 1.2.2-dev.8 → 1.2.2
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 +1386 -895
- package/dist/index.mjs +849 -357
- 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)
|
|
@@ -4216,15 +4419,14 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
|
|
|
4216
4419
|
className: `
|
|
4217
4420
|
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
4421
|
${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}`
|
|
4422
|
+
`
|
|
4221
4423
|
},
|
|
4222
4424
|
/* @__PURE__ */ React6.createElement("span", { className: "opacity-60 text-[0.8em]" }, "@"),
|
|
4223
4425
|
displayName
|
|
4224
4426
|
);
|
|
4225
4427
|
});
|
|
4226
4428
|
};
|
|
4227
|
-
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
|
|
4429
|
+
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
|
|
4228
4430
|
const trimmedLine = line.replace(/\r$/, "");
|
|
4229
4431
|
const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
|
|
4230
4432
|
if (line.startsWith("# ")) {
|
|
@@ -4235,9 +4437,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
|
|
|
4235
4437
|
const content = line.replace("## ", "");
|
|
4236
4438
|
return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
|
|
4237
4439
|
}
|
|
4440
|
+
const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
|
|
4441
|
+
if (checkboxMatch) {
|
|
4442
|
+
const [_, space, state, content] = checkboxMatch;
|
|
4443
|
+
const isChecked = state.toLowerCase() === "x";
|
|
4444
|
+
const currentIdx = globalCheckboxCounterRef.current;
|
|
4445
|
+
globalCheckboxCounterRef.current += 1;
|
|
4446
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
|
|
4447
|
+
"div",
|
|
4448
|
+
{
|
|
4449
|
+
onClick: (e) => {
|
|
4450
|
+
e.stopPropagation();
|
|
4451
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4452
|
+
},
|
|
4453
|
+
className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
|
|
4454
|
+
${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"}
|
|
4455
|
+
`
|
|
4456
|
+
},
|
|
4457
|
+
isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
|
|
4458
|
+
), /* @__PURE__ */ React6.createElement(
|
|
4459
|
+
"span",
|
|
4460
|
+
{
|
|
4461
|
+
className: `transition-all duration-200 cursor-pointer pt-[1px]
|
|
4462
|
+
${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
|
|
4463
|
+
`,
|
|
4464
|
+
onClick: (e) => {
|
|
4465
|
+
e.stopPropagation();
|
|
4466
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4467
|
+
}
|
|
4468
|
+
},
|
|
4469
|
+
processContent(content)
|
|
4470
|
+
));
|
|
4471
|
+
}
|
|
4472
|
+
const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
|
|
4473
|
+
if (numberMatch) {
|
|
4474
|
+
const [_, space, numberStr, content] = numberMatch;
|
|
4475
|
+
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)));
|
|
4476
|
+
}
|
|
4238
4477
|
if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
|
|
4239
4478
|
const content = trimmedLine.trim().substring(2);
|
|
4240
|
-
return /* @__PURE__ */ React6.createElement("span", { className: "
|
|
4479
|
+
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
4480
|
}
|
|
4242
4481
|
return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
|
|
4243
4482
|
};
|
|
@@ -4249,14 +4488,33 @@ function DescriptionDisplay({
|
|
|
4249
4488
|
onOpenReference,
|
|
4250
4489
|
onMentionClick,
|
|
4251
4490
|
onImageClick,
|
|
4252
|
-
// <--- NOVA PROP RECEBIDA
|
|
4253
4491
|
onSectionChange,
|
|
4254
4492
|
onBranchNav,
|
|
4255
4493
|
onHighlightNode,
|
|
4256
4494
|
initialSectionId,
|
|
4257
|
-
currentBranchDirection = null
|
|
4495
|
+
currentBranchDirection = null,
|
|
4496
|
+
onSaveDescription,
|
|
4497
|
+
onStepChange
|
|
4498
|
+
// 1. Adicione a nova prop aqui
|
|
4258
4499
|
}) {
|
|
4259
|
-
const
|
|
4500
|
+
const [localDescription, setLocalDescription] = useState7(description || "");
|
|
4501
|
+
useEffect6(() => {
|
|
4502
|
+
setLocalDescription(description || "");
|
|
4503
|
+
}, [description]);
|
|
4504
|
+
const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
|
|
4505
|
+
const globalCheckboxCounterRef = useRef6(0);
|
|
4506
|
+
const handleToggleCheckbox = (targetIndex) => {
|
|
4507
|
+
let currentIndex = 0;
|
|
4508
|
+
const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
|
|
4509
|
+
if (currentIndex === targetIndex) {
|
|
4510
|
+
currentIndex++;
|
|
4511
|
+
return state === " " ? `${space}- [x]` : `${space}- [ ]`;
|
|
4512
|
+
}
|
|
4513
|
+
currentIndex++;
|
|
4514
|
+
return match;
|
|
4515
|
+
});
|
|
4516
|
+
setLocalDescription(newDesc);
|
|
4517
|
+
};
|
|
4260
4518
|
const flatNavigation = useMemo5(() => {
|
|
4261
4519
|
const navItems = [];
|
|
4262
4520
|
sections.forEach((section, sIdx) => {
|
|
@@ -4283,7 +4541,12 @@ function DescriptionDisplay({
|
|
|
4283
4541
|
});
|
|
4284
4542
|
return navItems;
|
|
4285
4543
|
}, [sections]);
|
|
4286
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
4544
|
+
const [currentStepIndex, setCurrentStepIndex] = useState7(0);
|
|
4545
|
+
useEffect6(() => {
|
|
4546
|
+
if (onStepChange) {
|
|
4547
|
+
onStepChange(currentStepIndex);
|
|
4548
|
+
}
|
|
4549
|
+
}, [currentStepIndex, onStepChange]);
|
|
4287
4550
|
const activeRef = useRef6(null);
|
|
4288
4551
|
const lastNotifiedSectionId = useRef6(null);
|
|
4289
4552
|
const isInitialMount = useRef6(true);
|
|
@@ -4397,26 +4660,27 @@ function DescriptionDisplay({
|
|
|
4397
4660
|
}
|
|
4398
4661
|
const lines = part.replace(/\n$/, "").split("\n");
|
|
4399
4662
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
|
|
4400
|
-
const isLastLine = lineIndex === lines.length - 1;
|
|
4401
4663
|
const isEmptyLine = line.trim() === "";
|
|
4402
4664
|
if (isEmptyLine) {
|
|
4403
4665
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
|
|
4404
4666
|
}
|
|
4405
4667
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
|
|
4406
|
-
"
|
|
4668
|
+
"div",
|
|
4407
4669
|
{
|
|
4408
4670
|
ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
|
|
4409
|
-
onClick: () => {
|
|
4410
|
-
|
|
4411
|
-
|
|
4671
|
+
onClick: (e) => {
|
|
4672
|
+
if (e.target.type !== "checkbox") {
|
|
4673
|
+
const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
|
|
4674
|
+
if (idx !== -1) setCurrentStepIndex(idx);
|
|
4675
|
+
}
|
|
4412
4676
|
},
|
|
4413
4677
|
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/
|
|
4678
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
|
|
4679
|
+
${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
|
|
4416
4680
|
`
|
|
4417
4681
|
},
|
|
4418
|
-
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
|
|
4419
|
-
)
|
|
4682
|
+
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
|
|
4683
|
+
));
|
|
4420
4684
|
}));
|
|
4421
4685
|
});
|
|
4422
4686
|
};
|
|
@@ -4434,8 +4698,7 @@ function DescriptionDisplay({
|
|
|
4434
4698
|
if (onOpenReference) {
|
|
4435
4699
|
onOpenReference({ type: resolved.type, id: resolved.sourceId });
|
|
4436
4700
|
}
|
|
4437
|
-
}
|
|
4438
|
-
title: `Ir para ${resolved.type === "node" ? "Node" : "Ancestralidade"}: ${resolved.sourceName}`
|
|
4701
|
+
}
|
|
4439
4702
|
},
|
|
4440
4703
|
/* @__PURE__ */ React6.createElement(FiCornerDownRight, { size: 12, className: "text-indigo-400" }),
|
|
4441
4704
|
/* @__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 +4707,9 @@ function DescriptionDisplay({
|
|
|
4444
4707
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4445
4708
|
` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
|
|
4446
4709
|
};
|
|
4447
|
-
|
|
4710
|
+
globalCheckboxCounterRef.current = 0;
|
|
4711
|
+
const hasUnsavedChanges = localDescription !== (description || "");
|
|
4712
|
+
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
4713
|
const currentNavItem = flatNavigation[currentStepIndex];
|
|
4449
4714
|
const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
|
|
4450
4715
|
const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
|
|
@@ -4460,11 +4725,22 @@ function DescriptionDisplay({
|
|
|
4460
4725
|
if (index === 0) leadingSpace = "";
|
|
4461
4726
|
const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
|
|
4462
4727
|
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
|
-
}))
|
|
4728
|
+
})), 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(
|
|
4729
|
+
"button",
|
|
4730
|
+
{
|
|
4731
|
+
onClick: (e) => {
|
|
4732
|
+
e.stopPropagation();
|
|
4733
|
+
onSaveDescription(localDescription);
|
|
4734
|
+
},
|
|
4735
|
+
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"
|
|
4736
|
+
},
|
|
4737
|
+
/* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
|
|
4738
|
+
" Salvar Checklist"
|
|
4739
|
+
)));
|
|
4464
4740
|
}
|
|
4465
4741
|
|
|
4466
4742
|
// src/components/DescriptionReadModePanel.jsx
|
|
4467
|
-
import React7, { useState as
|
|
4743
|
+
import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
|
|
4468
4744
|
import {
|
|
4469
4745
|
FiArrowLeft,
|
|
4470
4746
|
FiEdit2,
|
|
@@ -4543,7 +4819,6 @@ function DescriptionReadModePanel({
|
|
|
4543
4819
|
title,
|
|
4544
4820
|
description,
|
|
4545
4821
|
ancestryId,
|
|
4546
|
-
// <-- NOVO: Prop recebida do XViewScene
|
|
4547
4822
|
savedSections,
|
|
4548
4823
|
onBack,
|
|
4549
4824
|
onEdit,
|
|
@@ -4565,12 +4840,14 @@ function DescriptionReadModePanel({
|
|
|
4565
4840
|
userRole,
|
|
4566
4841
|
abstractionTree = null,
|
|
4567
4842
|
onRenderAbstractionTree = null,
|
|
4568
|
-
initialShowAbstraction = false
|
|
4843
|
+
initialShowAbstraction = false,
|
|
4844
|
+
onSaveDescription
|
|
4569
4845
|
}) {
|
|
4570
|
-
const [showProperties, setShowProperties] =
|
|
4571
|
-
const [showAbstraction, setShowAbstraction] =
|
|
4572
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
4573
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
4846
|
+
const [showProperties, setShowProperties] = useState8(false);
|
|
4847
|
+
const [showAbstraction, setShowAbstraction] = useState8(false);
|
|
4848
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
|
|
4849
|
+
const [isLinkCopied, setIsLinkCopied] = useState8(false);
|
|
4850
|
+
const [isAtStartOfBranch, setIsAtStartOfBranch] = useState8(true);
|
|
4574
4851
|
const handleCopyLink = (e) => {
|
|
4575
4852
|
e.stopPropagation();
|
|
4576
4853
|
if (!ancestryId) return;
|
|
@@ -4623,7 +4900,7 @@ function DescriptionReadModePanel({
|
|
|
4623
4900
|
onClick: () => onBranchNav(activeNodeBranches.nodeId, "open", "left")
|
|
4624
4901
|
};
|
|
4625
4902
|
}
|
|
4626
|
-
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "left") {
|
|
4903
|
+
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "left" && isAtStartOfBranch) {
|
|
4627
4904
|
return {
|
|
4628
4905
|
type: "back",
|
|
4629
4906
|
name: backNavigationInfo.name,
|
|
@@ -4631,7 +4908,7 @@ function DescriptionReadModePanel({
|
|
|
4631
4908
|
};
|
|
4632
4909
|
}
|
|
4633
4910
|
return null;
|
|
4634
|
-
}, [activeNodeBranches, backNavigationInfo, onBranchNav]);
|
|
4911
|
+
}, [activeNodeBranches, backNavigationInfo, onBranchNav, isAtStartOfBranch]);
|
|
4635
4912
|
const rightAction = useMemo6(() => {
|
|
4636
4913
|
if (activeNodeBranches == null ? void 0 : activeNodeBranches.right) {
|
|
4637
4914
|
return {
|
|
@@ -4640,7 +4917,7 @@ function DescriptionReadModePanel({
|
|
|
4640
4917
|
onClick: () => onBranchNav(activeNodeBranches.nodeId, "open", "right")
|
|
4641
4918
|
};
|
|
4642
4919
|
}
|
|
4643
|
-
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "right") {
|
|
4920
|
+
if ((backNavigationInfo == null ? void 0 : backNavigationInfo.trigger) === "right" && isAtStartOfBranch) {
|
|
4644
4921
|
return {
|
|
4645
4922
|
type: "back",
|
|
4646
4923
|
name: backNavigationInfo.name,
|
|
@@ -4648,11 +4925,11 @@ function DescriptionReadModePanel({
|
|
|
4648
4925
|
};
|
|
4649
4926
|
}
|
|
4650
4927
|
return null;
|
|
4651
|
-
}, [activeNodeBranches, backNavigationInfo, onBranchNav]);
|
|
4928
|
+
}, [activeNodeBranches, backNavigationInfo, onBranchNav, isAtStartOfBranch]);
|
|
4652
4929
|
return /* @__PURE__ */ React7.createElement(
|
|
4653
4930
|
"div",
|
|
4654
4931
|
{
|
|
4655
|
-
className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
|
|
4932
|
+
className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
|
|
4656
4933
|
onPointerDown: swallow,
|
|
4657
4934
|
onClick: swallow
|
|
4658
4935
|
},
|
|
@@ -4724,7 +5001,7 @@ function DescriptionReadModePanel({
|
|
|
4724
5001
|
},
|
|
4725
5002
|
"\xD7"
|
|
4726
5003
|
))),
|
|
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(
|
|
5004
|
+
/* @__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
5005
|
"button",
|
|
4729
5006
|
{
|
|
4730
5007
|
onClick: (e) => {
|
|
@@ -4783,7 +5060,9 @@ function DescriptionReadModePanel({
|
|
|
4783
5060
|
onHighlightNode,
|
|
4784
5061
|
initialSectionId,
|
|
4785
5062
|
currentBranchDirection,
|
|
4786
|
-
onImageClick
|
|
5063
|
+
onImageClick,
|
|
5064
|
+
onSaveDescription,
|
|
5065
|
+
onStepChange: (stepIndex) => setIsAtStartOfBranch(stepIndex === 0)
|
|
4787
5066
|
}
|
|
4788
5067
|
)),
|
|
4789
5068
|
leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
|
|
@@ -4825,11 +5104,11 @@ function AncestryRelationshipPanel({
|
|
|
4825
5104
|
onMentionClick,
|
|
4826
5105
|
onUploadFile
|
|
4827
5106
|
}) {
|
|
4828
|
-
const [description, setDescription] =
|
|
4829
|
-
const [customProps, setCustomProps] =
|
|
4830
|
-
const [existingSections, setExistingSections] =
|
|
4831
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
4832
|
-
const [isReadMode, setIsReadMode] =
|
|
5107
|
+
const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
|
|
5108
|
+
const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
|
|
5109
|
+
const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
|
|
5110
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
|
|
5111
|
+
const [isReadMode, setIsReadMode] = useState9(false);
|
|
4833
5112
|
const propsEndRef = useRef7(null);
|
|
4834
5113
|
useEffect8(() => {
|
|
4835
5114
|
setDescription((data == null ? void 0 : data.description) ?? "");
|
|
@@ -4853,6 +5132,17 @@ function AncestryRelationshipPanel({
|
|
|
4853
5132
|
return newProps;
|
|
4854
5133
|
});
|
|
4855
5134
|
};
|
|
5135
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
5136
|
+
setDescription(newDescription);
|
|
5137
|
+
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
5138
|
+
const processedSections = processDescriptionForSave(newDescription, existingSections);
|
|
5139
|
+
const dataToSave = {
|
|
5140
|
+
description: newDescription,
|
|
5141
|
+
description_sections: processedSections,
|
|
5142
|
+
...extrasObj
|
|
5143
|
+
};
|
|
5144
|
+
onSave(dataToSave);
|
|
5145
|
+
};
|
|
4856
5146
|
const handleSave = () => {
|
|
4857
5147
|
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
4858
5148
|
const processedSections = processDescriptionForSave(description, existingSections);
|
|
@@ -4902,7 +5192,8 @@ function AncestryRelationshipPanel({
|
|
|
4902
5192
|
availableAncestries,
|
|
4903
5193
|
onOpenReference,
|
|
4904
5194
|
onMentionClick,
|
|
4905
|
-
onImageClick: handleImageClickFromText
|
|
5195
|
+
onImageClick: handleImageClickFromText,
|
|
5196
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4906
5197
|
}
|
|
4907
5198
|
) : /* @__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
5199
|
DescriptionDisplay,
|
|
@@ -4913,7 +5204,8 @@ function AncestryRelationshipPanel({
|
|
|
4913
5204
|
availableAncestries,
|
|
4914
5205
|
onOpenReference,
|
|
4915
5206
|
onMentionClick,
|
|
4916
|
-
onImageClick: handleImageClickFromText
|
|
5207
|
+
onImageClick: handleImageClickFromText,
|
|
5208
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4917
5209
|
}
|
|
4918
5210
|
), /* @__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
5211
|
"button",
|
|
@@ -4971,7 +5263,7 @@ function AncestryRelationshipPanel({
|
|
|
4971
5263
|
}
|
|
4972
5264
|
|
|
4973
5265
|
// src/components/CreateAncestryPanel.jsx
|
|
4974
|
-
import React10, { useState as
|
|
5266
|
+
import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
|
|
4975
5267
|
import {
|
|
4976
5268
|
FiEdit2 as FiEdit23,
|
|
4977
5269
|
FiBookOpen as FiBookOpen2,
|
|
@@ -4987,11 +5279,12 @@ import {
|
|
|
4987
5279
|
FiGitBranch as FiGitBranch2,
|
|
4988
5280
|
FiPlus as FiPlus2,
|
|
4989
5281
|
FiLock,
|
|
4990
|
-
FiLink as FiLink4
|
|
5282
|
+
FiLink as FiLink4,
|
|
5283
|
+
FiTrash2 as FiTrash22
|
|
4991
5284
|
} from "react-icons/fi";
|
|
4992
5285
|
|
|
4993
5286
|
// src/components/AncestryPickerModal.jsx
|
|
4994
|
-
import React9, { useState as
|
|
5287
|
+
import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
|
|
4995
5288
|
import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
|
|
4996
5289
|
function AncestryPickerModal({
|
|
4997
5290
|
isOpen,
|
|
@@ -5001,7 +5294,7 @@ function AncestryPickerModal({
|
|
|
5001
5294
|
availableNodes = [],
|
|
5002
5295
|
currentAncestryId
|
|
5003
5296
|
}) {
|
|
5004
|
-
const [searchTerm, setSearchTerm] =
|
|
5297
|
+
const [searchTerm, setSearchTerm] = useState10("");
|
|
5005
5298
|
useEffect9(() => {
|
|
5006
5299
|
if (!isOpen) return;
|
|
5007
5300
|
const handleKeyDown = (e) => {
|
|
@@ -5086,7 +5379,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
|
|
|
5086
5379
|
var _a, _b;
|
|
5087
5380
|
const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
|
|
5088
5381
|
const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
|
|
5089
|
-
const [isDragOver, setIsDragOver] =
|
|
5382
|
+
const [isDragOver, setIsDragOver] = useState11(false);
|
|
5090
5383
|
const isSelectedParent = String(selectedParentId) === String(itemId);
|
|
5091
5384
|
const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
|
|
5092
5385
|
const isHighlightedPath = highlightedPathIds.includes(String(itemId));
|
|
@@ -5222,8 +5515,9 @@ function CreateAncestryPanel({
|
|
|
5222
5515
|
isAddingNodes,
|
|
5223
5516
|
currentAncestryId
|
|
5224
5517
|
} = ancestryMode;
|
|
5225
|
-
const [isSaving, setIsSaving] =
|
|
5226
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
5518
|
+
const [isSaving, setIsSaving] = useState11(false);
|
|
5519
|
+
const [isLinkCopied, setIsLinkCopied] = useState11(false);
|
|
5520
|
+
const [showDeleteBranchConfirm, setShowDeleteBranchConfirm] = useState11(false);
|
|
5227
5521
|
const handleCopyLink = (e) => {
|
|
5228
5522
|
e.stopPropagation();
|
|
5229
5523
|
if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
|
|
@@ -5237,11 +5531,14 @@ function CreateAncestryPanel({
|
|
|
5237
5531
|
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
5238
5532
|
}).catch((err) => console.error("Erro ao copiar link:", err));
|
|
5239
5533
|
};
|
|
5240
|
-
const [isPickerOpen, setIsPickerOpen] =
|
|
5241
|
-
const [customProps, setCustomProps] =
|
|
5534
|
+
const [isPickerOpen, setIsPickerOpen] = useState11(false);
|
|
5535
|
+
const [customProps, setCustomProps] = useState11([]);
|
|
5242
5536
|
const propsEndRef = useRef8(null);
|
|
5243
|
-
const [branchStack, setBranchStack] =
|
|
5244
|
-
|
|
5537
|
+
const [branchStack, setBranchStack] = useState11([]);
|
|
5538
|
+
useEffect10(() => {
|
|
5539
|
+
setShowDeleteBranchConfirm(false);
|
|
5540
|
+
}, [branchStack]);
|
|
5541
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
|
|
5245
5542
|
const highlightedPathIds = useMemo8(() => {
|
|
5246
5543
|
var _a, _b;
|
|
5247
5544
|
if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
|
|
@@ -5255,17 +5552,27 @@ function CreateAncestryPanel({
|
|
|
5255
5552
|
}
|
|
5256
5553
|
return ids;
|
|
5257
5554
|
}, [targetRenderNodeId, ancestryMode.abstraction_tree]);
|
|
5258
|
-
const [targetScrollSectionId, setTargetScrollSectionId] =
|
|
5259
|
-
const [internalHighlightedNodeId, setInternalHighlightedNodeId] =
|
|
5260
|
-
const [
|
|
5261
|
-
const [
|
|
5262
|
-
const [
|
|
5263
|
-
const [
|
|
5264
|
-
const [
|
|
5555
|
+
const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
|
|
5556
|
+
const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
|
|
5557
|
+
const [isAtStartOfBranch, setIsAtStartOfBranch] = useState11(true);
|
|
5558
|
+
const [ancestryName, setAncestryName] = useState11(initialName);
|
|
5559
|
+
const [description, setDescription] = useState11(initialDescription || "");
|
|
5560
|
+
const [existingSections, setExistingSections] = useState11(initialSections || []);
|
|
5561
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
|
|
5562
|
+
const [isReadMode, setIsReadMode] = useState11(false);
|
|
5563
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
5564
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
5565
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
5566
|
+
minWidth: 320,
|
|
5567
|
+
maxWidth: maxPanelW
|
|
5568
|
+
});
|
|
5569
|
+
useEffect10(() => {
|
|
5570
|
+
setWidth(isReadMode ? 700 : 440);
|
|
5571
|
+
}, [isReadMode, setWidth]);
|
|
5265
5572
|
const currentMaxRenderIndexRef = useRef8(0);
|
|
5266
5573
|
const branchProgressMapRef = useRef8({});
|
|
5267
|
-
const [lastSavedSnapshot, setLastSavedSnapshot] =
|
|
5268
|
-
const [isPrivate, setIsPrivate] =
|
|
5574
|
+
const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
|
|
5575
|
+
const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
|
|
5269
5576
|
const initializedContextIdRef = useRef8(null);
|
|
5270
5577
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
5271
5578
|
const handleImageClickFromText = (url, name) => {
|
|
@@ -5284,7 +5591,7 @@ function CreateAncestryPanel({
|
|
|
5284
5591
|
}
|
|
5285
5592
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5286
5593
|
};
|
|
5287
|
-
const handleRemoveNode =
|
|
5594
|
+
const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
|
|
5288
5595
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5289
5596
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5290
5597
|
setAncestryMode((prev) => {
|
|
@@ -5641,6 +5948,59 @@ function CreateAncestryPanel({
|
|
|
5641
5948
|
}
|
|
5642
5949
|
}
|
|
5643
5950
|
};
|
|
5951
|
+
const handleDeleteBranch = async () => {
|
|
5952
|
+
if (branchStack.length === 0) return;
|
|
5953
|
+
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
5954
|
+
let ptr = rootTreeClone;
|
|
5955
|
+
for (let i = 0; i < branchStack.length - 1; i++) {
|
|
5956
|
+
const step = branchStack[i];
|
|
5957
|
+
const found = findNodePath2(ptr, step.nodeId);
|
|
5958
|
+
if (found && found.node.parallel_branches) {
|
|
5959
|
+
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5960
|
+
if (branch) ptr = branch.tree;
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
const currentStep = branchStack[branchStack.length - 1];
|
|
5964
|
+
const foundParentPath = findNodePath2(ptr, currentStep.nodeId);
|
|
5965
|
+
if (foundParentPath && foundParentPath.node && foundParentPath.node.parallel_branches) {
|
|
5966
|
+
const branchIndex = foundParentPath.node.parallel_branches.findIndex((b) => b.id === currentStep.branchId);
|
|
5967
|
+
if (branchIndex !== -1) {
|
|
5968
|
+
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
5969
|
+
updateGlobalTree(rootTreeClone);
|
|
5970
|
+
try {
|
|
5971
|
+
setIsSaving(true);
|
|
5972
|
+
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
5973
|
+
const rootExtras = toObjectFromCustomProps(currentRootProps);
|
|
5974
|
+
await onSave(
|
|
5975
|
+
ancestryMode.ancestryName,
|
|
5976
|
+
ancestryMode.ancestryDescription,
|
|
5977
|
+
ancestryMode.ancestryDescriptionSections,
|
|
5978
|
+
true,
|
|
5979
|
+
rootTreeClone,
|
|
5980
|
+
rootExtras
|
|
5981
|
+
);
|
|
5982
|
+
setLastSavedSnapshot(takeSnapshot(
|
|
5983
|
+
rootTreeClone,
|
|
5984
|
+
ancestryMode.ancestryName,
|
|
5985
|
+
ancestryMode.ancestryDescription,
|
|
5986
|
+
ancestryMode.ancestryDescriptionSections,
|
|
5987
|
+
currentRootProps,
|
|
5988
|
+
isPrivate,
|
|
5989
|
+
ancestryMode.abstraction_tree
|
|
5990
|
+
));
|
|
5991
|
+
if (onClearAncestryVisuals) {
|
|
5992
|
+
onClearAncestryVisuals(currentStep.branchId);
|
|
5993
|
+
}
|
|
5994
|
+
handleNavigateUp();
|
|
5995
|
+
} catch (err) {
|
|
5996
|
+
console.error("Erro ao remover a ramifica\xE7\xE3o:", err);
|
|
5997
|
+
alert("Erro ao remover a ramifica\xE7\xE3o.");
|
|
5998
|
+
} finally {
|
|
5999
|
+
setIsSaving(false);
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
5644
6004
|
const sideActions = useMemo8(() => {
|
|
5645
6005
|
const actions = { left: null, right: null };
|
|
5646
6006
|
const isInBranch = branchStack.length > 0;
|
|
@@ -5679,7 +6039,7 @@ function CreateAncestryPanel({
|
|
|
5679
6039
|
}
|
|
5680
6040
|
return actions;
|
|
5681
6041
|
}
|
|
5682
|
-
if (isInBranch) {
|
|
6042
|
+
if (isInBranch && isAtStartOfBranch) {
|
|
5683
6043
|
const lastStep = branchStack[branchStack.length - 1];
|
|
5684
6044
|
const entryDir = lastStep.entryDirection || "right";
|
|
5685
6045
|
const backSide = entryDir === "right" ? "left" : "right";
|
|
@@ -5690,7 +6050,7 @@ function CreateAncestryPanel({
|
|
|
5690
6050
|
};
|
|
5691
6051
|
}
|
|
5692
6052
|
return actions;
|
|
5693
|
-
}, [internalHighlightedNodeId, branchStack, activeTree]);
|
|
6053
|
+
}, [internalHighlightedNodeId, branchStack, activeTree, isAtStartOfBranch]);
|
|
5694
6054
|
const applyDescriptionToTree = (baseTree, descText, descSections) => {
|
|
5695
6055
|
const rootTreeClone = JSON.parse(JSON.stringify(baseTree));
|
|
5696
6056
|
let targetTree = rootTreeClone;
|
|
@@ -6168,6 +6528,10 @@ function CreateAncestryPanel({
|
|
|
6168
6528
|
setInternalHighlightedNodeId(id);
|
|
6169
6529
|
if (onHighlightNode) onHighlightNode(id);
|
|
6170
6530
|
};
|
|
6531
|
+
const handleSaveDescriptionInline = (newDesc) => {
|
|
6532
|
+
setDescription(newDesc);
|
|
6533
|
+
handleLocalSave(true, { description: newDesc });
|
|
6534
|
+
};
|
|
6171
6535
|
const swallow = (e) => e.stopPropagation();
|
|
6172
6536
|
const getSelectedParentName = () => {
|
|
6173
6537
|
if (!activeTree || !selectedParentId) return "";
|
|
@@ -6240,10 +6604,8 @@ function CreateAncestryPanel({
|
|
|
6240
6604
|
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
6241
6605
|
"div",
|
|
6242
6606
|
{
|
|
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)" },
|
|
6607
|
+
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"}`,
|
|
6608
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
6247
6609
|
onPointerDown: swallow,
|
|
6248
6610
|
onPointerMove: swallow,
|
|
6249
6611
|
onPointerUp: swallow,
|
|
@@ -6252,6 +6614,17 @@ function CreateAncestryPanel({
|
|
|
6252
6614
|
onContextMenu: swallow,
|
|
6253
6615
|
onDoubleClick: swallow
|
|
6254
6616
|
},
|
|
6617
|
+
/* @__PURE__ */ React10.createElement(
|
|
6618
|
+
"div",
|
|
6619
|
+
{
|
|
6620
|
+
onPointerDown: (e) => {
|
|
6621
|
+
e.stopPropagation();
|
|
6622
|
+
handleResize(e);
|
|
6623
|
+
},
|
|
6624
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
6625
|
+
title: "Arraste para redimensionar"
|
|
6626
|
+
}
|
|
6627
|
+
),
|
|
6255
6628
|
isReadMode ? /* @__PURE__ */ React10.createElement(
|
|
6256
6629
|
DescriptionReadModePanel,
|
|
6257
6630
|
{
|
|
@@ -6270,7 +6643,8 @@ function CreateAncestryPanel({
|
|
|
6270
6643
|
onMentionClick,
|
|
6271
6644
|
onSectionChange: handleSectionChangeWrapper,
|
|
6272
6645
|
onHighlightNode,
|
|
6273
|
-
onImageClick: handleImageClickFromText
|
|
6646
|
+
onImageClick: handleImageClickFromText,
|
|
6647
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6274
6648
|
}
|
|
6275
6649
|
) : /* @__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
6650
|
"button",
|
|
@@ -6289,7 +6663,7 @@ function CreateAncestryPanel({
|
|
|
6289
6663
|
placeholder: "Nome da Ancestralidade",
|
|
6290
6664
|
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
6665
|
}
|
|
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(
|
|
6666
|
+
)), /* @__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
6667
|
"button",
|
|
6294
6668
|
{
|
|
6295
6669
|
onClick: handleNavigateUp,
|
|
@@ -6297,7 +6671,33 @@ function CreateAncestryPanel({
|
|
|
6297
6671
|
},
|
|
6298
6672
|
/* @__PURE__ */ React10.createElement(FiArrowLeft2, null),
|
|
6299
6673
|
" Voltar para Principal / N\xEDvel Anterior"
|
|
6300
|
-
)
|
|
6674
|
+
), !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(
|
|
6675
|
+
"button",
|
|
6676
|
+
{
|
|
6677
|
+
onClick: () => {
|
|
6678
|
+
setShowDeleteBranchConfirm(false);
|
|
6679
|
+
handleDeleteBranch();
|
|
6680
|
+
},
|
|
6681
|
+
className: "text-xs font-bold text-rose-400 hover:text-rose-200 transition-colors"
|
|
6682
|
+
},
|
|
6683
|
+
"Sim"
|
|
6684
|
+
), /* @__PURE__ */ React10.createElement("span", { className: "text-slate-600/50" }, "|"), /* @__PURE__ */ React10.createElement(
|
|
6685
|
+
"button",
|
|
6686
|
+
{
|
|
6687
|
+
onClick: () => setShowDeleteBranchConfirm(false),
|
|
6688
|
+
className: "text-xs text-slate-400 hover:text-white transition-colors"
|
|
6689
|
+
},
|
|
6690
|
+
"N\xE3o"
|
|
6691
|
+
))) : /* @__PURE__ */ React10.createElement(
|
|
6692
|
+
"button",
|
|
6693
|
+
{
|
|
6694
|
+
onClick: () => setShowDeleteBranchConfirm(true),
|
|
6695
|
+
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",
|
|
6696
|
+
title: "Excluir permanentemente esta ramifica\xE7\xE3o e seu conte\xFAdo"
|
|
6697
|
+
},
|
|
6698
|
+
/* @__PURE__ */ React10.createElement(FiTrash22, null),
|
|
6699
|
+
" Excluir Ramifica\xE7\xE3o"
|
|
6700
|
+
))), /* @__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
6701
|
"button",
|
|
6302
6702
|
{
|
|
6303
6703
|
onClick: handleUnlinkAncestry,
|
|
@@ -6327,7 +6727,9 @@ function CreateAncestryPanel({
|
|
|
6327
6727
|
onHighlightNode: handleHighlightWrapper,
|
|
6328
6728
|
initialSectionId: targetScrollSectionId,
|
|
6329
6729
|
currentBranchDirection: currentContext ? currentContext.direction : null,
|
|
6330
|
-
onImageClick: handleImageClickFromText
|
|
6730
|
+
onImageClick: handleImageClickFromText,
|
|
6731
|
+
onSaveDescription: handleSaveDescriptionInline,
|
|
6732
|
+
onStepChange: (stepIndex) => setIsAtStartOfBranch(stepIndex === 0)
|
|
6331
6733
|
}
|
|
6332
6734
|
), /* @__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
6735
|
"button",
|
|
@@ -6548,25 +6950,25 @@ function CreateAncestryPanel({
|
|
|
6548
6950
|
}
|
|
6549
6951
|
|
|
6550
6952
|
// src/components/ImageViewer.jsx
|
|
6551
|
-
import React11, { useState as
|
|
6953
|
+
import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
|
|
6552
6954
|
import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
6553
6955
|
function ImageViewer({ data, onClose }) {
|
|
6554
6956
|
var _a;
|
|
6555
6957
|
const { images = [], startIndex = 0, visible } = data;
|
|
6556
|
-
const [currentIndex, setCurrentIndex] =
|
|
6557
|
-
const [isLoading, setIsLoading] =
|
|
6558
|
-
const [loadedSrc, setLoadedSrc] =
|
|
6958
|
+
const [currentIndex, setCurrentIndex] = useState12(startIndex);
|
|
6959
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
6960
|
+
const [loadedSrc, setLoadedSrc] = useState12(null);
|
|
6559
6961
|
useLayoutEffect2(() => {
|
|
6560
6962
|
if (visible) {
|
|
6561
6963
|
setCurrentIndex(startIndex);
|
|
6562
6964
|
}
|
|
6563
6965
|
}, [visible, startIndex]);
|
|
6564
|
-
const handleNext =
|
|
6966
|
+
const handleNext = useCallback3(() => {
|
|
6565
6967
|
if (images.length > 1) {
|
|
6566
6968
|
setCurrentIndex((prev) => (prev + 1) % images.length);
|
|
6567
6969
|
}
|
|
6568
6970
|
}, [images.length]);
|
|
6569
|
-
const handlePrev =
|
|
6971
|
+
const handlePrev = useCallback3(() => {
|
|
6570
6972
|
if (images.length > 1) {
|
|
6571
6973
|
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
|
6572
6974
|
}
|
|
@@ -6671,10 +7073,10 @@ function ImageViewer({ data, onClose }) {
|
|
|
6671
7073
|
}
|
|
6672
7074
|
|
|
6673
7075
|
// src/components/InSceneCreationForm.jsx
|
|
6674
|
-
import React13, { useState as
|
|
7076
|
+
import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
6675
7077
|
|
|
6676
7078
|
// src/components/ColorPicker.jsx
|
|
6677
|
-
import React12, { useState as
|
|
7079
|
+
import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
|
|
6678
7080
|
import { HexColorPicker } from "react-colorful";
|
|
6679
7081
|
import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
|
|
6680
7082
|
var PRESET_COLORS = [
|
|
@@ -6695,7 +7097,7 @@ var PRESET_COLORS = [
|
|
|
6695
7097
|
"#000000"
|
|
6696
7098
|
];
|
|
6697
7099
|
function ColorPicker({ color, onChange, disabled }) {
|
|
6698
|
-
const [isOpen, setIsOpen] =
|
|
7100
|
+
const [isOpen, setIsOpen] = useState13(false);
|
|
6699
7101
|
const popoverRef = useRef9(null);
|
|
6700
7102
|
useEffect12(() => {
|
|
6701
7103
|
const handleClickOutside = (event) => {
|
|
@@ -6770,7 +7172,7 @@ function ColorPicker({ color, onChange, disabled }) {
|
|
|
6770
7172
|
}
|
|
6771
7173
|
|
|
6772
7174
|
// src/components/InSceneCreationForm.jsx
|
|
6773
|
-
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun } from "react-icons/fi";
|
|
7175
|
+
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
|
|
6774
7176
|
function InSceneCreationForm({
|
|
6775
7177
|
onSave,
|
|
6776
7178
|
onCancel,
|
|
@@ -6789,28 +7191,43 @@ function InSceneCreationForm({
|
|
|
6789
7191
|
onMentionClick,
|
|
6790
7192
|
sourceTypes,
|
|
6791
7193
|
onUploadFile,
|
|
6792
|
-
// Props do Dataset adicionadas
|
|
6793
7194
|
availableDatasets = [],
|
|
6794
7195
|
sourceNodeDatasetId,
|
|
6795
7196
|
viewType
|
|
6796
7197
|
}) {
|
|
6797
|
-
|
|
6798
|
-
const [
|
|
6799
|
-
const [
|
|
6800
|
-
const [
|
|
6801
|
-
const [
|
|
6802
|
-
const [
|
|
6803
|
-
const [
|
|
6804
|
-
const [
|
|
6805
|
-
const [
|
|
6806
|
-
const [
|
|
6807
|
-
const [
|
|
6808
|
-
const [
|
|
6809
|
-
const [
|
|
6810
|
-
const [
|
|
7198
|
+
var _a;
|
|
7199
|
+
const [name, setName] = useState14("");
|
|
7200
|
+
const [types, setTypes] = useState14([]);
|
|
7201
|
+
const [typeInput, setTypeInput] = useState14("");
|
|
7202
|
+
const [color, setColor] = useState14(initialColor || "#cccccc");
|
|
7203
|
+
const [size, setSize] = useState14("medium");
|
|
7204
|
+
const [intensity, setIntensity] = useState14(0);
|
|
7205
|
+
const [description, setDescription] = useState14("");
|
|
7206
|
+
const [customProps, setCustomProps] = useState14([]);
|
|
7207
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
|
|
7208
|
+
const [filteredTypes, setFilteredTypes] = useState14([]);
|
|
7209
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
|
|
7210
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
|
|
7211
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
|
|
7212
|
+
const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
|
|
7213
|
+
const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
|
|
7214
|
+
const datasetDropdownRef = useRef10(null);
|
|
6811
7215
|
useEffect13(() => {
|
|
6812
7216
|
if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
|
|
6813
7217
|
}, [sourceNodeDatasetId]);
|
|
7218
|
+
useEffect13(() => {
|
|
7219
|
+
function handleClickOutside(event) {
|
|
7220
|
+
if (datasetDropdownRef.current && !datasetDropdownRef.current.contains(event.target)) {
|
|
7221
|
+
setIsDatasetDropdownOpen(false);
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7224
|
+
if (isDatasetDropdownOpen) {
|
|
7225
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
7226
|
+
}
|
|
7227
|
+
return () => {
|
|
7228
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
7229
|
+
};
|
|
7230
|
+
}, [isDatasetDropdownOpen]);
|
|
6814
7231
|
const propsEndRef = useRef10(null);
|
|
6815
7232
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
6816
7233
|
useEffect13(() => {
|
|
@@ -6856,8 +7273,8 @@ function InSceneCreationForm({
|
|
|
6856
7273
|
const newProp = createNewCustomProperty(customProps);
|
|
6857
7274
|
setCustomProps([...customProps, newProp]);
|
|
6858
7275
|
setTimeout(() => {
|
|
6859
|
-
var
|
|
6860
|
-
(
|
|
7276
|
+
var _a2;
|
|
7277
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
6861
7278
|
}, 100);
|
|
6862
7279
|
};
|
|
6863
7280
|
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
@@ -6890,12 +7307,12 @@ function InSceneCreationForm({
|
|
|
6890
7307
|
onSizeChange == null ? void 0 : onSizeChange(newSize);
|
|
6891
7308
|
};
|
|
6892
7309
|
const handleToggleImageMode = () => {
|
|
6893
|
-
var
|
|
7310
|
+
var _a2, _b;
|
|
6894
7311
|
const newValue = !useImageAsTexture;
|
|
6895
7312
|
setUseImageAsTexture(newValue);
|
|
6896
7313
|
if (newValue) {
|
|
6897
7314
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
6898
|
-
if (firstImageProp && ((_b = (
|
|
7315
|
+
if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
|
|
6899
7316
|
const url = firstImageProp.value[0].value;
|
|
6900
7317
|
setSelectedImageUrl(url);
|
|
6901
7318
|
onImageChange == null ? void 0 : onImageChange(true, url);
|
|
@@ -6929,7 +7346,6 @@ function InSceneCreationForm({
|
|
|
6929
7346
|
useImageAsTexture,
|
|
6930
7347
|
textureImageUrl: useImageAsTexture ? selectedImageUrl : null,
|
|
6931
7348
|
targetDatasetId,
|
|
6932
|
-
// Alvo do Dataset adicionado no onSave
|
|
6933
7349
|
...additionalData
|
|
6934
7350
|
});
|
|
6935
7351
|
};
|
|
@@ -6950,6 +7366,7 @@ function InSceneCreationForm({
|
|
|
6950
7366
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
6951
7367
|
}
|
|
6952
7368
|
};
|
|
7369
|
+
const selectedDatasetName = ((_a = availableDatasets.find((ds) => ds.id === targetDatasetId)) == null ? void 0 : _a.name) || "Selecione um Dataset...";
|
|
6953
7370
|
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
|
|
6954
7371
|
"div",
|
|
6955
7372
|
{
|
|
@@ -7007,15 +7424,27 @@ function InSceneCreationForm({
|
|
|
7007
7424
|
}
|
|
7008
7425
|
},
|
|
7009
7426
|
suggestedType
|
|
7010
|
-
))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), viewType === "view" && availableDatasets.length > 0 && /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Criar Node no Dataset:"), /* @__PURE__ */ React13.createElement(
|
|
7011
|
-
"
|
|
7427
|
+
))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), viewType === "view" && availableDatasets.length > 0 && /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative", ref: datasetDropdownRef }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Criar Node no Dataset:"), /* @__PURE__ */ React13.createElement(
|
|
7428
|
+
"button",
|
|
7429
|
+
{
|
|
7430
|
+
type: "button",
|
|
7431
|
+
onClick: () => setIsDatasetDropdownOpen(!isDatasetDropdownOpen),
|
|
7432
|
+
className: "w-full flex items-center justify-between bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 hover:bg-slate-700/70 transition-colors text-slate-200 text-left"
|
|
7433
|
+
},
|
|
7434
|
+
/* @__PURE__ */ React13.createElement("span", { className: "truncate pr-2" }, selectedDatasetName),
|
|
7435
|
+
/* @__PURE__ */ React13.createElement(FiChevronDown4, { className: `flex-shrink-0 text-slate-400 transition-transform ${isDatasetDropdownOpen ? "rotate-180" : ""}` })
|
|
7436
|
+
), isDatasetDropdownOpen && /* @__PURE__ */ React13.createElement("ul", { className: "custom-scrollbar absolute top-[66px] left-0 z-20 w-full max-h-48 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-xl py-1" }, availableDatasets.map((ds) => /* @__PURE__ */ React13.createElement(
|
|
7437
|
+
"li",
|
|
7012
7438
|
{
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7439
|
+
key: ds.id,
|
|
7440
|
+
onClick: () => {
|
|
7441
|
+
setTargetDatasetId(ds.id);
|
|
7442
|
+
setIsDatasetDropdownOpen(false);
|
|
7443
|
+
},
|
|
7444
|
+
className: `px-3 py-2 text-sm cursor-pointer transition-colors ${targetDatasetId === ds.id ? "bg-indigo-600/40 text-indigo-200 font-medium" : "text-slate-300 hover:bg-white/5"}`
|
|
7016
7445
|
},
|
|
7017
|
-
|
|
7018
|
-
)), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React13.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React13.createElement(
|
|
7446
|
+
ds.name
|
|
7447
|
+
)))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React13.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React13.createElement(
|
|
7019
7448
|
DescriptionDisplay,
|
|
7020
7449
|
{
|
|
7021
7450
|
description,
|
|
@@ -7023,7 +7452,8 @@ function InSceneCreationForm({
|
|
|
7023
7452
|
availableNodes,
|
|
7024
7453
|
availableAncestries,
|
|
7025
7454
|
onMentionClick,
|
|
7026
|
-
onImageClick: handleImageClickFromText
|
|
7455
|
+
onImageClick: handleImageClickFromText,
|
|
7456
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7027
7457
|
}
|
|
7028
7458
|
), /* @__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(
|
|
7029
7459
|
"button",
|
|
@@ -7114,7 +7544,7 @@ function InSceneCreationForm({
|
|
|
7114
7544
|
}
|
|
7115
7545
|
|
|
7116
7546
|
// src/components/InSceneVersionForm.jsx
|
|
7117
|
-
import React14, { useState as
|
|
7547
|
+
import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
|
|
7118
7548
|
import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
|
|
7119
7549
|
function InSceneVersionForm({
|
|
7120
7550
|
onSave,
|
|
@@ -7132,14 +7562,14 @@ function InSceneVersionForm({
|
|
|
7132
7562
|
onMentionClick,
|
|
7133
7563
|
onUploadFile
|
|
7134
7564
|
}) {
|
|
7135
|
-
const [name, setName] =
|
|
7136
|
-
const [size, setSize] =
|
|
7137
|
-
const [description, setDescription] =
|
|
7138
|
-
const [customProps, setCustomProps] =
|
|
7139
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7565
|
+
const [name, setName] = useState15("");
|
|
7566
|
+
const [size, setSize] = useState15("medium");
|
|
7567
|
+
const [description, setDescription] = useState15("");
|
|
7568
|
+
const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
|
|
7569
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
|
|
7140
7570
|
const propsEndRef = useRef11(null);
|
|
7141
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7142
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7571
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
|
|
7572
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
|
|
7143
7573
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
7144
7574
|
useEffect14(() => {
|
|
7145
7575
|
if (!hasImages && useImageAsTexture) {
|
|
@@ -7260,7 +7690,8 @@ function InSceneVersionForm({
|
|
|
7260
7690
|
availableNodes,
|
|
7261
7691
|
availableAncestries,
|
|
7262
7692
|
onMentionClick,
|
|
7263
|
-
onImageClick: handleImageClickFromText
|
|
7693
|
+
onImageClick: handleImageClickFromText,
|
|
7694
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7264
7695
|
}
|
|
7265
7696
|
), /* @__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(
|
|
7266
7697
|
"button",
|
|
@@ -7332,7 +7763,7 @@ function InSceneVersionForm({
|
|
|
7332
7763
|
}
|
|
7333
7764
|
|
|
7334
7765
|
// src/components/NodeDetailsPanel.jsx
|
|
7335
|
-
import React15, { useState as
|
|
7766
|
+
import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
|
|
7336
7767
|
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";
|
|
7337
7768
|
function NodeDetailsPanel({
|
|
7338
7769
|
node,
|
|
@@ -7353,29 +7784,37 @@ function NodeDetailsPanel({
|
|
|
7353
7784
|
onUploadFile,
|
|
7354
7785
|
userRole,
|
|
7355
7786
|
currentDatasetName
|
|
7356
|
-
// Prop currentDatasetName adicionada
|
|
7357
7787
|
}) {
|
|
7358
|
-
const [name, setName] =
|
|
7359
|
-
const [types, setTypes] =
|
|
7360
|
-
const [typeInput, setTypeInput] =
|
|
7361
|
-
const [color, setColor] =
|
|
7362
|
-
const [size, setSize] =
|
|
7363
|
-
const [description, setDescription] =
|
|
7364
|
-
const [intensity, setIntensity] =
|
|
7365
|
-
const [customProps, setCustomProps] =
|
|
7366
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
7367
|
-
const [filteredTypes, setFilteredTypes] =
|
|
7368
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7369
|
-
const [isReadMode, setIsReadMode] =
|
|
7370
|
-
const [existingSections, setExistingSections] =
|
|
7371
|
-
const [isSaving, setIsSaving] =
|
|
7372
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
7373
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7788
|
+
const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
|
|
7789
|
+
const [types, setTypes] = useState16([]);
|
|
7790
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7791
|
+
const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
7792
|
+
const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
|
|
7793
|
+
const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
|
|
7794
|
+
const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
7795
|
+
const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
|
|
7796
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
|
|
7797
|
+
const [filteredTypes, setFilteredTypes] = useState16([]);
|
|
7798
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7799
|
+
const [isReadMode, setIsReadMode] = useState16(false);
|
|
7800
|
+
const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
|
|
7801
|
+
const [isSaving, setIsSaving] = useState16(false);
|
|
7802
|
+
const [isLinkCopied, setIsLinkCopied] = useState16(false);
|
|
7803
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
|
|
7374
7804
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7375
7805
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7376
7806
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7377
7807
|
});
|
|
7378
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7808
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7809
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7810
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7811
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
7812
|
+
minWidth: 320,
|
|
7813
|
+
maxWidth: maxPanelW
|
|
7814
|
+
});
|
|
7815
|
+
useEffect15(() => {
|
|
7816
|
+
setWidth(isReadMode ? 700 : 440);
|
|
7817
|
+
}, [isReadMode, setWidth]);
|
|
7379
7818
|
const prevNodeIdRef = useRef12(null);
|
|
7380
7819
|
const propsEndRef = useRef12(null);
|
|
7381
7820
|
const canEdit = userRole !== "viewer";
|
|
@@ -7528,6 +7967,11 @@ function NodeDetailsPanel({
|
|
|
7528
7967
|
textureImageUrl: url
|
|
7529
7968
|
});
|
|
7530
7969
|
};
|
|
7970
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
7971
|
+
setDescription(newDescription);
|
|
7972
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
7973
|
+
triggerAutoSave({ description: newDescription });
|
|
7974
|
+
};
|
|
7531
7975
|
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
7532
7976
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
7533
7977
|
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
@@ -7583,10 +8027,8 @@ function NodeDetailsPanel({
|
|
|
7583
8027
|
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
7584
8028
|
"div",
|
|
7585
8029
|
{
|
|
7586
|
-
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
|
|
7587
|
-
|
|
7588
|
-
`,
|
|
7589
|
-
style: { top: 16, right: 16, zIndex: 1100 },
|
|
8030
|
+
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"}`,
|
|
8031
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
7590
8032
|
onPointerDown: swallow,
|
|
7591
8033
|
onPointerMove: swallow,
|
|
7592
8034
|
onPointerUp: swallow,
|
|
@@ -7595,6 +8037,17 @@ function NodeDetailsPanel({
|
|
|
7595
8037
|
onContextMenu: swallow,
|
|
7596
8038
|
onDoubleClick: swallow
|
|
7597
8039
|
},
|
|
8040
|
+
/* @__PURE__ */ React15.createElement(
|
|
8041
|
+
"div",
|
|
8042
|
+
{
|
|
8043
|
+
onPointerDown: (e) => {
|
|
8044
|
+
e.stopPropagation();
|
|
8045
|
+
handleResize(e);
|
|
8046
|
+
},
|
|
8047
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
8048
|
+
title: "Arraste para redimensionar"
|
|
8049
|
+
}
|
|
8050
|
+
),
|
|
7598
8051
|
isReadMode ? /* @__PURE__ */ React15.createElement(
|
|
7599
8052
|
DescriptionReadModePanel,
|
|
7600
8053
|
{
|
|
@@ -7613,7 +8066,8 @@ function NodeDetailsPanel({
|
|
|
7613
8066
|
availableAncestries,
|
|
7614
8067
|
onOpenReference,
|
|
7615
8068
|
onMentionClick,
|
|
7616
|
-
onImageClick: handleImageClickFromText
|
|
8069
|
+
onImageClick: handleImageClickFromText,
|
|
8070
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7617
8071
|
}
|
|
7618
8072
|
) : /* @__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(
|
|
7619
8073
|
"button",
|
|
@@ -7681,7 +8135,8 @@ function NodeDetailsPanel({
|
|
|
7681
8135
|
availableAncestries,
|
|
7682
8136
|
onOpenReference,
|
|
7683
8137
|
onMentionClick,
|
|
7684
|
-
onImageClick: handleImageClickFromText
|
|
8138
|
+
onImageClick: handleImageClickFromText,
|
|
8139
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7685
8140
|
}
|
|
7686
8141
|
), /* @__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(
|
|
7687
8142
|
"button",
|
|
@@ -7764,7 +8219,7 @@ function NodeDetailsPanel({
|
|
|
7764
8219
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
7765
8220
|
readOnly: !canEdit
|
|
7766
8221
|
}
|
|
7767
|
-
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React15.createElement("div", { className: "pt-
|
|
8222
|
+
)), /* @__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(
|
|
7768
8223
|
"button",
|
|
7769
8224
|
{
|
|
7770
8225
|
onClick: () => handleSave(false),
|
|
@@ -7796,18 +8251,18 @@ function NodeDetailsPanel({
|
|
|
7796
8251
|
}
|
|
7797
8252
|
|
|
7798
8253
|
// src/components/MultiNodeContextMenu.jsx
|
|
7799
|
-
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as
|
|
8254
|
+
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
|
|
7800
8255
|
function MultiNodeContextMenu({
|
|
7801
8256
|
data,
|
|
7802
8257
|
userRole,
|
|
7803
|
-
// 2. Recebendo a role do usuário nas props
|
|
7804
8258
|
onClose,
|
|
7805
8259
|
onDismissNodes,
|
|
7806
8260
|
onDismissOtherNodes,
|
|
7807
8261
|
onDeleteNodes
|
|
7808
8262
|
}) {
|
|
7809
8263
|
const menuRef = useRef13(null);
|
|
7810
|
-
const [menuPos, setMenuPos] =
|
|
8264
|
+
const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
|
|
8265
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState17(false);
|
|
7811
8266
|
const ability = defineAbilityFor(userRole);
|
|
7812
8267
|
const canDelete = ability.can("delete", "Node");
|
|
7813
8268
|
useLayoutEffect3(() => {
|
|
@@ -7824,7 +8279,9 @@ function MultiNodeContextMenu({
|
|
|
7824
8279
|
setMenuPos({ left, top });
|
|
7825
8280
|
}, [data]);
|
|
7826
8281
|
useEffect16(() => {
|
|
7827
|
-
if (
|
|
8282
|
+
if (data.visible) {
|
|
8283
|
+
setIsConfirmingDelete(false);
|
|
8284
|
+
}
|
|
7828
8285
|
const handleClickOutside = (e) => {
|
|
7829
8286
|
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
7830
8287
|
};
|
|
@@ -7851,12 +8308,26 @@ function MultiNodeContextMenu({
|
|
|
7851
8308
|
onDoubleClick: swallow
|
|
7852
8309
|
},
|
|
7853
8310
|
/* @__PURE__ */ React16.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
7854
|
-
/* @__PURE__ */ React16.createElement("div", { className: "p-1.5" },
|
|
8311
|
+
/* @__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(
|
|
8312
|
+
"button",
|
|
8313
|
+
{
|
|
8314
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
8315
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8316
|
+
},
|
|
8317
|
+
"Cancelar"
|
|
8318
|
+
), /* @__PURE__ */ React16.createElement(
|
|
8319
|
+
"button",
|
|
8320
|
+
{
|
|
8321
|
+
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8322
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8323
|
+
},
|
|
8324
|
+
"Excluir"
|
|
8325
|
+
))) : /* @__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, ")"))))))
|
|
7855
8326
|
);
|
|
7856
8327
|
}
|
|
7857
8328
|
|
|
7858
8329
|
// src/components/RelationshipDetailsPanel.jsx
|
|
7859
|
-
import React17, { useState as
|
|
8330
|
+
import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
|
|
7860
8331
|
import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
7861
8332
|
function RelationshipDetailsPanel({
|
|
7862
8333
|
link,
|
|
@@ -7870,15 +8341,14 @@ function RelationshipDetailsPanel({
|
|
|
7870
8341
|
onMentionClick,
|
|
7871
8342
|
onUploadFile,
|
|
7872
8343
|
userRole
|
|
7873
|
-
// Recebendo userRole via props
|
|
7874
8344
|
}) {
|
|
7875
|
-
const [name, setName] =
|
|
7876
|
-
const [description, setDescription] =
|
|
7877
|
-
const [customProps, setCustomProps] =
|
|
7878
|
-
const [existingSections, setExistingSections] =
|
|
7879
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7880
|
-
const [isSaving, setIsSaving] =
|
|
7881
|
-
const [isReadMode, setIsReadMode] =
|
|
8345
|
+
const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
|
|
8346
|
+
const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
|
|
8347
|
+
const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
|
|
8348
|
+
const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
|
|
8349
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
|
|
8350
|
+
const [isSaving, setIsSaving] = useState18(false);
|
|
8351
|
+
const [isReadMode, setIsReadMode] = useState18(false);
|
|
7882
8352
|
const propsEndRef = useRef14(null);
|
|
7883
8353
|
const canEdit = useMemo9(() => {
|
|
7884
8354
|
const ability = defineAbilityFor(userRole);
|
|
@@ -7933,6 +8403,12 @@ function RelationshipDetailsPanel({
|
|
|
7933
8403
|
const triggerAutoSave = (overrides = {}) => {
|
|
7934
8404
|
if (canEdit) handleSave(true, overrides);
|
|
7935
8405
|
};
|
|
8406
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8407
|
+
if (!canEdit) return;
|
|
8408
|
+
setDescription(newDescription);
|
|
8409
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8410
|
+
triggerAutoSave({ description: newDescription });
|
|
8411
|
+
};
|
|
7936
8412
|
const handleRemoveProp = (i) => {
|
|
7937
8413
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
7938
8414
|
setCustomProps(newProps);
|
|
@@ -7986,7 +8462,8 @@ function RelationshipDetailsPanel({
|
|
|
7986
8462
|
availableAncestries,
|
|
7987
8463
|
onOpenReference,
|
|
7988
8464
|
onMentionClick,
|
|
7989
|
-
onImageClick: handleImageClickFromText
|
|
8465
|
+
onImageClick: handleImageClickFromText,
|
|
8466
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7990
8467
|
}
|
|
7991
8468
|
) : /* @__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(
|
|
7992
8469
|
"input",
|
|
@@ -8009,7 +8486,8 @@ function RelationshipDetailsPanel({
|
|
|
8009
8486
|
availableAncestries,
|
|
8010
8487
|
onOpenReference,
|
|
8011
8488
|
onMentionClick,
|
|
8012
|
-
onImageClick: handleImageClickFromText
|
|
8489
|
+
onImageClick: handleImageClickFromText,
|
|
8490
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
8013
8491
|
}
|
|
8014
8492
|
), /* @__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(
|
|
8015
8493
|
"button",
|
|
@@ -8081,11 +8559,10 @@ function RelationshipDetailsPanel({
|
|
|
8081
8559
|
}
|
|
8082
8560
|
|
|
8083
8561
|
// src/components/RelationshipContextMenu.jsx
|
|
8084
|
-
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as
|
|
8562
|
+
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8085
8563
|
function RelationshipContextMenu({
|
|
8086
8564
|
data,
|
|
8087
8565
|
userRole,
|
|
8088
|
-
// Recebemos a role do usuário para verificar permissões
|
|
8089
8566
|
onRelinkSource,
|
|
8090
8567
|
onRelinkTarget,
|
|
8091
8568
|
onOpenDetails,
|
|
@@ -8093,7 +8570,8 @@ function RelationshipContextMenu({
|
|
|
8093
8570
|
onClose
|
|
8094
8571
|
}) {
|
|
8095
8572
|
const menuRef = useRef15(null);
|
|
8096
|
-
const [menuPos, setMenuPos] =
|
|
8573
|
+
const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
|
|
8574
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState19(false);
|
|
8097
8575
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8098
8576
|
const sourceName = useMemo10(
|
|
8099
8577
|
() => {
|
|
@@ -8123,7 +8601,9 @@ function RelationshipContextMenu({
|
|
|
8123
8601
|
setMenuPos({ left, top });
|
|
8124
8602
|
}, [data]);
|
|
8125
8603
|
useEffect18(() => {
|
|
8126
|
-
if (
|
|
8604
|
+
if (data.visible) {
|
|
8605
|
+
setIsConfirmingDelete(false);
|
|
8606
|
+
}
|
|
8127
8607
|
const handleClickOutside = (e) => {
|
|
8128
8608
|
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
8129
8609
|
};
|
|
@@ -8151,7 +8631,21 @@ function RelationshipContextMenu({
|
|
|
8151
8631
|
onDoubleClick: swallow
|
|
8152
8632
|
},
|
|
8153
8633
|
/* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
8154
|
-
/* @__PURE__ */ React18.createElement("div", { className: "p-1.5" }, /* @__PURE__ */ React18.createElement("div", { className: "flex
|
|
8634
|
+
/* @__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(
|
|
8635
|
+
"button",
|
|
8636
|
+
{
|
|
8637
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
8638
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8639
|
+
},
|
|
8640
|
+
"Cancelar"
|
|
8641
|
+
), /* @__PURE__ */ React18.createElement(
|
|
8642
|
+
"button",
|
|
8643
|
+
{
|
|
8644
|
+
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8645
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8646
|
+
},
|
|
8647
|
+
"Excluir"
|
|
8648
|
+
))) : /* @__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(
|
|
8155
8649
|
"button",
|
|
8156
8650
|
{
|
|
8157
8651
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
@@ -8230,7 +8724,7 @@ function RelationshipContextMenu({
|
|
|
8230
8724
|
), canDelete && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React18.createElement(
|
|
8231
8725
|
"button",
|
|
8232
8726
|
{
|
|
8233
|
-
onClick: () =>
|
|
8727
|
+
onClick: () => setIsConfirmingDelete(true),
|
|
8234
8728
|
className: dangerButtonClass,
|
|
8235
8729
|
title: "Excluir esta conex\xE3o"
|
|
8236
8730
|
},
|
|
@@ -8254,7 +8748,7 @@ function RelationshipContextMenu({
|
|
|
8254
8748
|
/* @__PURE__ */ React18.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
8255
8749
|
),
|
|
8256
8750
|
/* @__PURE__ */ React18.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
8257
|
-
))))
|
|
8751
|
+
)))))
|
|
8258
8752
|
);
|
|
8259
8753
|
}
|
|
8260
8754
|
|
|
@@ -8295,7 +8789,7 @@ function LoadingScreen() {
|
|
|
8295
8789
|
}
|
|
8296
8790
|
|
|
8297
8791
|
// src/components/ImportParentFileModal.jsx
|
|
8298
|
-
import React20, { useEffect as useEffect19, useState as
|
|
8792
|
+
import React20, { useEffect as useEffect19, useState as useState20 } from "react";
|
|
8299
8793
|
function ImportParentFileModal({
|
|
8300
8794
|
isOpen,
|
|
8301
8795
|
onClose,
|
|
@@ -8306,11 +8800,11 @@ function ImportParentFileModal({
|
|
|
8306
8800
|
onFetchAvailableFiles,
|
|
8307
8801
|
currentViewName
|
|
8308
8802
|
}) {
|
|
8309
|
-
const [activeTab, setActiveTab] =
|
|
8310
|
-
const [availableDbs, setAvailableDbs] =
|
|
8311
|
-
const [availableViews, setAvailableViews] =
|
|
8312
|
-
const [selectedItem, setSelectedItem] =
|
|
8313
|
-
const [isLoading, setIsLoading] =
|
|
8803
|
+
const [activeTab, setActiveTab] = useState20("databases");
|
|
8804
|
+
const [availableDbs, setAvailableDbs] = useState20([]);
|
|
8805
|
+
const [availableViews, setAvailableViews] = useState20([]);
|
|
8806
|
+
const [selectedItem, setSelectedItem] = useState20(null);
|
|
8807
|
+
const [isLoading, setIsLoading] = useState20(false);
|
|
8314
8808
|
useEffect19(() => {
|
|
8315
8809
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8316
8810
|
const fetchData = async () => {
|
|
@@ -8456,7 +8950,7 @@ function ImportParentFileModal({
|
|
|
8456
8950
|
}
|
|
8457
8951
|
|
|
8458
8952
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
8459
|
-
import React21, { useState as
|
|
8953
|
+
import React21, { useState as useState21 } from "react";
|
|
8460
8954
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
8461
8955
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
8462
8956
|
var _a, _b, _c, _d;
|
|
@@ -8466,7 +8960,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8466
8960
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
8467
8961
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
8468
8962
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
8469
|
-
const [isReadMode, setIsReadMode] =
|
|
8963
|
+
const [isReadMode, setIsReadMode] = useState21(false);
|
|
8470
8964
|
const swallow = (e) => e.stopPropagation();
|
|
8471
8965
|
const handleImageClickFromText = (url, name) => {
|
|
8472
8966
|
if (onOpenImageViewer) {
|
|
@@ -8532,14 +9026,14 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8532
9026
|
}
|
|
8533
9027
|
|
|
8534
9028
|
// src/components/AncestryBoard.jsx
|
|
8535
|
-
import React22, { useState as
|
|
9029
|
+
import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
|
|
8536
9030
|
import {
|
|
8537
9031
|
FiSearch as FiSearch4,
|
|
8538
9032
|
FiLayers as FiLayers6,
|
|
8539
9033
|
FiCornerUpRight as FiCornerUpRight4,
|
|
8540
9034
|
FiPlay,
|
|
8541
9035
|
FiPlus as FiPlus7,
|
|
8542
|
-
FiTrash2 as
|
|
9036
|
+
FiTrash2 as FiTrash23,
|
|
8543
9037
|
FiArrowLeft as FiArrowLeft3,
|
|
8544
9038
|
FiArrowRight,
|
|
8545
9039
|
FiCheckCircle,
|
|
@@ -8676,7 +9170,7 @@ var GroupItem = ({
|
|
|
8676
9170
|
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
8677
9171
|
title: "Remover Grupo"
|
|
8678
9172
|
},
|
|
8679
|
-
/* @__PURE__ */ React22.createElement(
|
|
9173
|
+
/* @__PURE__ */ React22.createElement(FiTrash23, { size: 14 })
|
|
8680
9174
|
)))), group.children && group.children.length > 0 && /* @__PURE__ */ React22.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React22.createElement(
|
|
8681
9175
|
GroupItem,
|
|
8682
9176
|
{
|
|
@@ -8709,11 +9203,11 @@ function AncestryBoard({
|
|
|
8709
9203
|
userRole
|
|
8710
9204
|
// [NOVO] Recebe a role do usuário
|
|
8711
9205
|
}) {
|
|
8712
|
-
const [searchTerm, setSearchTerm] =
|
|
8713
|
-
const [groups, setGroups] =
|
|
8714
|
-
const [isLoaded, setIsLoaded] =
|
|
8715
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
8716
|
-
const [saveStatus, setSaveStatus] =
|
|
9206
|
+
const [searchTerm, setSearchTerm] = useState22("");
|
|
9207
|
+
const [groups, setGroups] = useState22([]);
|
|
9208
|
+
const [isLoaded, setIsLoaded] = useState22(false);
|
|
9209
|
+
const [pickingGroupId, setPickingGroupId] = useState22(null);
|
|
9210
|
+
const [saveStatus, setSaveStatus] = useState22("idle");
|
|
8717
9211
|
const canEdit = useMemo11(() => {
|
|
8718
9212
|
return userRole !== "viewer";
|
|
8719
9213
|
}, [userRole]);
|
|
@@ -9163,37 +9657,37 @@ function XViewScene({
|
|
|
9163
9657
|
const sceneDataRef = useRef17(null);
|
|
9164
9658
|
const parentDataRef = useRef17(null);
|
|
9165
9659
|
const ancestryDataRef = useRef17(null);
|
|
9166
|
-
const [isLoading, setIsLoading] =
|
|
9167
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9168
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9169
|
-
const [isInitialized, setIsInitialized] =
|
|
9170
|
-
const [sceneVersion, setSceneVersion] =
|
|
9171
|
-
const [contextMenu, setContextMenu] =
|
|
9172
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9173
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9174
|
-
const [creationMode, setCreationMode] =
|
|
9175
|
-
const [versionMode, setVersionMode] =
|
|
9176
|
-
const [hasFocusedInitial, setHasFocusedInitial] =
|
|
9177
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] =
|
|
9178
|
-
const [ancestryMode, setAncestryMode] =
|
|
9179
|
-
const [readingMode, setReadingMode] =
|
|
9660
|
+
const [isLoading, setIsLoading] = useState23(true);
|
|
9661
|
+
const [permissionStatus, setPermissionStatus] = useState23("loading");
|
|
9662
|
+
const [userPermissionRole, setUserPermissionRole] = useState23(null);
|
|
9663
|
+
const [isInitialized, setIsInitialized] = useState23(false);
|
|
9664
|
+
const [sceneVersion, setSceneVersion] = useState23(0);
|
|
9665
|
+
const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
|
|
9666
|
+
const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
9667
|
+
const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
|
|
9668
|
+
const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9669
|
+
const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9670
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
|
|
9671
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
|
|
9672
|
+
const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
9673
|
+
const [readingMode, setReadingMode] = useState23({
|
|
9180
9674
|
isActive: false,
|
|
9181
9675
|
ancestry: null,
|
|
9182
9676
|
branchStack: [],
|
|
9183
9677
|
autoAbstraction: false
|
|
9184
9678
|
});
|
|
9185
|
-
const [formPosition, setFormPosition] =
|
|
9186
|
-
const [detailsNode, setDetailsNode] =
|
|
9187
|
-
const [detailsLink, setDetailsLink] =
|
|
9188
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9189
|
-
const [imageViewer, setImageViewer] =
|
|
9190
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9191
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9192
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9193
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9194
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9195
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9196
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9679
|
+
const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
|
|
9680
|
+
const [detailsNode, setDetailsNode] = useState23(null);
|
|
9681
|
+
const [detailsLink, setDetailsLink] = useState23(null);
|
|
9682
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
|
|
9683
|
+
const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
|
|
9684
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
|
|
9685
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
|
|
9686
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState23("");
|
|
9687
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
|
|
9688
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
|
|
9689
|
+
const [ancestryBoardData, setAncestryBoardData] = useState23([]);
|
|
9690
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
|
|
9197
9691
|
const mountRef = useRef17(null);
|
|
9198
9692
|
const tooltipRef = useRef17(null);
|
|
9199
9693
|
const formRef = useRef17(null);
|
|
@@ -9236,6 +9730,12 @@ function XViewScene({
|
|
|
9236
9730
|
lastDescriptionLength: 0,
|
|
9237
9731
|
highlightedNodeId: null
|
|
9238
9732
|
});
|
|
9733
|
+
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9734
|
+
const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
|
|
9735
|
+
initialWidth: 700,
|
|
9736
|
+
minWidth: 320,
|
|
9737
|
+
maxWidth: maxReadPanelW
|
|
9738
|
+
});
|
|
9239
9739
|
useEffect21(() => {
|
|
9240
9740
|
stateRef.current.ancestry = ancestryMode;
|
|
9241
9741
|
}, [ancestryMode]);
|
|
@@ -9260,10 +9760,10 @@ function XViewScene({
|
|
|
9260
9760
|
}
|
|
9261
9761
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
9262
9762
|
}, [isInitialized, sceneVersion]);
|
|
9263
|
-
const handleNavigateBack =
|
|
9763
|
+
const handleNavigateBack = useCallback4(() => {
|
|
9264
9764
|
router.push("/dashboard/scenes");
|
|
9265
9765
|
}, [router]);
|
|
9266
|
-
const handleConfirmImport =
|
|
9766
|
+
const handleConfirmImport = useCallback4(
|
|
9267
9767
|
async (importPayload) => {
|
|
9268
9768
|
var _a2, _b2;
|
|
9269
9769
|
let files = [];
|
|
@@ -9311,7 +9811,6 @@ function XViewScene({
|
|
|
9311
9811
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
9312
9812
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
9313
9813
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
9314
|
-
// <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
|
|
9315
9814
|
);
|
|
9316
9815
|
const processedAncestries = viewSpecificAncestries.map((anc) => ({
|
|
9317
9816
|
...anc,
|
|
@@ -9362,7 +9861,7 @@ function XViewScene({
|
|
|
9362
9861
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
9363
9862
|
setImageViewer({ visible: true, images, startIndex });
|
|
9364
9863
|
};
|
|
9365
|
-
const tweenToTarget =
|
|
9864
|
+
const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
|
|
9366
9865
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
9367
9866
|
if (!camera || !controls || !tweenGroup) return;
|
|
9368
9867
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -9385,7 +9884,7 @@ function XViewScene({
|
|
|
9385
9884
|
if (!t || typeof t.closest !== "function") return false;
|
|
9386
9885
|
return !!t.closest(".ui-overlay");
|
|
9387
9886
|
};
|
|
9388
|
-
const buildFullAncestryTree =
|
|
9887
|
+
const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
|
|
9389
9888
|
if (!idTree) return null;
|
|
9390
9889
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
9391
9890
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -9411,14 +9910,10 @@ function XViewScene({
|
|
|
9411
9910
|
return {
|
|
9412
9911
|
...branch,
|
|
9413
9912
|
name: linkedAncestry.name,
|
|
9414
|
-
// Sobrescreve nome para exibição
|
|
9415
9913
|
description: linkedAncestry.description,
|
|
9416
|
-
// Sobrescreve descrição
|
|
9417
9914
|
description_sections: linkedAncestry.description_sections,
|
|
9418
9915
|
tree: graftedTree,
|
|
9419
|
-
// ENXERTA A ÁRVORE AQUI
|
|
9420
9916
|
isLinked: true
|
|
9421
|
-
// Flag útil
|
|
9422
9917
|
};
|
|
9423
9918
|
}
|
|
9424
9919
|
}
|
|
@@ -9465,7 +9960,7 @@ function XViewScene({
|
|
|
9465
9960
|
}
|
|
9466
9961
|
return recursiveBuild(idTree);
|
|
9467
9962
|
}, []);
|
|
9468
|
-
const handleActivateTimeline =
|
|
9963
|
+
const handleActivateTimeline = useCallback4(() => {
|
|
9469
9964
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9470
9965
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
9471
9966
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -9618,7 +10113,7 @@ function XViewScene({
|
|
|
9618
10113
|
}
|
|
9619
10114
|
});
|
|
9620
10115
|
}, []);
|
|
9621
|
-
const handleVersionTimeline =
|
|
10116
|
+
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
9622
10117
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9623
10118
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
9624
10119
|
versionMeshes.forEach((mesh) => {
|
|
@@ -9811,16 +10306,14 @@ function XViewScene({
|
|
|
9811
10306
|
isInitialized,
|
|
9812
10307
|
permissionStatus,
|
|
9813
10308
|
focusNodeId,
|
|
9814
|
-
// <-- MANTIDO
|
|
9815
10309
|
focusAncestryId
|
|
9816
|
-
// <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
|
|
9817
10310
|
]);
|
|
9818
|
-
const isNodeInView =
|
|
10311
|
+
const isNodeInView = useCallback4((id) => {
|
|
9819
10312
|
const key = String(id);
|
|
9820
10313
|
const objs = stateRef.current.nodeObjects || {};
|
|
9821
10314
|
return !!objs[key];
|
|
9822
10315
|
}, []);
|
|
9823
|
-
const addOrUpdateNodeMesh =
|
|
10316
|
+
const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
|
|
9824
10317
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
9825
10318
|
const nodeId = String(nodeData.id);
|
|
9826
10319
|
if (nodeObjects[nodeId]) {
|
|
@@ -10469,7 +10962,7 @@ function XViewScene({
|
|
|
10469
10962
|
}
|
|
10470
10963
|
};
|
|
10471
10964
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
10472
|
-
const handleGhostNodeImageChange =
|
|
10965
|
+
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
10473
10966
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10474
10967
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
10475
10968
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -10511,7 +11004,7 @@ function XViewScene({
|
|
|
10511
11004
|
aura: newGhostNode.getObjectByName("aura")
|
|
10512
11005
|
};
|
|
10513
11006
|
}, []);
|
|
10514
|
-
const handleGhostNodeIntensityChange =
|
|
11007
|
+
const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
|
|
10515
11008
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10516
11009
|
if (!ghostNode) return;
|
|
10517
11010
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10532,7 +11025,7 @@ function XViewScene({
|
|
|
10532
11025
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
10533
11026
|
}
|
|
10534
11027
|
}, []);
|
|
10535
|
-
const handleDetailNodeIntensityChange =
|
|
11028
|
+
const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
|
|
10536
11029
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10537
11030
|
if (!mesh) return;
|
|
10538
11031
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10678,7 +11171,7 @@ function XViewScene({
|
|
|
10678
11171
|
mountRef.current.style.cursor = "default";
|
|
10679
11172
|
}
|
|
10680
11173
|
};
|
|
10681
|
-
const handleAncestryTreeUpdate =
|
|
11174
|
+
const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
|
|
10682
11175
|
setAncestryMode((prev) => {
|
|
10683
11176
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
10684
11177
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -10748,7 +11241,7 @@ function XViewScene({
|
|
|
10748
11241
|
const handleStartVersioning = (nodeData) => {
|
|
10749
11242
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
10750
11243
|
};
|
|
10751
|
-
const handleClearAncestryVisuals =
|
|
11244
|
+
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
10752
11245
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
10753
11246
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
10754
11247
|
if (renderIndex !== -1) {
|
|
@@ -10762,7 +11255,7 @@ function XViewScene({
|
|
|
10762
11255
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10763
11256
|
}
|
|
10764
11257
|
}, []);
|
|
10765
|
-
const handleRenderAncestry =
|
|
11258
|
+
const handleRenderAncestry = useCallback4(
|
|
10766
11259
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
10767
11260
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10768
11261
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11178,7 +11671,7 @@ function XViewScene({
|
|
|
11178
11671
|
},
|
|
11179
11672
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
11180
11673
|
);
|
|
11181
|
-
const handleRenderAbstractionTree =
|
|
11674
|
+
const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
|
|
11182
11675
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11183
11676
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
11184
11677
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -11239,7 +11732,7 @@ function XViewScene({
|
|
|
11239
11732
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11240
11733
|
tweenToTarget(rootTargetPos, 0.7);
|
|
11241
11734
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
11242
|
-
const handleReadModeBranchNav =
|
|
11735
|
+
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
11243
11736
|
const { ancestry, branchStack } = readingMode;
|
|
11244
11737
|
if (!ancestry || !ancestry.tree) return;
|
|
11245
11738
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -11277,9 +11770,7 @@ function XViewScene({
|
|
|
11277
11770
|
description_sections: branchToOpen.description_sections,
|
|
11278
11771
|
tree: branchToOpen.tree,
|
|
11279
11772
|
_originNodeId: nodeId,
|
|
11280
|
-
// <--- ID do node pai (link visual)
|
|
11281
11773
|
_branchDirection: direction
|
|
11282
|
-
// <--- Direção para cálculo de posição
|
|
11283
11774
|
};
|
|
11284
11775
|
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
11285
11776
|
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
@@ -11335,7 +11826,6 @@ function XViewScene({
|
|
|
11335
11826
|
const parentAncestryObj = {
|
|
11336
11827
|
...targetAncestryInfo,
|
|
11337
11828
|
tree: targetTreeToRender,
|
|
11338
|
-
// Re-injeta a origem se o pai também for uma branch aninhada
|
|
11339
11829
|
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
11340
11830
|
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
11341
11831
|
};
|
|
@@ -11383,7 +11873,7 @@ function XViewScene({
|
|
|
11383
11873
|
}));
|
|
11384
11874
|
}
|
|
11385
11875
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
11386
|
-
const handleReadModeHighlight =
|
|
11876
|
+
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
11387
11877
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
11388
11878
|
stateRef.current.highlightedNodeId = nodeId;
|
|
11389
11879
|
}
|
|
@@ -11395,7 +11885,6 @@ function XViewScene({
|
|
|
11395
11885
|
readingMode.ancestry.tree,
|
|
11396
11886
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
11397
11887
|
ancestryDataRef.current
|
|
11398
|
-
// <--- Adicionar
|
|
11399
11888
|
);
|
|
11400
11889
|
const findNodeInTree = (tree, targetId) => {
|
|
11401
11890
|
if (!tree) return null;
|
|
@@ -11449,7 +11938,6 @@ function XViewScene({
|
|
|
11449
11938
|
description_sections: ancestry.description_sections,
|
|
11450
11939
|
direction: null,
|
|
11451
11940
|
customProperties: rootProps
|
|
11452
|
-
// <--- ADICIONADO
|
|
11453
11941
|
};
|
|
11454
11942
|
}
|
|
11455
11943
|
const fullTree = buildFullAncestryTree(
|
|
@@ -11478,7 +11966,6 @@ function XViewScene({
|
|
|
11478
11966
|
description_sections: currentMeta.description_sections,
|
|
11479
11967
|
direction: currentDirection,
|
|
11480
11968
|
customProperties: branchProps
|
|
11481
|
-
// <--- ADICIONADO
|
|
11482
11969
|
};
|
|
11483
11970
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11484
11971
|
const readModeAbstractionTree = useMemo12(() => {
|
|
@@ -11493,7 +11980,7 @@ function XViewScene({
|
|
|
11493
11980
|
allAncestries
|
|
11494
11981
|
);
|
|
11495
11982
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
11496
|
-
const handleStartReadingAncestry =
|
|
11983
|
+
const handleStartReadingAncestry = useCallback4(
|
|
11497
11984
|
async (ancestryObject) => {
|
|
11498
11985
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11499
11986
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11514,7 +12001,6 @@ function XViewScene({
|
|
|
11514
12001
|
ancestry: ancestryObject,
|
|
11515
12002
|
branchStack: [],
|
|
11516
12003
|
autoAbstraction: shouldAutoRenderAbstraction
|
|
11517
|
-
// <--- FLAG ENVIADA PARA A UI
|
|
11518
12004
|
});
|
|
11519
12005
|
if (shouldAutoRenderAbstraction) {
|
|
11520
12006
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
@@ -11528,9 +12014,8 @@ function XViewScene({
|
|
|
11528
12014
|
}
|
|
11529
12015
|
},
|
|
11530
12016
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
11531
|
-
// <--- DEPENDÊNCIA ADICIONADA
|
|
11532
12017
|
);
|
|
11533
|
-
const handleReadModeSectionChange =
|
|
12018
|
+
const handleReadModeSectionChange = useCallback4((activeSectionId) => {
|
|
11534
12019
|
const { ancestry, branchStack } = readingMode;
|
|
11535
12020
|
if (!ancestry || !readingMode.isActive) return;
|
|
11536
12021
|
let targetObj = ancestry;
|
|
@@ -11599,10 +12084,10 @@ function XViewScene({
|
|
|
11599
12084
|
}, 0);
|
|
11600
12085
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11601
12086
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11602
|
-
const handleCloseReadMode =
|
|
12087
|
+
const handleCloseReadMode = useCallback4(() => {
|
|
11603
12088
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
11604
12089
|
}, []);
|
|
11605
|
-
const handleAncestrySectionChange =
|
|
12090
|
+
const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
11606
12091
|
var _a2, _b2;
|
|
11607
12092
|
const currentMode = stateRef.current.ancestry;
|
|
11608
12093
|
let targetObj = ancestryOverride;
|
|
@@ -11654,7 +12139,7 @@ function XViewScene({
|
|
|
11654
12139
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
11655
12140
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11656
12141
|
}, [handleRenderAncestry]);
|
|
11657
|
-
const handleEditAncestry =
|
|
12142
|
+
const handleEditAncestry = useCallback4(
|
|
11658
12143
|
async (ancestryObject) => {
|
|
11659
12144
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11660
12145
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11677,10 +12162,8 @@ function XViewScene({
|
|
|
11677
12162
|
...ancestryObject,
|
|
11678
12163
|
tree: fullTree,
|
|
11679
12164
|
abstraction_tree: fullAbstractionTree,
|
|
11680
|
-
// NOVO
|
|
11681
12165
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11682
12166
|
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11683
|
-
// NOVO
|
|
11684
12167
|
isEditMode: true,
|
|
11685
12168
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11686
12169
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
@@ -11688,7 +12171,6 @@ function XViewScene({
|
|
|
11688
12171
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11689
12172
|
isAddingNodes: false,
|
|
11690
12173
|
isAddingAbstractionNodes: false
|
|
11691
|
-
// NOVO
|
|
11692
12174
|
});
|
|
11693
12175
|
},
|
|
11694
12176
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11696,7 +12178,7 @@ function XViewScene({
|
|
|
11696
12178
|
const handleSelectAncestryParent = (nodeId) => {
|
|
11697
12179
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
11698
12180
|
};
|
|
11699
|
-
const handleRemoveFromAncestry =
|
|
12181
|
+
const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
|
|
11700
12182
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
11701
12183
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
11702
12184
|
return;
|
|
@@ -11721,7 +12203,7 @@ function XViewScene({
|
|
|
11721
12203
|
return { ...prev, tree: newTree };
|
|
11722
12204
|
});
|
|
11723
12205
|
}, []);
|
|
11724
|
-
const handleSaveAncestry =
|
|
12206
|
+
const handleSaveAncestry = useCallback4(
|
|
11725
12207
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
11726
12208
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
11727
12209
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -11925,7 +12407,7 @@ function XViewScene({
|
|
|
11925
12407
|
});
|
|
11926
12408
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
11927
12409
|
};
|
|
11928
|
-
const handleDeleteAncestry =
|
|
12410
|
+
const handleDeleteAncestry = useCallback4(
|
|
11929
12411
|
async (ancestryIdToDelete) => {
|
|
11930
12412
|
if (!ancestryIdToDelete) {
|
|
11931
12413
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -11987,15 +12469,15 @@ function XViewScene({
|
|
|
11987
12469
|
},
|
|
11988
12470
|
[save_view_data, delete_file_action]
|
|
11989
12471
|
);
|
|
11990
|
-
const handleOpenAncestryBoard =
|
|
12472
|
+
const handleOpenAncestryBoard = useCallback4(() => {
|
|
11991
12473
|
setIsAncestryBoardOpen(true);
|
|
11992
12474
|
}, []);
|
|
11993
|
-
const handleSelectAncestryFromBoard =
|
|
12475
|
+
const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
|
|
11994
12476
|
setIsAncestryBoardOpen(false);
|
|
11995
12477
|
setIsSidebarOpen(false);
|
|
11996
12478
|
handleStartReadingAncestry(ancestry);
|
|
11997
12479
|
}, [handleStartReadingAncestry]);
|
|
11998
|
-
const handleSaveAncestryBoard =
|
|
12480
|
+
const handleSaveAncestryBoard = useCallback4(async (groups) => {
|
|
11999
12481
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
12000
12482
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
12001
12483
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
@@ -12019,13 +12501,13 @@ function XViewScene({
|
|
|
12019
12501
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
12020
12502
|
});
|
|
12021
12503
|
}, [parentDataRef.current, sceneVersion]);
|
|
12022
|
-
const handleAddExistingNode =
|
|
12504
|
+
const handleAddExistingNode = useCallback4(
|
|
12023
12505
|
(nodeId) => {
|
|
12024
12506
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
12025
12507
|
},
|
|
12026
12508
|
[actionHandlerContext]
|
|
12027
12509
|
);
|
|
12028
|
-
const handleSaveCurrentView =
|
|
12510
|
+
const handleSaveCurrentView = useCallback4(async () => {
|
|
12029
12511
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12030
12512
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12031
12513
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12065,7 +12547,7 @@ function XViewScene({
|
|
|
12065
12547
|
const allAvailableAncestries = useMemo12(() => {
|
|
12066
12548
|
return ancestryDataRef.current || [];
|
|
12067
12549
|
}, [sceneVersion, isInitialized]);
|
|
12068
|
-
const handleOpenReference =
|
|
12550
|
+
const handleOpenReference = useCallback4((referenceData) => {
|
|
12069
12551
|
const { type, id } = referenceData;
|
|
12070
12552
|
if (type === "node") {
|
|
12071
12553
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -12092,10 +12574,10 @@ function XViewScene({
|
|
|
12092
12574
|
}
|
|
12093
12575
|
}
|
|
12094
12576
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
12095
|
-
const handleToggleAncestryAddMode =
|
|
12577
|
+
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
12096
12578
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
12097
12579
|
}, []);
|
|
12098
|
-
const handleFocusNode =
|
|
12580
|
+
const handleFocusNode = useCallback4((nodeData) => {
|
|
12099
12581
|
if (!nodeData) return;
|
|
12100
12582
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
12101
12583
|
if (nodeMesh) {
|
|
@@ -12165,7 +12647,6 @@ function XViewScene({
|
|
|
12165
12647
|
height: "100vh",
|
|
12166
12648
|
position: "relative",
|
|
12167
12649
|
overflow: "hidden",
|
|
12168
|
-
// <--- ADICIONE ESTA LINHA
|
|
12169
12650
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12170
12651
|
}
|
|
12171
12652
|
},
|
|
@@ -12232,9 +12713,20 @@ function XViewScene({
|
|
|
12232
12713
|
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
|
|
12233
12714
|
"div",
|
|
12234
12715
|
{
|
|
12235
|
-
className:
|
|
12236
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
|
|
12716
|
+
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"}`,
|
|
12717
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12237
12718
|
},
|
|
12719
|
+
/* @__PURE__ */ React23.createElement(
|
|
12720
|
+
"div",
|
|
12721
|
+
{
|
|
12722
|
+
onPointerDown: (e) => {
|
|
12723
|
+
e.stopPropagation();
|
|
12724
|
+
handleReadModeResize(e);
|
|
12725
|
+
},
|
|
12726
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
12727
|
+
title: "Arraste para redimensionar"
|
|
12728
|
+
}
|
|
12729
|
+
),
|
|
12238
12730
|
/* @__PURE__ */ React23.createElement(
|
|
12239
12731
|
DescriptionReadModePanel,
|
|
12240
12732
|
{
|