@lv-x-software-house/x_view 1.2.4-dev.9 → 1.2.4

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.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1225 -551
  3. package/dist/index.mjs +1171 -497
  4. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/XViewScene.jsx
2
- import React24, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef18, useState as useState24, useMemo as useMemo12 } from "react";
2
+ import React25, { useCallback as useCallback4, useEffect as useEffect22, useRef as useRef19, useState as useState25, 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";
@@ -72,6 +72,13 @@ function defineAbilityFor(role) {
72
72
  }
73
73
 
74
74
  // src/components/ContextMenu.jsx
75
+ var QUEST_STATUS_COLORS = {
76
+ "Backlog": "#64748b",
77
+ "In Progress": "#eab308",
78
+ "Review": "#a855f7",
79
+ "Done": "#22c55e"
80
+ };
81
+ var QUEST_STATUSES = ["Backlog", "In Progress", "Review", "Done"];
75
82
  function ContextMenu({
76
83
  data,
77
84
  userRole,
@@ -92,19 +99,21 @@ function ContextMenu({
92
99
  onFocusNode,
93
100
  onClose
94
101
  }) {
95
- var _a, _b;
102
+ var _a, _b, _c;
96
103
  const menuRef = useRef(null);
97
104
  const [menuPos, setMenuPos] = useState({ left: 0, top: 0 });
98
105
  const [menuView, setMenuView] = useState("main");
99
106
  const [selectedAncestry, setSelectedAncestry] = useState(null);
100
107
  const [versionSubMenu, setVersionSubMenu] = useState(null);
101
108
  const [isLinkCopied, setIsLinkCopied] = useState(false);
109
+ const [selectedQuestStatus, setSelectedQuestStatus] = useState(null);
102
110
  const ability = useMemo(() => defineAbilityFor(userRole), [userRole]);
103
111
  useEffect(() => {
104
112
  if (data.visible) {
105
113
  setMenuView("main");
106
114
  setSelectedAncestry(null);
107
115
  setVersionSubMenu(null);
116
+ setSelectedQuestStatus(null);
108
117
  }
109
118
  }, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
110
119
  useLayoutEffect(() => {
@@ -119,7 +128,7 @@ function ContextMenu({
119
128
  if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
120
129
  if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
121
130
  setMenuPos({ left, top });
122
- }, [data, menuView, versionSubMenu]);
131
+ }, [data, menuView, versionSubMenu, selectedQuestStatus]);
123
132
  useEffect(() => {
124
133
  if (!data.visible) return;
125
134
  const handleClickOutside = (e) => {
@@ -162,7 +171,16 @@ function ContextMenu({
162
171
  var _a2;
163
172
  return c.targetNode && !(((_a2 = c.targetNode.version_node) == null ? void 0 : _a2.is_version) && String(c.targetNode.version_node.parent_node) === String(data.nodeData.id));
164
173
  });
165
- const groupedConnections = connections.reduce((acc, conn) => {
174
+ const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
175
+ const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
176
+ var _a2;
177
+ return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
178
+ });
179
+ const questConnections = isCurrentNodeQuest ? [] : connections.filter((c) => {
180
+ var _a2;
181
+ return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
182
+ });
183
+ const groupedConnections = commonConnections.reduce((acc, conn) => {
166
184
  var _a2;
167
185
  const { targetNode } = conn;
168
186
  const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
@@ -198,6 +216,20 @@ function ContextMenu({
198
216
  };
199
217
  }
200
218
  }).filter(Boolean);
219
+ const questsByStatus = {
220
+ "Backlog": [],
221
+ "In Progress": [],
222
+ "Review": [],
223
+ "Done": []
224
+ };
225
+ questConnections.forEach((conn) => {
226
+ const status = conn.targetNode.status || "Backlog";
227
+ if (questsByStatus[status]) {
228
+ questsByStatus[status].push(conn);
229
+ } else {
230
+ questsByStatus["Backlog"].push(conn);
231
+ }
232
+ });
201
233
  const availableAncestries = (ancestryData || []).filter(
202
234
  (ancestry) => String(ancestry.ancestral_node) === String(data.nodeData.id)
203
235
  );
@@ -250,11 +282,12 @@ function ContextMenu({
250
282
  });
251
283
  };
252
284
  const renderMainView = () => {
285
+ var _a2;
253
286
  const hasVersions = computedVersions.length > 0;
254
287
  const canCreateVersion = ability.can("create", "Versioning");
255
288
  const canReadVersion = ability.can("read", "Versioning");
256
289
  const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
257
- 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: () => {
290
+ 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") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__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-.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: () => {
258
291
  onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
259
292
  onClose();
260
293
  }, 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"))));
@@ -279,9 +312,9 @@ function ContextMenu({
279
312
  if (versionSubMenu) {
280
313
  return renderVersionSubMenuView();
281
314
  }
282
- const totalItems = availableAncestries.length + finalRenderableConnections.length;
315
+ const totalItems = availableAncestries.length + finalRenderableConnections.length + (questConnections.length > 0 ? 1 : 0);
283
316
  const isScrollable = totalItems > 10;
284
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), connections.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(connections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 ? "mb-4" : "mb-2"}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ React.createElement(
317
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(commonConnections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ React.createElement(
285
318
  "button",
286
319
  {
287
320
  key: anc.ancestry_id,
@@ -291,7 +324,7 @@ function ContextMenu({
291
324
  },
292
325
  /* @__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: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ React.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "21", r: "2" })),
293
326
  /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
294
- )), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" })), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, finalRenderableConnections.map((group) => {
327
+ ))), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), finalRenderableConnections.map((group) => {
295
328
  if (group.isVersionGroup) {
296
329
  return /* @__PURE__ */ React.createElement(
297
330
  "button",
@@ -319,7 +352,54 @@ function ContextMenu({
319
352
  group.links.length > 1 && /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-indigo-500/20 rounded-full" }, group.links.length)
320
353
  );
321
354
  }
322
- }))));
355
+ })), questConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1 mt-1" }, (availableAncestries.length > 0 || finalRenderableConnections.length > 0) && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement(
356
+ "button",
357
+ {
358
+ onClick: () => setMenuView("quest_statuses"),
359
+ className: baseButtonClass,
360
+ title: "Ver Quests Conectadas"
361
+ },
362
+ /* @__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", className: "text-sky-400" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "2" })),
363
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, "quests"),
364
+ /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-sky-500/20 text-sky-200 rounded-full" }, questConnections.length)
365
+ ))));
366
+ };
367
+ const renderQuestStatusesView = () => {
368
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Status das Quests"))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, QUEST_STATUSES.map((status) => {
369
+ const count = questsByStatus[status].length;
370
+ const color = QUEST_STATUS_COLORS[status];
371
+ return /* @__PURE__ */ React.createElement(
372
+ "button",
373
+ {
374
+ key: status,
375
+ onClick: () => {
376
+ if (count > 0) {
377
+ setSelectedQuestStatus(status);
378
+ setMenuView("quest_list");
379
+ }
380
+ },
381
+ className: `${baseButtonClass} ${count === 0 ? "opacity-50 cursor-default hover:bg-transparent hover:text-slate-200" : ""}`
382
+ },
383
+ /* @__PURE__ */ React.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: color } }),
384
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, status),
385
+ count > 0 && /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-white/10 rounded-full" }, count)
386
+ );
387
+ })));
388
+ };
389
+ const renderQuestListView = () => {
390
+ const quests = questsByStatus[selectedQuestStatus] || [];
391
+ const isScrollable = quests.length > 10;
392
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("quest_statuses"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: `Quests: ${selectedQuestStatus}` }, "Quests: ", selectedQuestStatus)), quests.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(quests.map((q) => q.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, quests.map((conn) => /* @__PURE__ */ React.createElement(
393
+ "button",
394
+ {
395
+ key: conn.targetNode.id,
396
+ onClick: () => handleConnectionClick({ links: [conn.link] }),
397
+ className: baseButtonClass,
398
+ title: `Expandir Quest ${conn.targetNode.name}`
399
+ },
400
+ /* @__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", className: "opacity-70" }, /* @__PURE__ */ React.createElement("polyline", { points: "13 17 18 12 13 7" }), /* @__PURE__ */ React.createElement("polyline", { points: "6 17 11 12 6 7" })),
401
+ /* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
402
+ ))));
323
403
  };
324
404
  const renderAncestryActionsView = () => {
325
405
  const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
@@ -382,7 +462,7 @@ function ContextMenu({
382
462
  onDoubleClick: swallow
383
463
  },
384
464
  /* @__PURE__ */ React.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
385
- /* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
465
+ /* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "quest_statuses" && renderQuestStatusesView(), menuView === "quest_list" && renderQuestListView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
386
466
  );
387
467
  }
388
468
 
@@ -460,7 +540,11 @@ function XViewSidebar({
460
540
  let pool = base;
461
541
  const qNorm = normalize(query);
462
542
  if (qNorm) {
463
- pool = pool.filter((n) => normalize((n == null ? void 0 : n.name) || "").includes(qNorm));
543
+ pool = pool.filter((n) => {
544
+ const matchName = normalize((n == null ? void 0 : n.name) || "").includes(qNorm);
545
+ const matchRawTitle = n.is_quest && n.raw_title ? normalize(n.raw_title).includes(qNorm) : false;
546
+ return matchName || matchRawTitle;
547
+ });
464
548
  }
465
549
  if (activeFilters.length > 0) {
466
550
  pool = pool.filter((node) => {
@@ -962,7 +1046,8 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
962
1046
  const size = nodeData.size || "medium";
963
1047
  const scale = NODE_SCALE_FACTORS[size] || 1;
964
1048
  mesh.scale.set(scale, scale, scale);
965
- const label = createTextSprite(nodeData.name);
1049
+ const labelText = nodeData.is_quest && nodeData.raw_title ? nodeData.raw_title : nodeData.name;
1050
+ const label = createTextSprite(labelText);
966
1051
  label.name = "label";
967
1052
  mesh.userData.labelObject = label;
968
1053
  mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
@@ -1067,13 +1152,15 @@ var updateExistingNodeVisuals = (state, updatedNode) => {
1067
1152
  const size = updatedNode.size || "medium";
1068
1153
  const scale = NODE_SCALE_FACTORS[size] || 1;
1069
1154
  existingMesh.scale.set(scale, scale, scale);
1070
- if (existingMesh.userData.name !== updatedNode.name) {
1155
+ const oldText = existingMesh.userData.is_quest && existingMesh.userData.raw_title ? existingMesh.userData.raw_title : existingMesh.userData.name;
1156
+ const newText = updatedNode.is_quest && updatedNode.raw_title ? updatedNode.raw_title : updatedNode.name;
1157
+ if (oldText !== newText) {
1071
1158
  const oldLabelToDispose = existingMesh.userData.labelObject;
1072
1159
  if (oldLabelToDispose && state.graphGroup) {
1073
1160
  state.graphGroup.remove(oldLabelToDispose);
1074
1161
  if (oldLabelToDispose.material) oldLabelToDispose.material.dispose();
1075
1162
  }
1076
- const newLabel = createTextSprite(updatedNode.name || "");
1163
+ const newLabel = createTextSprite(newText || "");
1077
1164
  newLabel.name = "label";
1078
1165
  existingMesh.userData.labelObject = newLabel;
1079
1166
  if (state.graphGroup) {
@@ -1181,8 +1268,6 @@ var createMultipleLinkLines = (linksArray, sourceNodeMesh, targetNodeMesh, resol
1181
1268
  targetNodeMesh,
1182
1269
  resolution,
1183
1270
  isCurved,
1184
- isCurved,
1185
- isCurved,
1186
1271
  curveOffset
1187
1272
  );
1188
1273
  line.userData = {
@@ -1795,6 +1880,7 @@ var userActionHandlers = {
1795
1880
  setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
1796
1881
  },
1797
1882
  handleSaveVersionNode: async (context, newNodeData) => {
1883
+ var _a;
1798
1884
  const { graphDataRef, sceneDataRef, stateRef, versionMode, setters } = context;
1799
1885
  if (!graphDataRef.current || !sceneDataRef.current) return;
1800
1886
  const { sourceNodeData } = versionMode;
@@ -1814,9 +1900,21 @@ var userActionHandlers = {
1814
1900
  const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
1815
1901
  specificParentData.nodes.push(newNode);
1816
1902
  specificParentData.links.push(newLink);
1817
- const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
1818
1903
  try {
1819
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
1904
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
1905
+ if (isView && parentFileId === context.sceneConfigId) {
1906
+ const viewFilePayload = {
1907
+ parent_dbs: sceneDataRef.current.parent_dbs,
1908
+ nodes: sceneDataRef.current.nodes,
1909
+ links: sceneDataRef.current.links,
1910
+ quest_nodes: specificParentData.nodes,
1911
+ quest_links: specificParentData.links
1912
+ };
1913
+ await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
1914
+ } else {
1915
+ const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
1916
+ await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
1917
+ }
1820
1918
  graphDataRef.current[parentFileId] = specificParentData;
1821
1919
  const finalPosition = stateRef.current.ghostElements.node.position.clone();
1822
1920
  addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
@@ -1840,10 +1938,6 @@ var userActionHandlers = {
1840
1938
  var _a;
1841
1939
  const isSource = String(link.source) === String(sourceNode.id);
1842
1940
  const targetNodeId = isSource ? link.target : link.source;
1843
- const linkAlreadyInSceneData = sceneDataRef.current.links.some((l) => String(l.id) === String(link.id));
1844
- if (!linkAlreadyInSceneData) {
1845
- sceneDataRef.current.links.push(link);
1846
- }
1847
1941
  if (!nodeObjects[String(targetNodeId)]) {
1848
1942
  const allParentNodes = Object.values(graphDataRef.current).flatMap((fileData) => fileData.nodes);
1849
1943
  const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId));
@@ -1851,9 +1945,6 @@ var userActionHandlers = {
1851
1945
  console.warn(`Dados do Node com ID ${targetNodeId} n\xE3o encontrados no cache.`);
1852
1946
  return;
1853
1947
  }
1854
- if (!sceneDataRef.current.nodes.some((n) => String(n.id) === String(nodeData.id))) {
1855
- sceneDataRef.current.nodes.push(nodeData);
1856
- }
1857
1948
  const startPosition = sourceNodeMesh.position.clone();
1858
1949
  const endPosition = startPosition.clone().add(
1859
1950
  new THREE.Vector3((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 60)
@@ -1973,6 +2064,7 @@ var userActionHandlers = {
1973
2064
  if (mountRef.current) mountRef.current.style.cursor = "grab";
1974
2065
  },
1975
2066
  handleCompleteConnection: async (context, targetNodeData) => {
2067
+ var _a;
1976
2068
  const { stateRef, graphDataRef, sceneDataRef } = context;
1977
2069
  const { sourceNodeData } = stateRef.current.connection;
1978
2070
  if (!graphDataRef.current || !sceneDataRef.current || !sourceNodeData || !targetNodeData) {
@@ -1995,12 +2087,26 @@ var userActionHandlers = {
1995
2087
  source: sourceNodeData.id,
1996
2088
  target: targetNodeData.id
1997
2089
  };
1998
- const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
1999
- specificParentData.links.push(newLink);
2000
- const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
2001
2090
  try {
2002
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2003
- graphDataRef.current[parentFileIdToSave] = specificParentData;
2091
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2092
+ if (isView && parentFileIdToSave === context.sceneConfigId) {
2093
+ const specificParentData = graphDataRef.current[context.sceneConfigId];
2094
+ specificParentData.links.push(newLink);
2095
+ const viewFilePayload = {
2096
+ parent_dbs: sceneDataRef.current.parent_dbs,
2097
+ nodes: sceneDataRef.current.nodes,
2098
+ links: sceneDataRef.current.links,
2099
+ quest_nodes: specificParentData.nodes,
2100
+ quest_links: specificParentData.links
2101
+ };
2102
+ await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
2103
+ } else {
2104
+ const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
2105
+ specificParentData.links.push(newLink);
2106
+ const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
2107
+ await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2108
+ graphDataRef.current[parentFileIdToSave] = specificParentData;
2109
+ }
2004
2110
  addNewLinkToScene(stateRef.current, newLink);
2005
2111
  } catch (error) {
2006
2112
  console.error("Falha ao salvar a nova conex\xE3o:", error);
@@ -2069,14 +2175,28 @@ var userActionHandlers = {
2069
2175
  } else {
2070
2176
  newTargetId = newEndNodeData.id;
2071
2177
  }
2072
- const originalParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
2073
- const newParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
2074
- if (!originalParentInfo || !newParentInfo || !originalParentInfo.ownerId || !newParentInfo.ownerId) {
2075
- console.error("N\xE3o foi poss\xEDvel encontrar informa\xE7\xF5es dos arquivos pai para o relink.");
2178
+ const oldSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
2179
+ const oldTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldTargetId, context.sceneConfigId, context.ownerId);
2180
+ const newSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
2181
+ const newTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newTargetId, context.sceneConfigId, context.ownerId);
2182
+ if (!oldSourceInfo || !oldTargetInfo || !newSourceInfo || !newTargetInfo) {
2183
+ console.error("Informa\xE7\xF5es dos arquivos pai incompletas para o relink.");
2076
2184
  alert("Ocorreu um erro ao identificar os arquivos pai para salvar a altera\xE7\xE3o.");
2077
2185
  userActionHandlers.handleCancelRelink(context);
2078
2186
  return;
2079
2187
  }
2188
+ let oldGoverningFileId = oldSourceInfo.parentFileId;
2189
+ let oldGoverningOwnerId = oldSourceInfo.ownerId;
2190
+ if (oldSourceInfo.parentFileId === context.sceneConfigId || oldTargetInfo.parentFileId === context.sceneConfigId) {
2191
+ oldGoverningFileId = context.sceneConfigId;
2192
+ oldGoverningOwnerId = context.ownerId;
2193
+ }
2194
+ let newGoverningFileId = newSourceInfo.parentFileId;
2195
+ let newGoverningOwnerId = newSourceInfo.ownerId;
2196
+ if (newSourceInfo.parentFileId === context.sceneConfigId || newTargetInfo.parentFileId === context.sceneConfigId) {
2197
+ newGoverningFileId = context.sceneConfigId;
2198
+ newGoverningOwnerId = context.ownerId;
2199
+ }
2080
2200
  const { sourceNode, targetNode, ...dataToKeep } = originalLinkData;
2081
2201
  const newLinkData = {
2082
2202
  ...dataToKeep,
@@ -2084,34 +2204,44 @@ var userActionHandlers = {
2084
2204
  target: newTargetId,
2085
2205
  id: linkId
2086
2206
  };
2207
+ const saveParentData = async (fileId, fileOwnerId, data) => {
2208
+ var _a;
2209
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2210
+ if (isView && fileId === context.sceneConfigId) {
2211
+ const viewFilePayload = {
2212
+ parent_dbs: sceneDataRef.current.parent_dbs,
2213
+ nodes: sceneDataRef.current.nodes,
2214
+ links: sceneDataRef.current.links,
2215
+ quest_nodes: data.nodes,
2216
+ quest_links: data.links
2217
+ };
2218
+ return context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
2219
+ } else {
2220
+ return context.actions.save_view_data(`x_view_dbs/${fileOwnerId}/${fileId}`, data);
2221
+ }
2222
+ };
2087
2223
  const savePromises = [];
2088
2224
  const filesToUpdate = {};
2089
- if (originalParentInfo.parentFileId !== newParentInfo.parentFileId) {
2090
- const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[originalParentInfo.parentFileId]));
2225
+ if (oldGoverningFileId !== newGoverningFileId) {
2226
+ const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
2091
2227
  updatedOriginalParentData.links = updatedOriginalParentData.links.filter(
2092
2228
  (l) => String(l.id) !== String(linkId)
2093
2229
  );
2094
- filesToUpdate[originalParentInfo.parentFileId] = updatedOriginalParentData;
2095
- savePromises.push(
2096
- context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedOriginalParentData)
2097
- );
2098
- const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newParentInfo.parentFileId]));
2230
+ filesToUpdate[oldGoverningFileId] = updatedOriginalParentData;
2231
+ savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedOriginalParentData));
2232
+ const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newGoverningFileId]));
2099
2233
  if (!updatedNewParentData.links) updatedNewParentData.links = [];
2100
2234
  updatedNewParentData.links.push(newLinkData);
2101
- filesToUpdate[newParentInfo.parentFileId] = updatedNewParentData;
2102
- savePromises.push(
2103
- context.actions.save_view_data(`x_view_dbs/${newParentInfo.ownerId}/${newParentInfo.parentFileId}`, updatedNewParentData)
2104
- );
2235
+ filesToUpdate[newGoverningFileId] = updatedNewParentData;
2236
+ savePromises.push(saveParentData(newGoverningFileId, newGoverningOwnerId, updatedNewParentData));
2105
2237
  } else {
2106
- const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[originalParentInfo.parentFileId]));
2238
+ const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
2107
2239
  updatedParentData.links = updatedParentData.links.filter(
2108
2240
  (l) => String(l.id) !== String(linkId)
2109
2241
  );
2110
2242
  updatedParentData.links.push(newLinkData);
2111
- filesToUpdate[originalParentInfo.parentFileId] = updatedParentData;
2112
- savePromises.push(
2113
- context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedParentData)
2114
- );
2243
+ filesToUpdate[oldGoverningFileId] = updatedParentData;
2244
+ savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedParentData));
2115
2245
  }
2116
2246
  try {
2117
2247
  await Promise.all(savePromises);
@@ -2129,7 +2259,7 @@ var userActionHandlers = {
2129
2259
  }
2130
2260
  },
2131
2261
  handleDeleteLink: async (context, linkObject) => {
2132
- var _a, _b, _c, _d, _e, _f;
2262
+ var _a, _b, _c, _d, _e, _f, _g;
2133
2263
  const { stateRef, graphDataRef, sceneDataRef, setters } = context;
2134
2264
  setters.setRelationshipMenu({ visible: false });
2135
2265
  if (!(linkObject == null ? void 0 : linkObject.userData) || !graphDataRef.current || !sceneDataRef.current) return;
@@ -2152,7 +2282,8 @@ var userActionHandlers = {
2152
2282
  specificParentData.links = newLinks;
2153
2283
  let filenameToSave;
2154
2284
  let payloadToSave;
2155
- if (parentFileId === context.sceneConfigId) {
2285
+ const isView = ((_g = context.viewType) == null ? void 0 : _g.toLowerCase()) === "view";
2286
+ if (isView && parentFileId === context.sceneConfigId) {
2156
2287
  filenameToSave = context.sceneSaveUrl;
2157
2288
  sceneDataRef.current.links = sceneDataRef.current.links.filter((l) => String(l.id) !== String(linkIdToDelete));
2158
2289
  payloadToSave = {
@@ -2185,12 +2316,6 @@ var userActionHandlers = {
2185
2316
  if (!nodeData || !sceneDataRef.current) return;
2186
2317
  const nodeIdToDismiss = nodeData.id;
2187
2318
  const strNodeId = String(nodeIdToDismiss);
2188
- sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
2189
- (n) => String(n.id) !== strNodeId
2190
- );
2191
- sceneDataRef.current.links = sceneDataRef.current.links.filter(
2192
- (l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId
2193
- );
2194
2319
  const { ancestryGroup, ancestryLinks } = stateRef.current;
2195
2320
  if (ancestryGroup && ancestryLinks) {
2196
2321
  const remainingAncestryLinks = [];
@@ -2232,22 +2357,12 @@ var userActionHandlers = {
2232
2357
  removeNodeFromScene(stateRef.current, nodeId);
2233
2358
  setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
2234
2359
  });
2235
- sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
2236
- (n) => String(n.id) === strNodeIdToKeep
2237
- );
2238
- sceneDataRef.current.links = [];
2239
2360
  },
2240
2361
  handleDismissMultipleNodes: (context, nodeIds) => {
2241
2362
  const { stateRef, sceneDataRef, setters } = context;
2242
2363
  setters.setMultiContextMenu({ visible: false });
2243
2364
  if (!nodeIds || nodeIds.size === 0 || !sceneDataRef.current) return;
2244
2365
  const strNodeIds = Array.from(nodeIds).map(String);
2245
- sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
2246
- (n) => !strNodeIds.includes(String(n.id))
2247
- );
2248
- sceneDataRef.current.links = sceneDataRef.current.links.filter(
2249
- (l) => !strNodeIds.includes(String(l.source)) && !strNodeIds.includes(String(l.target))
2250
- );
2251
2366
  const { ancestryGroup, ancestryLinks } = stateRef.current;
2252
2367
  if (ancestryGroup && ancestryLinks) {
2253
2368
  const remainingAncestryLinks = [];
@@ -2303,15 +2418,10 @@ var userActionHandlers = {
2303
2418
  removeNodeFromScene(stateRef.current, nodeId);
2304
2419
  setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
2305
2420
  });
2306
- sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
2307
- (n) => strNodeIdsToKeep.includes(String(n.id))
2308
- );
2309
- sceneDataRef.current.links = sceneDataRef.current.links.filter(
2310
- (l) => strNodeIdsToKeep.includes(String(l.source)) && strNodeIdsToKeep.includes(String(l.target))
2311
- );
2312
2421
  stateRef.current.selectedNodes.clear();
2313
2422
  },
2314
2423
  handleDeleteMultipleNodes: async (context, nodeIds) => {
2424
+ var _a;
2315
2425
  const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
2316
2426
  setters.setMultiContextMenu({ visible: false });
2317
2427
  if (!nodeIds || nodeIds.size === 0 || !graphDataRef.current || !sceneDataRef.current) return;
@@ -2366,7 +2476,8 @@ var userActionHandlers = {
2366
2476
  );
2367
2477
  let filenameToSave;
2368
2478
  let payloadToSave;
2369
- if (parentFileId === context.sceneConfigId) {
2479
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2480
+ if (isView && parentFileId === context.sceneConfigId) {
2370
2481
  filenameToSave = context.sceneSaveUrl;
2371
2482
  const strNodesToDelete = Array.from(nodesToDelete).map(String);
2372
2483
  const strLinksToDelete = Array.from(linksToDelete).map(String);
@@ -2404,6 +2515,7 @@ var userActionHandlers = {
2404
2515
  }
2405
2516
  },
2406
2517
  handleDeleteNode: async (context, nodeData) => {
2518
+ var _a;
2407
2519
  const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
2408
2520
  if (actions.delete_file && nodeData) {
2409
2521
  const urls = extractFileUrlsFromProperties(nodeData);
@@ -2429,7 +2541,8 @@ var userActionHandlers = {
2429
2541
  specificParentData.links = newLinks;
2430
2542
  let filenameToSave;
2431
2543
  let payloadToSave;
2432
- if (parentFileId === context.sceneConfigId) {
2544
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2545
+ if (isView && parentFileId === context.sceneConfigId) {
2433
2546
  filenameToSave = context.sceneSaveUrl;
2434
2547
  const newVisualNodes = sceneDataRef.current.nodes.filter((n) => String(n.id) !== strNodeId);
2435
2548
  const newVisualLinks = sceneDataRef.current.links.filter((l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId);
@@ -2458,6 +2571,7 @@ var userActionHandlers = {
2458
2571
  }
2459
2572
  },
2460
2573
  handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
2574
+ var _a;
2461
2575
  const { graphDataRef, sceneDataRef, stateRef, setters } = context;
2462
2576
  if (!graphDataRef.current || !sceneDataRef.current) return;
2463
2577
  const { _baseEmissiveIntensity: ignored, ...nodeToSave } = updatedNode;
@@ -2477,9 +2591,28 @@ var userActionHandlers = {
2477
2591
  alert("Erro interno: Node n\xE3o encontrado para salvar.");
2478
2592
  return;
2479
2593
  }
2480
- const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
2481
2594
  try {
2482
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2595
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2596
+ if (isView && parentFileId === context.sceneConfigId) {
2597
+ const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
2598
+ if (visualNodeIndex > -1) {
2599
+ sceneDataRef.current.nodes[visualNodeIndex] = {
2600
+ ...sceneDataRef.current.nodes[visualNodeIndex],
2601
+ ...nodeToSave
2602
+ };
2603
+ }
2604
+ const viewFilePayload = {
2605
+ parent_dbs: sceneDataRef.current.parent_dbs,
2606
+ nodes: sceneDataRef.current.nodes,
2607
+ links: sceneDataRef.current.links,
2608
+ quest_nodes: specificParentData.nodes,
2609
+ quest_links: specificParentData.links
2610
+ };
2611
+ await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
2612
+ } else {
2613
+ const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
2614
+ await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2615
+ }
2483
2616
  graphDataRef.current[parentFileId] = specificParentData;
2484
2617
  updateExistingNodeVisuals(stateRef.current, nodeToSave);
2485
2618
  setters.setSceneVersion((v) => v + 1);
@@ -2492,6 +2625,7 @@ var userActionHandlers = {
2492
2625
  }
2493
2626
  },
2494
2627
  handleSaveLinkDetails: async (context, updatedLink, keepOpen = false) => {
2628
+ var _a;
2495
2629
  const { graphDataRef, sceneDataRef, stateRef, setters } = context;
2496
2630
  if (!graphDataRef.current || !sceneDataRef.current) return;
2497
2631
  const { sourceNode, targetNode, ...linkToSave } = updatedLink;
@@ -2511,9 +2645,21 @@ var userActionHandlers = {
2511
2645
  alert("Erro interno: link n\xE3o encontrado para salvar.");
2512
2646
  return;
2513
2647
  }
2514
- const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
2515
2648
  try {
2516
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2649
+ const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
2650
+ if (isView && parentFileId === context.sceneConfigId) {
2651
+ const viewFilePayload = {
2652
+ parent_dbs: sceneDataRef.current.parent_dbs,
2653
+ nodes: sceneDataRef.current.nodes,
2654
+ links: sceneDataRef.current.links,
2655
+ quest_nodes: specificParentData.nodes,
2656
+ quest_links: specificParentData.links
2657
+ };
2658
+ await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
2659
+ } else {
2660
+ const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
2661
+ await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2662
+ }
2517
2663
  graphDataRef.current[parentFileId] = specificParentData;
2518
2664
  const lineObject = stateRef.current.allLinks.find(
2519
2665
  (l) => String(l.userData.id) === String(linkToSave.id)
@@ -2536,7 +2682,7 @@ var userActionHandlers = {
2536
2682
  }
2537
2683
  },
2538
2684
  handleAddExistingNodeById: (context, nodeId) => {
2539
- var _a, _b;
2685
+ var _a;
2540
2686
  const { stateRef, sceneDataRef, graphDataRef, tweenToTarget, setters } = context;
2541
2687
  const state = stateRef.current;
2542
2688
  const graphFull = graphDataRef.current;
@@ -2552,16 +2698,12 @@ var userActionHandlers = {
2552
2698
  tweenToTarget(state.nodeObjects[strNodeId]);
2553
2699
  return;
2554
2700
  }
2555
- const alreadyInSceneData = (((_a = sceneDataRef.current) == null ? void 0 : _a.nodes) || []).some((n) => String(n.id) === String(strNodeId));
2556
- if (!alreadyInSceneData) {
2557
- sceneDataRef.current.nodes.push(nodeData);
2558
- }
2559
2701
  const base = state.controls ? state.controls.target.clone() : new THREE.Vector3(0, 0, 0);
2560
2702
  const offset = new THREE.Vector3((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 6, (Math.random() - 0.5) * 20);
2561
2703
  const position = base.add(offset);
2562
2704
  addStandaloneNodeToScene(state, nodeData, position);
2563
2705
  tweenToTarget(position, 1.3);
2564
- (_b = setters == null ? void 0 : setters.setSceneVersion) == null ? void 0 : _b.call(setters, (v) => v + 1);
2706
+ (_a = setters == null ? void 0 : setters.setSceneVersion) == null ? void 0 : _a.call(setters, (v) => v + 1);
2565
2707
  }
2566
2708
  };
2567
2709
 
@@ -2800,7 +2942,10 @@ var IGNORED_KEYS = [
2800
2942
  "is_private",
2801
2943
  "abstraction_tree",
2802
2944
  "selectedAbstractionParentId",
2803
- "isAddingAbstractionNodes"
2945
+ "isAddingAbstractionNodes",
2946
+ "status",
2947
+ "is_quest",
2948
+ "raw_title"
2804
2949
  ];
2805
2950
  function extractCustomPropsFromNode(node) {
2806
2951
  const customPropTypes = node._customPropTypes || {};
@@ -7890,16 +8035,12 @@ function InSceneVersionForm({
7890
8035
 
7891
8036
  // src/components/InSceneQuestForm.jsx
7892
8037
  import React15, { useState as useState16, useRef as useRef12 } from "react";
7893
- import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4 } from "react-icons/fi";
7894
- var QUEST_STATUS_COLORS = {
8038
+ import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4, FiChevronDown as FiChevronDown5 } from "react-icons/fi";
8039
+ var QUEST_STATUS_COLORS2 = {
7895
8040
  "Backlog": "#64748b",
7896
- // Slate (Cinza azulado)
7897
8041
  "In Progress": "#eab308",
7898
- // Yellow (Amarelo)
7899
8042
  "Review": "#a855f7",
7900
- // Purple (Roxo)
7901
8043
  "Done": "#22c55e"
7902
- // Green (Verde)
7903
8044
  };
7904
8045
  function InSceneQuestForm({
7905
8046
  onSave,
@@ -7910,7 +8051,14 @@ function InSceneQuestForm({
7910
8051
  availableNodes = [],
7911
8052
  availableAncestries = [],
7912
8053
  onMentionClick,
7913
- onUploadFile
8054
+ onUploadFile,
8055
+ onNameChange,
8056
+ onColorChange,
8057
+ onSizeChange,
8058
+ viewName = "Projeto",
8059
+ // NOVA PROP
8060
+ questCounter = 1
8061
+ // NOVA PROP
7914
8062
  }) {
7915
8063
  const [name, setName] = useState16("");
7916
8064
  const [types, setTypes] = useState16(["quest"]);
@@ -7919,9 +8067,11 @@ function InSceneQuestForm({
7919
8067
  const [size, setSize] = useState16("medium");
7920
8068
  const [intensity, setIntensity] = useState16(0);
7921
8069
  const [description, setDescription] = useState16("");
8070
+ const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState16(false);
7922
8071
  const [customProps, setCustomProps] = useState16([]);
7923
8072
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
7924
8073
  const propsEndRef = useRef12(null);
8074
+ const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
7925
8075
  const handleAddProp = () => {
7926
8076
  const newProp = createNewCustomProperty(customProps);
7927
8077
  setCustomProps([...customProps, newProp]);
@@ -7958,7 +8108,7 @@ function InSceneQuestForm({
7958
8108
  const handleSubmit = (e) => {
7959
8109
  e.preventDefault();
7960
8110
  if (!name.trim()) {
7961
- alert("O campo 'Nome' \xE9 obrigat\xF3rio.");
8111
+ alert("O campo 'T\xEDtulo' \xE9 obrigat\xF3rio.");
7962
8112
  return;
7963
8113
  }
7964
8114
  const additionalData = toObjectFromCustomProps(
@@ -7966,10 +8116,12 @@ function InSceneQuestForm({
7966
8116
  );
7967
8117
  const processedSections = processDescriptionForSave(description, []);
7968
8118
  onSave({
7969
- name: name.trim(),
8119
+ name: standardizedName,
8120
+ // SALVA O NOME FORMATADO
8121
+ raw_title: name.trim(),
8122
+ // Salva o título puro como fallback ou metadado útil
7970
8123
  type: types,
7971
- color: QUEST_STATUS_COLORS[status],
7972
- // Cor atrelada ao status
8124
+ color: QUEST_STATUS_COLORS2[status],
7973
8125
  status,
7974
8126
  size,
7975
8127
  intensity,
@@ -7995,21 +8147,54 @@ function InSceneQuestForm({
7995
8147
  onContextMenu: swallow,
7996
8148
  onDoubleClick: swallow
7997
8149
  },
7998
- /* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS[status]}, transparent)` } }),
7999
- /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement(FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova Tarefa / Objetivo")), /* @__PURE__ */ React15.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")),
8000
- /* @__PURE__ */ React15.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ React15.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement(
8001
- "select",
8002
- {
8003
- value: status,
8004
- onChange: (e) => setStatus(e.target.value),
8005
- 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 appearance-none cursor-pointer",
8006
- style: { borderLeft: `4px solid ${QUEST_STATUS_COLORS[status]}` }
8150
+ /* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }),
8151
+ /* @__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(FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova quest")), /* @__PURE__ */ React15.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")), /* @__PURE__ */ React15.createElement(
8152
+ "button",
8153
+ {
8154
+ type: "button",
8155
+ onClick: onCancel,
8156
+ 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",
8157
+ title: "Fechar"
8158
+ },
8159
+ "\xD7"
8160
+ )),
8161
+ /* @__PURE__ */ React15.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ React15.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React15.createElement(
8162
+ "input",
8163
+ {
8164
+ required: true,
8165
+ type: "text",
8166
+ placeholder: "Ex.: Refatorar M\xF3dulo X",
8167
+ value: name,
8168
+ onChange: (e) => {
8169
+ const val = e.target.value;
8170
+ setName(val);
8171
+ onNameChange == null ? void 0 : onNameChange(val || "Nova Quest");
8172
+ },
8173
+ 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"
8174
+ }
8175
+ ), /* @__PURE__ */ React15.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ React15.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement("div", { className: "relative" }, /* @__PURE__ */ React15.createElement(
8176
+ "button",
8177
+ {
8178
+ type: "button",
8179
+ onClick: () => setIsStatusDropdownOpen(!isStatusDropdownOpen),
8180
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
8181
+ },
8182
+ /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, status)),
8183
+ /* @__PURE__ */ React15.createElement(FiChevronDown5, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
8184
+ ), isStatusDropdownOpen && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React15.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ React15.createElement(
8185
+ "li",
8186
+ {
8187
+ key: s,
8188
+ onClick: () => {
8189
+ setStatus(s);
8190
+ setIsStatusDropdownOpen(false);
8191
+ onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS2[s]);
8192
+ },
8193
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8007
8194
  },
8008
- /* @__PURE__ */ React15.createElement("option", { value: "Backlog" }, "Backlog"),
8009
- /* @__PURE__ */ React15.createElement("option", { value: "In Progress" }, "In Progress"),
8010
- /* @__PURE__ */ React15.createElement("option", { value: "Review" }, "Review"),
8011
- /* @__PURE__ */ React15.createElement("option", { value: "Done" }, "Done")
8012
- )), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ React15.createElement("input", { required: true, type: "text", placeholder: "Ex.: Refatorar M\xF3dulo X", value: name, onChange: (e) => setName(e.target.value), 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" })), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8195
+ /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8196
+ s
8197
+ )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8013
8198
  "input",
8014
8199
  {
8015
8200
  type: "text",
@@ -8032,7 +8217,20 @@ function InSceneQuestForm({
8032
8217
  onMentionClick,
8033
8218
  onSaveDescription: (newDesc) => setDescription(newDesc)
8034
8219
  }
8035
- ), /* @__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 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiEdit26, { size: 14 }))), !description && /* @__PURE__ */ React15.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Cen\xE1rio (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement("button", { key: s, type: "button", onClick: () => setSize(s), className: "flex items-center gap-2 group cursor-pointer focus:outline-none" }, /* @__PURE__ */ React15.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${size === s ? "bg-indigo-500 border-indigo-500" : "border-slate-600 bg-transparent group-hover:border-slate-500"}` }, size === s && /* @__PURE__ */ React15.createElement(FiCheck9, { size: 12, className: "text-white" })), /* @__PURE__ */ React15.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s))))), /* @__PURE__ */ React15.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React15.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiPlus5, { size: 14 }), " Adicionar")), /* @__PURE__ */ React15.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React15.createElement(
8220
+ ), /* @__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 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiEdit26, { size: 14 }))), !description && /* @__PURE__ */ React15.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement(
8221
+ "button",
8222
+ {
8223
+ key: s,
8224
+ type: "button",
8225
+ onClick: () => {
8226
+ setSize(s);
8227
+ onSizeChange == null ? void 0 : onSizeChange(s);
8228
+ },
8229
+ className: "flex items-center gap-2 group cursor-pointer focus:outline-none"
8230
+ },
8231
+ /* @__PURE__ */ React15.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${size === s ? "bg-indigo-500 border-indigo-500" : "border-slate-600 bg-transparent group-hover:border-slate-500"}` }, size === s && /* @__PURE__ */ React15.createElement(FiCheck9, { size: 12, className: "text-white" })),
8232
+ /* @__PURE__ */ React15.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s)
8233
+ )))), /* @__PURE__ */ React15.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React15.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiPlus5, { size: 14 }), " Adicionar")), /* @__PURE__ */ React15.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React15.createElement(
8036
8234
  CustomPropertyDisplay,
8037
8235
  {
8038
8236
  key: prop.id,
@@ -8547,136 +8745,475 @@ function NodeDetailsPanel({
8547
8745
  ));
8548
8746
  }
8549
8747
 
8550
- // src/components/MultiNodeContextMenu.jsx
8551
- import React17, { useLayoutEffect as useLayoutEffect3, useRef as useRef14, useState as useState18, useEffect as useEffect16 } from "react";
8552
- function MultiNodeContextMenu({
8553
- data,
8554
- userRole,
8555
- onClose,
8556
- onDismissNodes,
8557
- onDismissOtherNodes,
8558
- onDeleteNodes
8559
- }) {
8560
- const menuRef = useRef14(null);
8561
- const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
8562
- const [isConfirmingDelete, setIsConfirmingDelete] = useState18(false);
8563
- const ability = defineAbilityFor(userRole);
8564
- const canDelete = ability.can("delete", "Node");
8565
- useLayoutEffect3(() => {
8566
- if (!data.visible || !menuRef.current) return;
8567
- const el = menuRef.current;
8568
- const w = el.clientWidth;
8569
- const h = el.clientHeight;
8570
- const vw = window.innerWidth;
8571
- const vh = window.innerHeight;
8572
- let left = data.x + 8;
8573
- let top = data.y + 8;
8574
- if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
8575
- if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
8576
- setMenuPos({ left, top });
8577
- }, [data]);
8578
- useEffect16(() => {
8579
- if (data.visible) {
8580
- setIsConfirmingDelete(false);
8581
- }
8582
- const handleClickOutside = (e) => {
8583
- if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
8584
- };
8585
- document.addEventListener("mousedown", handleClickOutside);
8586
- return () => document.removeEventListener("mousedown", handleClickOutside);
8587
- }, [data.visible, onClose]);
8588
- if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
8589
- const swallow = (e) => e.stopPropagation();
8590
- const baseButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-indigo-500/20 text-slate-200 hover:text-white transition-colors duration-150 truncate";
8591
- const deleteButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-red-500/25 text-red-400 hover:text-red-300 transition-colors duration-150 truncate";
8592
- const nodeCount = data.nodeIds.size;
8593
- return /* @__PURE__ */ React17.createElement(
8594
- "div",
8595
- {
8596
- ref: menuRef,
8597
- className: "ui-overlay context-menu-class origin-top-left rounded-xl 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 w-[min(92vw,250px)] overflow-hidden",
8598
- style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
8599
- onPointerDown: swallow,
8600
- onPointerMove: swallow,
8601
- onPointerUp: swallow,
8602
- onClick: swallow,
8603
- onWheel: swallow,
8604
- onContextMenu: swallow,
8605
- onDoubleClick: swallow
8606
- },
8607
- /* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
8608
- /* @__PURE__ */ React17.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React17.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ React17.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__ */ React17.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React17.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__ */ React17.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React17.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ React17.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__ */ React17.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React17.createElement(
8609
- "button",
8610
- {
8611
- onClick: () => setIsConfirmingDelete(false),
8612
- className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
8613
- },
8614
- "Cancelar"
8615
- ), /* @__PURE__ */ React17.createElement(
8616
- "button",
8617
- {
8618
- onClick: () => onDeleteNodes(data.nodeIds),
8619
- className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
8620
- },
8621
- "Excluir"
8622
- ))) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React17.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__ */ React17.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React17.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React17.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__ */ React17.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React17.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__ */ React17.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__ */ React17.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React17.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ React17.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React17.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__ */ React17.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React17.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React17.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React17.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React17.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React17.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React17.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ React17.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__ */ React17.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React17.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__ */ React17.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React17.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React17.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
8623
- );
8624
- }
8625
-
8626
- // src/components/RelationshipDetailsPanel.jsx
8627
- import React18, { useState as useState19, useEffect as useEffect17, useRef as useRef15, useMemo as useMemo9 } from "react";
8628
- import { FiPlus as FiPlus7, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
8629
- function RelationshipDetailsPanel({
8630
- link,
8748
+ // src/components/QuestDetailsPanel.jsx
8749
+ import React17, { useState as useState18, useEffect as useEffect16, useRef as useRef14 } from "react";
8750
+ import { FiPlus as FiPlus7, FiX as FiX6, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink6, FiTarget as FiTarget2, FiChevronDown as FiChevronDown6 } from "react-icons/fi";
8751
+ var QUEST_STATUS_COLORS3 = {
8752
+ "Backlog": "#64748b",
8753
+ "In Progress": "#eab308",
8754
+ "Review": "#a855f7",
8755
+ "Done": "#22c55e"
8756
+ };
8757
+ function QuestDetailsPanel({
8758
+ node,
8631
8759
  onClose,
8632
8760
  onSave,
8761
+ onNameChange,
8762
+ onColorChange,
8763
+ onSizeChange,
8633
8764
  onDataUpdate,
8634
8765
  onOpenImageViewer,
8766
+ existingTypes = [],
8635
8767
  availableNodes = [],
8636
8768
  availableAncestries = [],
8637
8769
  onOpenReference,
8638
8770
  onMentionClick,
8639
8771
  onUploadFile,
8640
- userRole
8772
+ userRole,
8773
+ currentDatasetName
8641
8774
  }) {
8642
- const [name, setName] = useState19((link == null ? void 0 : link.name) ?? "");
8643
- const [description, setDescription] = useState19((link == null ? void 0 : link.description) ?? "");
8644
- const [customProps, setCustomProps] = useState19(() => extractCustomPropsFromNode(link || {}));
8645
- const [existingSections, setExistingSections] = useState19((link == null ? void 0 : link.description_sections) || []);
8646
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState19(false);
8647
- const [isSaving, setIsSaving] = useState19(false);
8648
- const [isReadMode, setIsReadMode] = useState19(false);
8649
- const propsEndRef = useRef15(null);
8650
- const canEdit = useMemo9(() => {
8651
- const ability = defineAbilityFor(userRole);
8652
- return ability.can("update", "Connection");
8653
- }, [userRole]);
8654
- useEffect17(() => {
8655
- setName((link == null ? void 0 : link.name) ?? "");
8656
- setDescription((link == null ? void 0 : link.description) ?? "");
8657
- setExistingSections((link == null ? void 0 : link.description_sections) || []);
8658
- setCustomProps(extractCustomPropsFromNode(link || {}));
8659
- }, [link]);
8660
- const swallow = (e) => e.stopPropagation();
8661
- const handleAddProp = () => {
8662
- if (!canEdit) return;
8663
- const newProp = createNewCustomProperty(customProps);
8664
- setCustomProps((p) => [...p, newProp]);
8665
- setTimeout(() => {
8666
- var _a;
8667
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
8668
- }, 100);
8669
- };
8670
- const handleSave = async (keepOpen = false, overrides = {}) => {
8671
- if (!canEdit) return;
8672
- const currentDescription = overrides.description !== void 0 ? overrides.description : description;
8673
- const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
8674
- const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
8675
- const currentName = overrides.name !== void 0 ? overrides.name : name;
8676
- setIsSaving(true);
8677
- try {
8678
- const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
8679
- const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
8775
+ var _a;
8776
+ const initialRawTitle = (node == null ? void 0 : node.raw_title) || (((_a = node == null ? void 0 : node.name) == null ? void 0 : _a.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
8777
+ const [rawTitle, setRawTitle] = useState18(initialRawTitle);
8778
+ const prefixParts = ((node == null ? void 0 : node.name) || "").split(" - \xBB ");
8779
+ const questPrefix = prefixParts.length > 1 ? prefixParts[0] : "";
8780
+ const standardizedName = questPrefix ? `${questPrefix} - \xBB ${rawTitle || "Sem t\xEDtulo"}` : rawTitle;
8781
+ const [types, setTypes] = useState18((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
8782
+ const [typeInput, setTypeInput] = useState18("");
8783
+ const [status, setStatus] = useState18((node == null ? void 0 : node.status) ?? "Backlog");
8784
+ const [size, setSize] = useState18((node == null ? void 0 : node.size) ?? "medium");
8785
+ const [description, setDescription] = useState18((node == null ? void 0 : node.description) ?? "");
8786
+ const [intensity, setIntensity] = useState18((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
8787
+ const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState18(false);
8788
+ const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(node || {}));
8789
+ const [showTypeSuggestions, setShowTypeSuggestions] = useState18(false);
8790
+ const [filteredTypes, setFilteredTypes] = useState18([]);
8791
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
8792
+ const [isReadMode, setIsReadMode] = useState18(false);
8793
+ const [existingSections, setExistingSections] = useState18((node == null ? void 0 : node.description_sections) || []);
8794
+ const [isSaving, setIsSaving] = useState18(false);
8795
+ const [isLinkCopied, setIsLinkCopied] = useState18(false);
8796
+ const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
8797
+ const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
8798
+ initialWidth: isReadMode ? 700 : 440,
8799
+ minWidth: 320,
8800
+ maxWidth: maxPanelW
8801
+ });
8802
+ useEffect16(() => {
8803
+ setWidth(isReadMode ? 700 : 440);
8804
+ }, [isReadMode, setWidth]);
8805
+ const prevNodeIdRef = useRef14(null);
8806
+ const propsEndRef = useRef14(null);
8807
+ const canEdit = userRole !== "viewer";
8808
+ const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
8809
+ const handleImageClickFromText = (url, name) => {
8810
+ if (onOpenImageViewer) {
8811
+ onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
8812
+ }
8813
+ };
8814
+ useEffect16(() => {
8815
+ var _a2;
8816
+ if ((node == null ? void 0 : node.id) !== prevNodeIdRef.current) {
8817
+ prevNodeIdRef.current = node == null ? void 0 : node.id;
8818
+ const newRawTitle = (node == null ? void 0 : node.raw_title) || (((_a2 = node == null ? void 0 : node.name) == null ? void 0 : _a2.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
8819
+ setRawTitle(newRawTitle);
8820
+ setTypes((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
8821
+ setStatus((node == null ? void 0 : node.status) ?? "Backlog");
8822
+ setSize((node == null ? void 0 : node.size) ?? "medium");
8823
+ setDescription((node == null ? void 0 : node.description) ?? "");
8824
+ setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
8825
+ setExistingSections((node == null ? void 0 : node.description_sections) || []);
8826
+ setCustomProps(extractCustomPropsFromNode(node || {}));
8827
+ }
8828
+ }, [node]);
8829
+ useEffect16(() => {
8830
+ if (typeInput.trim() === "") {
8831
+ setFilteredTypes(existingTypes.filter((t) => !types.includes(t)));
8832
+ } else {
8833
+ const lowercasedInput = typeInput.toLowerCase();
8834
+ setFilteredTypes(
8835
+ existingTypes.filter(
8836
+ (t) => t.toLowerCase().includes(lowercasedInput) && !types.includes(t)
8837
+ )
8838
+ );
8839
+ }
8840
+ }, [typeInput, existingTypes, types]);
8841
+ const handleCopyLink = () => {
8842
+ if (!(node == null ? void 0 : node.id)) return;
8843
+ const baseUrl = window.location.origin + window.location.pathname;
8844
+ const fullUrl = `${baseUrl}?focus=${node.id}`;
8845
+ navigator.clipboard.writeText(fullUrl).then(() => {
8846
+ setIsLinkCopied(true);
8847
+ setTimeout(() => setIsLinkCopied(false), 2e3);
8848
+ }).catch((err) => {
8849
+ console.error("Erro ao copiar link:", err);
8850
+ });
8851
+ };
8852
+ const swallow = (e) => e.stopPropagation();
8853
+ const handleNameChange = (e) => {
8854
+ const val = e.target.value;
8855
+ setRawTitle(val);
8856
+ const newStandardName = questPrefix ? `${questPrefix} - \xBB ${val || "Sem t\xEDtulo"}` : val;
8857
+ onNameChange == null ? void 0 : onNameChange(node.id, newStandardName, val);
8858
+ };
8859
+ const handleSizeChange = (newSize) => {
8860
+ setSize(newSize);
8861
+ onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
8862
+ };
8863
+ const handleStatusChange = (newStatus) => {
8864
+ setStatus(newStatus);
8865
+ const newColor = QUEST_STATUS_COLORS3[newStatus];
8866
+ onColorChange == null ? void 0 : onColorChange(node.id, newColor);
8867
+ onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
8868
+ };
8869
+ const handleAddType = (newType) => {
8870
+ const trimmed = newType.trim();
8871
+ if (trimmed && !types.includes(trimmed)) {
8872
+ setTypes([...types, trimmed]);
8873
+ setTypeInput("");
8874
+ setShowTypeSuggestions(false);
8875
+ }
8876
+ };
8877
+ const handleRemoveType = (indexToRemove) => {
8878
+ if (types[indexToRemove] === "quest") return;
8879
+ setTypes(types.filter((_, index) => index !== indexToRemove));
8880
+ };
8881
+ const handleTypeInputKeyDown = (e) => {
8882
+ if (e.key === "Enter") {
8883
+ e.preventDefault();
8884
+ handleAddType(typeInput);
8885
+ } else if (e.key === "Backspace" && typeInput === "" && types.length > 1) {
8886
+ handleRemoveType(types.length - 1);
8887
+ }
8888
+ };
8889
+ const handleAddProp = () => {
8890
+ const newProp = createNewCustomProperty(customProps);
8891
+ setCustomProps((p) => [...p, newProp]);
8892
+ setTimeout(() => {
8893
+ var _a2;
8894
+ (_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
8895
+ }, 100);
8896
+ };
8897
+ const handleRemoveProp = (i) => {
8898
+ const newProps = customProps.filter((_, idx) => idx !== i);
8899
+ setCustomProps(newProps);
8900
+ triggerAutoSave({ customProps: newProps });
8901
+ };
8902
+ const handleUpdateProp = (index, updatedProp) => {
8903
+ const newProps = [...customProps];
8904
+ newProps[index] = updatedProp;
8905
+ setCustomProps(newProps);
8906
+ if (!updatedProp.isEditing) {
8907
+ triggerAutoSave({ customProps: newProps });
8908
+ }
8909
+ };
8910
+ const handleSaveDescriptionInline = (newDescription) => {
8911
+ setDescription(newDescription);
8912
+ onDataUpdate({ ...node, description: newDescription });
8913
+ triggerAutoSave({ description: newDescription });
8914
+ };
8915
+ const handleSave = async (keepOpen = false, overrides = {}) => {
8916
+ const currentRawTitle = overrides.rawTitle !== void 0 ? overrides.rawTitle : rawTitle;
8917
+ const currentStandardName = questPrefix ? `${questPrefix} - \xBB ${currentRawTitle || "Sem t\xEDtulo"}` : currentRawTitle;
8918
+ const currentTypes = overrides.types !== void 0 ? overrides.types : types;
8919
+ const currentDescription = overrides.description !== void 0 ? overrides.description : description;
8920
+ const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
8921
+ const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
8922
+ const currentStatus = overrides.status !== void 0 ? overrides.status : status;
8923
+ if (!currentRawTitle.trim() || currentTypes.length === 0) {
8924
+ alert("O campo 'T\xEDtulo' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
8925
+ return;
8926
+ }
8927
+ setIsSaving(true);
8928
+ try {
8929
+ const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
8930
+ const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
8931
+ const dataToSave = {
8932
+ id: node.id,
8933
+ name: currentStandardName.trim(),
8934
+ // Salva o nome completo formatado
8935
+ raw_title: currentRawTitle.trim(),
8936
+ // Salva o título simples
8937
+ type: currentTypes,
8938
+ color: QUEST_STATUS_COLORS3[currentStatus],
8939
+ status: currentStatus,
8940
+ size,
8941
+ description: currentDescription,
8942
+ description_sections: processedSections,
8943
+ useImageAsTexture: false,
8944
+ textureImageUrl: null,
8945
+ intensity,
8946
+ is_quest: true,
8947
+ ...extrasObj,
8948
+ version_node: node.version_node
8949
+ };
8950
+ await onSave(dataToSave, keepOpen);
8951
+ onDataUpdate(dataToSave);
8952
+ if (!keepOpen) {
8953
+ onClose();
8954
+ }
8955
+ } finally {
8956
+ setIsSaving(false);
8957
+ }
8958
+ };
8959
+ const triggerAutoSave = (overrides = {}) => {
8960
+ handleSave(true, overrides);
8961
+ };
8962
+ const handleCancel = () => {
8963
+ if (node) {
8964
+ onNameChange == null ? void 0 : onNameChange(node.id, node.name);
8965
+ onColorChange == null ? void 0 : onColorChange(node.id, node.color);
8966
+ onSizeChange == null ? void 0 : onSizeChange(node.id, node.size || "medium");
8967
+ }
8968
+ onClose();
8969
+ };
8970
+ const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
8971
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(
8972
+ "div",
8973
+ {
8974
+ 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"}`,
8975
+ style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
8976
+ onPointerDown: swallow,
8977
+ onPointerMove: swallow,
8978
+ onPointerUp: swallow,
8979
+ onClick: swallow,
8980
+ onWheel: swallow,
8981
+ onContextMenu: swallow,
8982
+ onDoubleClick: swallow
8983
+ },
8984
+ /* @__PURE__ */ React17.createElement("div", { onPointerDown: (e) => {
8985
+ e.stopPropagation();
8986
+ handleResize(e);
8987
+ }, className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors", title: "Arraste para redimensionar" }),
8988
+ isReadMode ? /* @__PURE__ */ React17.createElement(
8989
+ DescriptionReadModePanel,
8990
+ {
8991
+ title: standardizedName || (node == null ? void 0 : node.name),
8992
+ description,
8993
+ savedSections: existingSections,
8994
+ onBack: () => setIsReadMode(false),
8995
+ onEdit: () => {
8996
+ if (canEdit) {
8997
+ setIsReadMode(false);
8998
+ setIsDescriptionModalOpen(true);
8999
+ }
9000
+ },
9001
+ onClose: handleCancel,
9002
+ availableNodes,
9003
+ availableAncestries,
9004
+ onOpenReference,
9005
+ onMentionClick,
9006
+ onImageClick: handleImageClickFromText,
9007
+ onSaveDescription: handleSaveDescriptionInline
9008
+ }
9009
+ ) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__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(FiTarget2, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ React17.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ React17.createElement(FiCheck11, { size: 12 }) : /* @__PURE__ */ React17.createElement(FiLink6, { size: 12 }))), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ React17.createElement("button", { onClick: handleCancel, 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: "Cancelar" }, "\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" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React17.createElement(
9010
+ "input",
9011
+ {
9012
+ type: "text",
9013
+ value: rawTitle,
9014
+ onChange: handleNameChange,
9015
+ readOnly: !canEdit,
9016
+ className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}`
9017
+ }
9018
+ ), /* @__PURE__ */ React17.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ React17.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, /* @__PURE__ */ React17.createElement(
9019
+ "button",
9020
+ {
9021
+ type: "button",
9022
+ onClick: () => canEdit && setIsStatusDropdownOpen(!isStatusDropdownOpen),
9023
+ disabled: !canEdit,
9024
+ className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 transition-colors flex items-center justify-between ${canEdit ? "hover:border-white/20 focus:ring-2 focus:ring-indigo-400/60 cursor-pointer" : "cursor-default opacity-80"}`
9025
+ },
9026
+ /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS3[status] } }), /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, status)),
9027
+ canEdit && /* @__PURE__ */ React17.createElement(FiChevronDown6, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
9028
+ ), isStatusDropdownOpen && canEdit && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React17.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS3).map((s) => /* @__PURE__ */ React17.createElement(
9029
+ "li",
9030
+ {
9031
+ key: s,
9032
+ onClick: () => {
9033
+ handleStatusChange(s);
9034
+ setIsStatusDropdownOpen(false);
9035
+ },
9036
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9037
+ },
9038
+ /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
9039
+ s
9040
+ )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
9041
+ "input",
9042
+ {
9043
+ type: "text",
9044
+ value: typeInput,
9045
+ onChange: (e) => {
9046
+ setTypeInput(e.target.value);
9047
+ setShowTypeSuggestions(true);
9048
+ },
9049
+ onKeyDown: handleTypeInputKeyDown,
9050
+ onClick: () => setShowTypeSuggestions(true),
9051
+ onBlur: () => {
9052
+ if (typeInput.trim()) {
9053
+ handleAddType(typeInput);
9054
+ }
9055
+ setTimeout(() => setShowTypeSuggestions(false), 150);
9056
+ },
9057
+ className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
9058
+ placeholder: "",
9059
+ autoComplete: "off"
9060
+ }
9061
+ ), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React17.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ React17.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
9062
+ e.preventDefault();
9063
+ handleAddType(suggestedType);
9064
+ } }, suggestedType))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React17.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__ */ React17.createElement(DescriptionDisplay, { description, savedSections: existingSections, availableNodes, availableAncestries, onOpenReference, onMentionClick, onImageClick: handleImageClickFromText, onSaveDescription: handleSaveDescriptionInline }), /* @__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("button", { type: "button", onClick: () => setIsReadMode(true), className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`, title: "Modo de Leitura" }, /* @__PURE__ */ React17.createElement(FiBookOpen4, { size: 14 })), canEdit && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors", title: "Editar descri\xE7\xE3o (Modo de Escrita)" }, /* @__PURE__ */ React17.createElement(FiEdit28, { size: 14 }))), canEdit && !description && /* @__PURE__ */ React17.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
9065
+ const isSelected = size === s;
9066
+ return /* @__PURE__ */ React17.createElement("button", { key: s, type: "button", onClick: () => canEdit && handleSizeChange(s), className: `flex items-center gap-2 group focus:outline-none ${canEdit ? "cursor-pointer" : "cursor-default opacity-80"}` }, /* @__PURE__ */ React17.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${isSelected ? "bg-indigo-500 border-indigo-500 shadow-[0_0_10px_rgba(99,102,241,0.4)]" : "border-slate-600 bg-transparent " + (canEdit ? "group-hover:border-slate-500" : "")}` }, isSelected && /* @__PURE__ */ React17.createElement(FiCheck11, { size: 12, className: "text-white" })), /* @__PURE__ */ React17.createElement("span", { className: `text-sm capitalize transition-colors ${isSelected ? "text-white font-medium" : "text-slate-400 " + (canEdit ? "group-hover:text-slate-300" : "")}` }, s));
9067
+ }))), /* @__PURE__ */ React17.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React17.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React17.createElement(FiPlus7, { size: 14 }), " Adicionar")), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React17.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ React17.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React17.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__ */ React17.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React17.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__ */ React17.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__ */ React17.createElement("button", { onClick: () => handleSave(false), disabled: isSaving, className: `px-4 py-2 rounded-lg transition-all font-semibold text-sm shadow-[0_8px_24px_rgba(99,102,241,0.35)] flex items-center gap-2 ${isSaving ? "bg-slate-700 text-slate-300 cursor-wait" : "bg-gradient-to-tr from-indigo-600 to-indigo-400 hover:from-indigo-500 hover:to-indigo-300 text-white"}` }, isSaving && /* @__PURE__ */ React17.createElement(FiLoader3, { className: "animate-spin" }), isSaving ? "Salvando..." : "Salvar Quest")))
9068
+ ), isDescriptionModalOpen && canEdit && /* @__PURE__ */ React17.createElement(
9069
+ DescriptionEditModal,
9070
+ {
9071
+ isOpen: isDescriptionModalOpen,
9072
+ title: "Editar Descri\xE7\xE3o da Quest",
9073
+ initialValue: description,
9074
+ onSave: (newDescription) => {
9075
+ setDescription(newDescription);
9076
+ onDataUpdate((prev) => ({ ...prev, description: newDescription }));
9077
+ triggerAutoSave({ description: newDescription });
9078
+ },
9079
+ onClose: () => setIsDescriptionModalOpen(false),
9080
+ availableNodes,
9081
+ availableAncestries,
9082
+ availableImages
9083
+ }
9084
+ ));
9085
+ }
9086
+
9087
+ // src/components/MultiNodeContextMenu.jsx
9088
+ import React18, { useLayoutEffect as useLayoutEffect3, useRef as useRef15, useState as useState19, useEffect as useEffect17 } from "react";
9089
+ function MultiNodeContextMenu({
9090
+ data,
9091
+ userRole,
9092
+ onClose,
9093
+ onDismissNodes,
9094
+ onDismissOtherNodes,
9095
+ onDeleteNodes
9096
+ }) {
9097
+ const menuRef = useRef15(null);
9098
+ const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
9099
+ const [isConfirmingDelete, setIsConfirmingDelete] = useState19(false);
9100
+ const ability = defineAbilityFor(userRole);
9101
+ const canDelete = ability.can("delete", "Node");
9102
+ useLayoutEffect3(() => {
9103
+ if (!data.visible || !menuRef.current) return;
9104
+ const el = menuRef.current;
9105
+ const w = el.clientWidth;
9106
+ const h = el.clientHeight;
9107
+ const vw = window.innerWidth;
9108
+ const vh = window.innerHeight;
9109
+ let left = data.x + 8;
9110
+ let top = data.y + 8;
9111
+ if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
9112
+ if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
9113
+ setMenuPos({ left, top });
9114
+ }, [data]);
9115
+ useEffect17(() => {
9116
+ if (data.visible) {
9117
+ setIsConfirmingDelete(false);
9118
+ }
9119
+ const handleClickOutside = (e) => {
9120
+ if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
9121
+ };
9122
+ document.addEventListener("mousedown", handleClickOutside);
9123
+ return () => document.removeEventListener("mousedown", handleClickOutside);
9124
+ }, [data.visible, onClose]);
9125
+ if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
9126
+ const swallow = (e) => e.stopPropagation();
9127
+ const baseButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-indigo-500/20 text-slate-200 hover:text-white transition-colors duration-150 truncate";
9128
+ const deleteButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-red-500/25 text-red-400 hover:text-red-300 transition-colors duration-150 truncate";
9129
+ const nodeCount = data.nodeIds.size;
9130
+ return /* @__PURE__ */ React18.createElement(
9131
+ "div",
9132
+ {
9133
+ ref: menuRef,
9134
+ className: "ui-overlay context-menu-class origin-top-left rounded-xl 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 w-[min(92vw,250px)] overflow-hidden",
9135
+ style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
9136
+ onPointerDown: swallow,
9137
+ onPointerMove: swallow,
9138
+ onPointerUp: swallow,
9139
+ onClick: swallow,
9140
+ onWheel: swallow,
9141
+ onContextMenu: swallow,
9142
+ onDoubleClick: swallow
9143
+ },
9144
+ /* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
9145
+ /* @__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-red-500/20 flex items-center justify-center text-red-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 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__ */ React18.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React18.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React18.createElement(
9146
+ "button",
9147
+ {
9148
+ onClick: () => setIsConfirmingDelete(false),
9149
+ className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
9150
+ },
9151
+ "Cancelar"
9152
+ ), /* @__PURE__ */ React18.createElement(
9153
+ "button",
9154
+ {
9155
+ onClick: () => onDeleteNodes(data.nodeIds),
9156
+ className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
9157
+ },
9158
+ "Excluir"
9159
+ ))) : /* @__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-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React18.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React18.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React18.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__ */ React18.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React18.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__ */ React18.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__ */ React18.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React18.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ React18.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React18.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__ */ React18.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React18.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React18.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React18.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React18.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React18.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React18.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ React18.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__ */ React18.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React18.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__ */ React18.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React18.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React18.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
9160
+ );
9161
+ }
9162
+
9163
+ // src/components/RelationshipDetailsPanel.jsx
9164
+ import React19, { useState as useState20, useEffect as useEffect18, useRef as useRef16, useMemo as useMemo9 } from "react";
9165
+ import { FiPlus as FiPlus8, FiEdit2 as FiEdit29, FiLoader as FiLoader4, FiBookOpen as FiBookOpen5 } from "react-icons/fi";
9166
+ function RelationshipDetailsPanel({
9167
+ link,
9168
+ onClose,
9169
+ onSave,
9170
+ onDataUpdate,
9171
+ onOpenImageViewer,
9172
+ availableNodes = [],
9173
+ availableAncestries = [],
9174
+ onOpenReference,
9175
+ onMentionClick,
9176
+ onUploadFile,
9177
+ userRole
9178
+ }) {
9179
+ const [name, setName] = useState20((link == null ? void 0 : link.name) ?? "");
9180
+ const [description, setDescription] = useState20((link == null ? void 0 : link.description) ?? "");
9181
+ const [customProps, setCustomProps] = useState20(() => extractCustomPropsFromNode(link || {}));
9182
+ const [existingSections, setExistingSections] = useState20((link == null ? void 0 : link.description_sections) || []);
9183
+ const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState20(false);
9184
+ const [isSaving, setIsSaving] = useState20(false);
9185
+ const [isReadMode, setIsReadMode] = useState20(false);
9186
+ const propsEndRef = useRef16(null);
9187
+ const canEdit = useMemo9(() => {
9188
+ const ability = defineAbilityFor(userRole);
9189
+ return ability.can("update", "Connection");
9190
+ }, [userRole]);
9191
+ useEffect18(() => {
9192
+ setName((link == null ? void 0 : link.name) ?? "");
9193
+ setDescription((link == null ? void 0 : link.description) ?? "");
9194
+ setExistingSections((link == null ? void 0 : link.description_sections) || []);
9195
+ setCustomProps(extractCustomPropsFromNode(link || {}));
9196
+ }, [link]);
9197
+ const swallow = (e) => e.stopPropagation();
9198
+ const handleAddProp = () => {
9199
+ if (!canEdit) return;
9200
+ const newProp = createNewCustomProperty(customProps);
9201
+ setCustomProps((p) => [...p, newProp]);
9202
+ setTimeout(() => {
9203
+ var _a;
9204
+ (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
9205
+ }, 100);
9206
+ };
9207
+ const handleSave = async (keepOpen = false, overrides = {}) => {
9208
+ if (!canEdit) return;
9209
+ const currentDescription = overrides.description !== void 0 ? overrides.description : description;
9210
+ const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
9211
+ const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
9212
+ const currentName = overrides.name !== void 0 ? overrides.name : name;
9213
+ setIsSaving(true);
9214
+ try {
9215
+ const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
9216
+ const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
8680
9217
  const dataToSave = {
8681
9218
  id: link.id,
8682
9219
  source: link.source,
@@ -8726,7 +9263,7 @@ function RelationshipDetailsPanel({
8726
9263
  onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
8727
9264
  }
8728
9265
  };
8729
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
9266
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
8730
9267
  "div",
8731
9268
  {
8732
9269
  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
@@ -8741,7 +9278,7 @@ function RelationshipDetailsPanel({
8741
9278
  onContextMenu: swallow,
8742
9279
  onDoubleClick: swallow
8743
9280
  },
8744
- isReadMode ? /* @__PURE__ */ React18.createElement(
9281
+ isReadMode ? /* @__PURE__ */ React19.createElement(
8745
9282
  DescriptionReadModePanel,
8746
9283
  {
8747
9284
  title: name || "Rela\xE7\xE3o",
@@ -8762,7 +9299,7 @@ function RelationshipDetailsPanel({
8762
9299
  onImageClick: handleImageClickFromText,
8763
9300
  onSaveDescription: handleSaveDescriptionInline
8764
9301
  }
8765
- ) : /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React18.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React18.createElement("div", null, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React18.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__ */ React18.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React18.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React18.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React18.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React18.createElement(
9302
+ ) : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React19.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React19.createElement("div", null, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React19.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__ */ React19.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React19.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React19.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__ */ React19.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React19.createElement(
8766
9303
  "input",
8767
9304
  {
8768
9305
  type: "text",
@@ -8774,7 +9311,7 @@ function RelationshipDetailsPanel({
8774
9311
  ${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
8775
9312
  `
8776
9313
  }
8777
- )), /* @__PURE__ */ React18.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React18.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React18.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__ */ React18.createElement(
9314
+ )), /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React19.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__ */ React19.createElement(
8778
9315
  DescriptionDisplay,
8779
9316
  {
8780
9317
  description,
@@ -8786,7 +9323,7 @@ function RelationshipDetailsPanel({
8786
9323
  onImageClick: handleImageClickFromText,
8787
9324
  onSaveDescription: handleSaveDescriptionInline
8788
9325
  }
8789
- ), /* @__PURE__ */ React18.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__ */ React18.createElement(
9326
+ ), /* @__PURE__ */ React19.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__ */ React19.createElement(
8790
9327
  "button",
8791
9328
  {
8792
9329
  type: "button",
@@ -8794,8 +9331,8 @@ function RelationshipDetailsPanel({
8794
9331
  className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors border-r border-white/5",
8795
9332
  title: "Modo de Leitura"
8796
9333
  },
8797
- /* @__PURE__ */ React18.createElement(FiBookOpen4, { size: 14 })
8798
- ), canEdit && /* @__PURE__ */ React18.createElement(
9334
+ /* @__PURE__ */ React19.createElement(FiBookOpen5, { size: 14 })
9335
+ ), canEdit && /* @__PURE__ */ React19.createElement(
8799
9336
  "button",
8800
9337
  {
8801
9338
  type: "button",
@@ -8803,15 +9340,15 @@ function RelationshipDetailsPanel({
8803
9340
  className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
8804
9341
  title: "Editar descri\xE7\xE3o"
8805
9342
  },
8806
- /* @__PURE__ */ React18.createElement(FiEdit28, { size: 14 })
8807
- )), !description && canEdit && /* @__PURE__ */ React18.createElement(
9343
+ /* @__PURE__ */ React19.createElement(FiEdit29, { size: 14 })
9344
+ )), !description && canEdit && /* @__PURE__ */ React19.createElement(
8808
9345
  "div",
8809
9346
  {
8810
9347
  onClick: () => setIsDescriptionModalOpen(true),
8811
9348
  className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
8812
9349
  },
8813
9350
  "Adicionar descri\xE7\xE3o..."
8814
- ))), /* @__PURE__ */ React18.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React18.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React18.createElement(FiPlus7, { size: 14 }), " Adicionar")), /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React18.createElement(
9351
+ ))), /* @__PURE__ */ React19.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React19.createElement(FiPlus8, { size: 14 }), " Adicionar")), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React19.createElement(
8815
9352
  CustomPropertyDisplay,
8816
9353
  {
8817
9354
  key: prop.id,
@@ -8823,7 +9360,7 @@ function RelationshipDetailsPanel({
8823
9360
  onUploadFile,
8824
9361
  disabled: !canEdit
8825
9362
  }
8826
- )), /* @__PURE__ */ React18.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React18.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__ */ React18.createElement("button", { onClick: onClose, 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__ */ React18.createElement(
9363
+ )), /* @__PURE__ */ React19.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React19.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__ */ React19.createElement("button", { onClick: onClose, 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__ */ React19.createElement(
8827
9364
  "button",
8828
9365
  {
8829
9366
  onClick: () => handleSave(false),
@@ -8832,10 +9369,10 @@ function RelationshipDetailsPanel({
8832
9369
  ${isSaving ? "bg-slate-700 text-slate-300 cursor-wait" : "bg-gradient-to-tr from-teal-600 to-teal-400 hover:from-teal-500 hover:to-teal-300 text-white"}
8833
9370
  `
8834
9371
  },
8835
- isSaving && /* @__PURE__ */ React18.createElement(FiLoader3, { className: "animate-spin" }),
9372
+ isSaving && /* @__PURE__ */ React19.createElement(FiLoader4, { className: "animate-spin" }),
8836
9373
  isSaving ? "Salvando..." : "Salvar"
8837
9374
  )))
8838
- ), isDescriptionModalOpen && /* @__PURE__ */ React18.createElement(
9375
+ ), isDescriptionModalOpen && /* @__PURE__ */ React19.createElement(
8839
9376
  DescriptionEditModal,
8840
9377
  {
8841
9378
  isOpen: isDescriptionModalOpen,
@@ -8856,7 +9393,7 @@ function RelationshipDetailsPanel({
8856
9393
  }
8857
9394
 
8858
9395
  // src/components/RelationshipContextMenu.jsx
8859
- import React19, { useLayoutEffect as useLayoutEffect4, useRef as useRef16, useState as useState20, useEffect as useEffect18, useMemo as useMemo10 } from "react";
9396
+ import React20, { useLayoutEffect as useLayoutEffect4, useRef as useRef17, useState as useState21, useEffect as useEffect19, useMemo as useMemo10 } from "react";
8860
9397
  function RelationshipContextMenu({
8861
9398
  data,
8862
9399
  userRole,
@@ -8866,9 +9403,9 @@ function RelationshipContextMenu({
8866
9403
  onDelete,
8867
9404
  onClose
8868
9405
  }) {
8869
- const menuRef = useRef16(null);
8870
- const [menuPos, setMenuPos] = useState20({ left: 0, top: 0 });
8871
- const [isConfirmingDelete, setIsConfirmingDelete] = useState20(false);
9406
+ const menuRef = useRef17(null);
9407
+ const [menuPos, setMenuPos] = useState21({ left: 0, top: 0 });
9408
+ const [isConfirmingDelete, setIsConfirmingDelete] = useState21(false);
8872
9409
  const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
8873
9410
  const sourceName = useMemo10(
8874
9411
  () => {
@@ -8897,7 +9434,7 @@ function RelationshipContextMenu({
8897
9434
  if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
8898
9435
  setMenuPos({ left, top });
8899
9436
  }, [data]);
8900
- useEffect18(() => {
9437
+ useEffect19(() => {
8901
9438
  if (data.visible) {
8902
9439
  setIsConfirmingDelete(false);
8903
9440
  }
@@ -8913,7 +9450,7 @@ function RelationshipContextMenu({
8913
9450
  const dangerButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-rose-500/20 text-rose-300 hover:text-rose-100 transition-colors duration-150 truncate";
8914
9451
  const canUpdate = ability.can("update", "Connection");
8915
9452
  const canDelete = ability.can("delete", "Connection");
8916
- return /* @__PURE__ */ React19.createElement(
9453
+ return /* @__PURE__ */ React20.createElement(
8917
9454
  "div",
8918
9455
  {
8919
9456
  ref: menuRef,
@@ -8927,29 +9464,29 @@ function RelationshipContextMenu({
8927
9464
  onContextMenu: swallow,
8928
9465
  onDoubleClick: swallow
8929
9466
  },
8930
- /* @__PURE__ */ React19.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
8931
- /* @__PURE__ */ React19.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React19.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ React19.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__ */ React19.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React19.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ React19.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ React19.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ React19.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React19.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ React19.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ React19.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ React19.createElement("strong", null, targetName), ".")), /* @__PURE__ */ React19.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React19.createElement(
9467
+ /* @__PURE__ */ React20.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
9468
+ /* @__PURE__ */ React20.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React20.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ React20.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__ */ React20.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React20.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ React20.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ React20.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ React20.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React20.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ React20.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ React20.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ React20.createElement("strong", null, targetName), ".")), /* @__PURE__ */ React20.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React20.createElement(
8932
9469
  "button",
8933
9470
  {
8934
9471
  onClick: () => setIsConfirmingDelete(false),
8935
9472
  className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
8936
9473
  },
8937
9474
  "Cancelar"
8938
- ), /* @__PURE__ */ React19.createElement(
9475
+ ), /* @__PURE__ */ React20.createElement(
8939
9476
  "button",
8940
9477
  {
8941
9478
  onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
8942
9479
  className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
8943
9480
  },
8944
9481
  "Excluir"
8945
- ))) : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React19.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__ */ React19.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
9482
+ ))) : /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React20.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__ */ React20.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(
8946
9483
  "button",
8947
9484
  {
8948
9485
  onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
8949
9486
  className: baseButtonClass,
8950
9487
  title: "Desconectar ponta ligada ao Source"
8951
9488
  },
8952
- /* @__PURE__ */ React19.createElement(
9489
+ /* @__PURE__ */ React20.createElement(
8953
9490
  "svg",
8954
9491
  {
8955
9492
  xmlns: "http://www.w3.org/2000/svg",
@@ -8962,18 +9499,18 @@ function RelationshipContextMenu({
8962
9499
  strokeLinecap: "round",
8963
9500
  strokeLinejoin: "round"
8964
9501
  },
8965
- /* @__PURE__ */ React19.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" }),
8966
- /* @__PURE__ */ React19.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" })
9502
+ /* @__PURE__ */ React20.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" }),
9503
+ /* @__PURE__ */ React20.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" })
8967
9504
  ),
8968
- /* @__PURE__ */ React19.createElement("span", null, "Desconectar Source (", sourceName, ")")
8969
- ), /* @__PURE__ */ React19.createElement(
9505
+ /* @__PURE__ */ React20.createElement("span", null, "Desconectar Source (", sourceName, ")")
9506
+ ), /* @__PURE__ */ React20.createElement(
8970
9507
  "button",
8971
9508
  {
8972
9509
  onClick: () => onRelinkTarget == null ? void 0 : onRelinkTarget(data.linkObject),
8973
9510
  className: baseButtonClass,
8974
9511
  title: "Desconectar ponta ligada ao Target"
8975
9512
  },
8976
- /* @__PURE__ */ React19.createElement(
9513
+ /* @__PURE__ */ React20.createElement(
8977
9514
  "svg",
8978
9515
  {
8979
9516
  xmlns: "http://www.w3.org/2000/svg",
@@ -8986,21 +9523,21 @@ function RelationshipContextMenu({
8986
9523
  strokeLinecap: "round",
8987
9524
  strokeLinejoin: "round"
8988
9525
  },
8989
- /* @__PURE__ */ React19.createElement("polyline", { points: "16 3 21 3 21 8" }),
8990
- /* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
8991
- /* @__PURE__ */ React19.createElement("polyline", { points: "21 16 21 21 16 21" }),
8992
- /* @__PURE__ */ React19.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
8993
- /* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
9526
+ /* @__PURE__ */ React20.createElement("polyline", { points: "16 3 21 3 21 8" }),
9527
+ /* @__PURE__ */ React20.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
9528
+ /* @__PURE__ */ React20.createElement("polyline", { points: "21 16 21 21 16 21" }),
9529
+ /* @__PURE__ */ React20.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
9530
+ /* @__PURE__ */ React20.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
8994
9531
  ),
8995
- /* @__PURE__ */ React19.createElement("span", null, "Desconectar Target (", targetName, ")")
8996
- ), /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ React19.createElement(
9532
+ /* @__PURE__ */ React20.createElement("span", null, "Desconectar Target (", targetName, ")")
9533
+ ), /* @__PURE__ */ React20.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ React20.createElement(
8997
9534
  "button",
8998
9535
  {
8999
9536
  onClick: () => onOpenDetails == null ? void 0 : onOpenDetails(data.linkObject),
9000
9537
  className: baseButtonClass,
9001
9538
  title: "Abrir detalhes da rela\xE7\xE3o"
9002
9539
  },
9003
- /* @__PURE__ */ React19.createElement(
9540
+ /* @__PURE__ */ React20.createElement(
9004
9541
  "svg",
9005
9542
  {
9006
9543
  xmlns: "http://www.w3.org/2000/svg",
@@ -9013,19 +9550,19 @@ function RelationshipContextMenu({
9013
9550
  strokeLinecap: "round",
9014
9551
  strokeLinejoin: "round"
9015
9552
  },
9016
- /* @__PURE__ */ React19.createElement("circle", { cx: "12", cy: "12", r: "10" }),
9017
- /* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
9018
- /* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
9553
+ /* @__PURE__ */ React20.createElement("circle", { cx: "12", cy: "12", r: "10" }),
9554
+ /* @__PURE__ */ React20.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
9555
+ /* @__PURE__ */ React20.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
9019
9556
  ),
9020
- /* @__PURE__ */ React19.createElement("span", null, "Abrir Detalhes")
9021
- ), canDelete && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React19.createElement(
9557
+ /* @__PURE__ */ React20.createElement("span", null, "Abrir Detalhes")
9558
+ ), canDelete && /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React20.createElement(
9022
9559
  "button",
9023
9560
  {
9024
9561
  onClick: () => setIsConfirmingDelete(true),
9025
9562
  className: dangerButtonClass,
9026
9563
  title: "Excluir esta conex\xE3o"
9027
9564
  },
9028
- /* @__PURE__ */ React19.createElement(
9565
+ /* @__PURE__ */ React20.createElement(
9029
9566
  "svg",
9030
9567
  {
9031
9568
  xmlns: "http://www.w3.org/2000/svg",
@@ -9038,19 +9575,19 @@ function RelationshipContextMenu({
9038
9575
  strokeLinecap: "round",
9039
9576
  strokeLinejoin: "round"
9040
9577
  },
9041
- /* @__PURE__ */ React19.createElement("polyline", { points: "3 6 5 6 21 6" }),
9042
- /* @__PURE__ */ React19.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
9043
- /* @__PURE__ */ React19.createElement("path", { d: "M10 11v6" }),
9044
- /* @__PURE__ */ React19.createElement("path", { d: "M14 11v6" }),
9045
- /* @__PURE__ */ React19.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
9578
+ /* @__PURE__ */ React20.createElement("polyline", { points: "3 6 5 6 21 6" }),
9579
+ /* @__PURE__ */ React20.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
9580
+ /* @__PURE__ */ React20.createElement("path", { d: "M10 11v6" }),
9581
+ /* @__PURE__ */ React20.createElement("path", { d: "M14 11v6" }),
9582
+ /* @__PURE__ */ React20.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
9046
9583
  ),
9047
- /* @__PURE__ */ React19.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
9584
+ /* @__PURE__ */ React20.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
9048
9585
  )))))
9049
9586
  );
9050
9587
  }
9051
9588
 
9052
9589
  // src/components/LoadingScreen.jsx
9053
- import React20 from "react";
9590
+ import React21 from "react";
9054
9591
  var styles = {
9055
9592
  loadingOverlay: {
9056
9593
  position: "fixed",
@@ -9082,11 +9619,11 @@ var styles = {
9082
9619
  `
9083
9620
  };
9084
9621
  function LoadingScreen() {
9085
- return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("style", null, styles.keyframes), /* @__PURE__ */ React20.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ React20.createElement("div", { style: styles.spinner })));
9622
+ return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement("style", null, styles.keyframes), /* @__PURE__ */ React21.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ React21.createElement("div", { style: styles.spinner })));
9086
9623
  }
9087
9624
 
9088
9625
  // src/components/ImportParentFileModal.jsx
9089
- import React21, { useEffect as useEffect19, useState as useState21 } from "react";
9626
+ import React22, { useEffect as useEffect20, useState as useState22 } from "react";
9090
9627
  function ImportParentFileModal({
9091
9628
  isOpen,
9092
9629
  onClose,
@@ -9097,12 +9634,12 @@ function ImportParentFileModal({
9097
9634
  onFetchAvailableFiles,
9098
9635
  currentViewName
9099
9636
  }) {
9100
- const [activeTab, setActiveTab] = useState21("databases");
9101
- const [availableDbs, setAvailableDbs] = useState21([]);
9102
- const [availableViews, setAvailableViews] = useState21([]);
9103
- const [selectedItem, setSelectedItem] = useState21(null);
9104
- const [isLoading, setIsLoading] = useState21(false);
9105
- useEffect19(() => {
9637
+ const [activeTab, setActiveTab] = useState22("databases");
9638
+ const [availableDbs, setAvailableDbs] = useState22([]);
9639
+ const [availableViews, setAvailableViews] = useState22([]);
9640
+ const [selectedItem, setSelectedItem] = useState22(null);
9641
+ const [isLoading, setIsLoading] = useState22(false);
9642
+ useEffect20(() => {
9106
9643
  if (isOpen && session && onFetchAvailableFiles) {
9107
9644
  const fetchData = async () => {
9108
9645
  setIsLoading(true);
@@ -9138,7 +9675,7 @@ function ImportParentFileModal({
9138
9675
  fetchData();
9139
9676
  }
9140
9677
  }, [isOpen, session, parentDbs, onFetchAvailableFiles, currentViewName]);
9141
- useEffect19(() => {
9678
+ useEffect20(() => {
9142
9679
  setSelectedItem(null);
9143
9680
  }, [activeTab]);
9144
9681
  if (!isOpen) {
@@ -9167,13 +9704,13 @@ function ImportParentFileModal({
9167
9704
  const swallow = (e) => e.stopPropagation();
9168
9705
  const currentList = activeTab === "databases" ? availableDbs : availableViews;
9169
9706
  const emptyMessage = activeTab === "databases" ? "Nenhum novo arquivo parent dispon\xEDvel." : "Nenhuma view dispon\xEDvel para importa\xE7\xE3o.";
9170
- return /* @__PURE__ */ React21.createElement(
9707
+ return /* @__PURE__ */ React22.createElement(
9171
9708
  "div",
9172
9709
  {
9173
9710
  className: "ui-overlay fixed inset-0 z-[1200] flex items-center justify-center bg-black/60 backdrop-blur-sm",
9174
9711
  onClick: onClose
9175
9712
  },
9176
- /* @__PURE__ */ React21.createElement(
9713
+ /* @__PURE__ */ React22.createElement(
9177
9714
  "div",
9178
9715
  {
9179
9716
  className: "ui-overlay relative rounded-2xl border border-white/10 bg-slate-950/80 shadow-[0_20px_80px_rgba(0,0,0,0.6)] text-white w-[min(92vw,500px)] flex flex-col max-h-[85vh]",
@@ -9185,14 +9722,14 @@ function ImportParentFileModal({
9185
9722
  onContextMenu: swallow,
9186
9723
  onDoubleClick: swallow
9187
9724
  },
9188
- /* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ React21.createElement(
9725
+ /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ React22.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ React22.createElement(
9189
9726
  "button",
9190
9727
  {
9191
9728
  onClick: onClose,
9192
9729
  className: "p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
9193
9730
  title: "Fechar"
9194
9731
  },
9195
- /* @__PURE__ */ React21.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React21.createElement(
9732
+ /* @__PURE__ */ React22.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React22.createElement(
9196
9733
  "path",
9197
9734
  {
9198
9735
  fillRule: "evenodd",
@@ -9201,14 +9738,14 @@ function ImportParentFileModal({
9201
9738
  }
9202
9739
  ))
9203
9740
  )),
9204
- /* @__PURE__ */ React21.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ React21.createElement(
9741
+ /* @__PURE__ */ React22.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ React22.createElement(
9205
9742
  "button",
9206
9743
  {
9207
9744
  onClick: () => setActiveTab("databases"),
9208
9745
  className: `flex-1 py-3 text-sm font-medium border-b-2 transition-colors ${activeTab === "databases" ? "border-indigo-500 text-white" : "border-transparent text-slate-400 hover:text-slate-200"}`
9209
9746
  },
9210
9747
  "Arquivos Parent"
9211
- ), /* @__PURE__ */ React21.createElement(
9748
+ ), /* @__PURE__ */ React22.createElement(
9212
9749
  "button",
9213
9750
  {
9214
9751
  onClick: () => setActiveTab("views"),
@@ -9216,24 +9753,24 @@ function ImportParentFileModal({
9216
9753
  },
9217
9754
  "Views (Ancestralidades)"
9218
9755
  )),
9219
- /* @__PURE__ */ React21.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ React21.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ React21.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ React21.createElement(
9756
+ /* @__PURE__ */ React22.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ React22.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ React22.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ React22.createElement(
9220
9757
  "div",
9221
9758
  {
9222
9759
  key: item.id,
9223
9760
  onClick: () => setSelectedItem(item),
9224
9761
  className: `px-4 py-3 rounded-lg border cursor-pointer transition-all duration-150 flex flex-col gap-1 ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "bg-indigo-600 border-indigo-500 shadow-lg" : "bg-slate-800/60 border-white/10 hover:border-white/20 hover:bg-slate-800"}`
9225
9762
  },
9226
- /* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React21.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ React21.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-black/30 text-indigo-300 border border-indigo-500/30" }, "VIEW")),
9227
- item.description && /* @__PURE__ */ React21.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
9228
- )) : /* @__PURE__ */ React21.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
9229
- /* @__PURE__ */ React21.createElement("div", { className: "px-6 py-4 border-t border-white/10 flex justify-end gap-3 flex-shrink-0 bg-slate-900/50" }, /* @__PURE__ */ React21.createElement(
9763
+ /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React22.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ React22.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-black/30 text-indigo-300 border border-indigo-500/30" }, "VIEW")),
9764
+ item.description && /* @__PURE__ */ React22.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
9765
+ )) : /* @__PURE__ */ React22.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
9766
+ /* @__PURE__ */ React22.createElement("div", { className: "px-6 py-4 border-t border-white/10 flex justify-end gap-3 flex-shrink-0 bg-slate-900/50" }, /* @__PURE__ */ React22.createElement(
9230
9767
  "button",
9231
9768
  {
9232
9769
  onClick: onClose,
9233
9770
  className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm text-slate-300"
9234
9771
  },
9235
9772
  "Cancelar"
9236
- ), /* @__PURE__ */ React21.createElement(
9773
+ ), /* @__PURE__ */ React22.createElement(
9237
9774
  "button",
9238
9775
  {
9239
9776
  onClick: handleConfirm,
@@ -9247,8 +9784,8 @@ function ImportParentFileModal({
9247
9784
  }
9248
9785
 
9249
9786
  // src/components/AncestryLinkDetailsPanel.jsx
9250
- import React22, { useState as useState22 } from "react";
9251
- import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
9787
+ import React23, { useState as useState23 } from "react";
9788
+ import { FiBookOpen as FiBookOpen6 } from "react-icons/fi";
9252
9789
  function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
9253
9790
  var _a, _b, _c, _d;
9254
9791
  const relationshipData = data.relationship || {};
@@ -9257,21 +9794,21 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
9257
9794
  const customProps = extractCustomPropsFromNode(relationshipData);
9258
9795
  const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
9259
9796
  const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
9260
- const [isReadMode, setIsReadMode] = useState22(false);
9797
+ const [isReadMode, setIsReadMode] = useState23(false);
9261
9798
  const swallow = (e) => e.stopPropagation();
9262
9799
  const handleImageClickFromText = (url, name) => {
9263
9800
  if (onOpenImageViewer) {
9264
9801
  onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
9265
9802
  }
9266
9803
  };
9267
- return /* @__PURE__ */ React22.createElement(
9804
+ return /* @__PURE__ */ React23.createElement(
9268
9805
  "div",
9269
9806
  {
9270
9807
  className: "ui-overlay fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[1200]",
9271
9808
  onClick: onClose,
9272
9809
  onPointerDown: swallow
9273
9810
  },
9274
- /* @__PURE__ */ React22.createElement(
9811
+ /* @__PURE__ */ React23.createElement(
9275
9812
  "div",
9276
9813
  {
9277
9814
  className: `relative group rounded-2xl border border-white/10 bg-slate-950/80 shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col max-h-[calc(100vh-4rem)] transition-all duration-300 ease-out
@@ -9279,7 +9816,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
9279
9816
  `,
9280
9817
  onClick: swallow
9281
9818
  },
9282
- isReadMode ? /* @__PURE__ */ React22.createElement(
9819
+ isReadMode ? /* @__PURE__ */ React23.createElement(
9283
9820
  DescriptionReadModePanel,
9284
9821
  {
9285
9822
  title: `${sourceName} \u2794 ${targetName}`,
@@ -9291,15 +9828,15 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
9291
9828
  onMentionClick,
9292
9829
  onImageClick: handleImageClickFromText
9293
9830
  }
9294
- ) : /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ React22.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React22.createElement("div", null, /* @__PURE__ */ React22.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React22.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-blue-500/80 shadow-[0_0_18px_2px_rgba(59,130,246,0.55)]" }), /* @__PURE__ */ React22.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ React22.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ React22.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ React22.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ React22.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ React22.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__ */ React22.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ React22.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React22.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React22.createElement(
9831
+ ) : /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ React23.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React23.createElement("div", null, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React23.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-blue-500/80 shadow-[0_0_18px_2px_rgba(59,130,246,0.55)]" }), /* @__PURE__ */ React23.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ React23.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ React23.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ React23.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__ */ React23.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ React23.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React23.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React23.createElement(
9295
9832
  "button",
9296
9833
  {
9297
9834
  onClick: () => setIsReadMode(true),
9298
9835
  className: "p-1 text-slate-400 hover:text-white transition-colors",
9299
9836
  title: "Modo de Leitura"
9300
9837
  },
9301
- /* @__PURE__ */ React22.createElement(FiBookOpen5, { size: 14 })
9302
- )), /* @__PURE__ */ React22.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ React22.createElement(
9838
+ /* @__PURE__ */ React23.createElement(FiBookOpen6, { size: 14 })
9839
+ )), /* @__PURE__ */ React23.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ React23.createElement(
9303
9840
  DescriptionDisplay,
9304
9841
  {
9305
9842
  description,
@@ -9308,7 +9845,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
9308
9845
  onMentionClick,
9309
9846
  onImageClick: handleImageClickFromText
9310
9847
  }
9311
- ))), customProps.length > 0 && /* @__PURE__ */ React22.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React22.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ React22.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ React22.createElement(
9848
+ ))), customProps.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React23.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ React23.createElement(
9312
9849
  CustomPropertyDisplay,
9313
9850
  {
9314
9851
  key: prop.id,
@@ -9317,25 +9854,25 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
9317
9854
  onOpenImageViewer,
9318
9855
  onUploadFile
9319
9856
  }
9320
- )))), !description && customProps.length === 0 && /* @__PURE__ */ React22.createElement("div", { className: "py-8 text-center text-slate-500 text-sm italic border border-dashed border-white/10 rounded-lg" }, "Nenhum detalhe adicional dispon\xEDvel para esta conex\xE3o."), /* @__PURE__ */ React22.createElement("div", { className: "mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg text-xs text-blue-200/80 text-center" }, 'Para editar esta conex\xE3o, utilize o menu "Editar Ancestralidade".')))
9857
+ )))), !description && customProps.length === 0 && /* @__PURE__ */ React23.createElement("div", { className: "py-8 text-center text-slate-500 text-sm italic border border-dashed border-white/10 rounded-lg" }, "Nenhum detalhe adicional dispon\xEDvel para esta conex\xE3o."), /* @__PURE__ */ React23.createElement("div", { className: "mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg text-xs text-blue-200/80 text-center" }, 'Para editar esta conex\xE3o, utilize o menu "Editar Ancestralidade".')))
9321
9858
  )
9322
9859
  );
9323
9860
  }
9324
9861
 
9325
9862
  // src/components/AncestryBoard.jsx
9326
- import React23, { useState as useState23, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef17 } from "react";
9863
+ import React24, { useState as useState24, useMemo as useMemo11, useEffect as useEffect21, useRef as useRef18 } from "react";
9327
9864
  import {
9328
9865
  FiSearch as FiSearch4,
9329
9866
  FiLayers as FiLayers6,
9330
9867
  FiCornerUpRight as FiCornerUpRight4,
9331
9868
  FiPlay,
9332
- FiPlus as FiPlus8,
9869
+ FiPlus as FiPlus9,
9333
9870
  FiTrash2 as FiTrash23,
9334
9871
  FiArrowLeft as FiArrowLeft3,
9335
9872
  FiArrowRight,
9336
9873
  FiCheckCircle,
9337
- FiLoader as FiLoader4,
9338
- FiX as FiX6,
9874
+ FiLoader as FiLoader5,
9875
+ FiX as FiX7,
9339
9876
  FiAlertTriangle
9340
9877
  } from "react-icons/fi";
9341
9878
  var GroupItem = ({
@@ -9357,7 +9894,7 @@ var GroupItem = ({
9357
9894
  }) => {
9358
9895
  const canIndent = index > 0;
9359
9896
  const isPickingForThisGroup = pickingGroupId === group.id;
9360
- const textareaRef = useRef17(null);
9897
+ const textareaRef = useRef18(null);
9361
9898
  const adjustHeight = () => {
9362
9899
  const textarea = textareaRef.current;
9363
9900
  if (textarea) {
@@ -9365,13 +9902,13 @@ var GroupItem = ({
9365
9902
  textarea.style.height = `${textarea.scrollHeight}px`;
9366
9903
  }
9367
9904
  };
9368
- useEffect20(() => {
9905
+ useEffect21(() => {
9369
9906
  adjustHeight();
9370
9907
  }, [group.text]);
9371
- return /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React23.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React23.createElement("div", { className: `
9908
+ return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement("div", { className: `
9372
9909
  flex flex-col gap-2 py-2 px-3 transition-all duration-200
9373
9910
  ${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
9374
- ` }, /* @__PURE__ */ React23.createElement(
9911
+ ` }, /* @__PURE__ */ React24.createElement(
9375
9912
  "textarea",
9376
9913
  {
9377
9914
  ref: textareaRef,
@@ -9388,9 +9925,9 @@ var GroupItem = ({
9388
9925
  if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
9389
9926
  }
9390
9927
  }
9391
- ), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
9928
+ ), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
9392
9929
  const isValid = availableIds.has(String(anc.ancestry_id));
9393
- return /* @__PURE__ */ React23.createElement(
9930
+ return /* @__PURE__ */ React24.createElement(
9394
9931
  "div",
9395
9932
  {
9396
9933
  key: anc.ancestry_id,
@@ -9402,28 +9939,28 @@ var GroupItem = ({
9402
9939
  },
9403
9940
  isValid ? (
9404
9941
  // [MANTIDO] Botão Play visível para todos
9405
- /* @__PURE__ */ React23.createElement(
9942
+ /* @__PURE__ */ React24.createElement(
9406
9943
  "button",
9407
9944
  {
9408
9945
  onClick: () => onPlayAncestry(anc.ancestry_id),
9409
9946
  className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
9410
9947
  title: "Renderizar no cen\xE1rio"
9411
9948
  },
9412
- /* @__PURE__ */ React23.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9949
+ /* @__PURE__ */ React24.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9413
9950
  )
9414
- ) : /* @__PURE__ */ React23.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React23.createElement(FiAlertTriangle, { size: 10 })),
9415
- /* @__PURE__ */ React23.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
9416
- canEdit && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ React23.createElement(
9951
+ ) : /* @__PURE__ */ React24.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React24.createElement(FiAlertTriangle, { size: 10 })),
9952
+ /* @__PURE__ */ React24.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
9953
+ canEdit && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ React24.createElement(
9417
9954
  "button",
9418
9955
  {
9419
9956
  onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
9420
9957
  className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
9421
9958
  title: "Remover men\xE7\xE3o"
9422
9959
  },
9423
- /* @__PURE__ */ React23.createElement(FiX6, { size: 12 })
9960
+ /* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
9424
9961
  ))
9425
9962
  );
9426
- })), canEdit && /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React23.createElement(
9963
+ })), canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
9427
9964
  "button",
9428
9965
  {
9429
9966
  onClick: () => onRequestPickAncestry(group.id),
@@ -9433,17 +9970,17 @@ var GroupItem = ({
9433
9970
  `,
9434
9971
  title: "Adicionar Ancestralidade a este grupo"
9435
9972
  },
9436
- isPickingForThisGroup ? /* @__PURE__ */ React23.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React23.createElement(FiSearch4, { size: 12 }),
9973
+ isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch4, { size: 12 }),
9437
9974
  isPickingForThisGroup ? "Selecionando..." : "Adicionar"
9438
- ), /* @__PURE__ */ React23.createElement(
9975
+ ), /* @__PURE__ */ React24.createElement(
9439
9976
  "button",
9440
9977
  {
9441
9978
  onClick: () => onAddSubgroup(group.id),
9442
9979
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
9443
9980
  title: "Criar Subgrupo"
9444
9981
  },
9445
- /* @__PURE__ */ React23.createElement(FiPlus8, { size: 14 })
9446
- )), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React23.createElement(
9982
+ /* @__PURE__ */ React24.createElement(FiPlus9, { size: 14 })
9983
+ )), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
9447
9984
  "button",
9448
9985
  {
9449
9986
  onClick: () => onIndent(group.id),
@@ -9451,24 +9988,24 @@ var GroupItem = ({
9451
9988
  className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
9452
9989
  title: "Aninhar no grupo acima"
9453
9990
  },
9454
- /* @__PURE__ */ React23.createElement(FiArrowRight, { size: 14 })
9455
- ), /* @__PURE__ */ React23.createElement(
9991
+ /* @__PURE__ */ React24.createElement(FiArrowRight, { size: 14 })
9992
+ ), /* @__PURE__ */ React24.createElement(
9456
9993
  "button",
9457
9994
  {
9458
9995
  onClick: () => onOutdent(group.id),
9459
9996
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
9460
9997
  title: "Desaninhar"
9461
9998
  },
9462
- /* @__PURE__ */ React23.createElement(FiArrowLeft3, { size: 14 })
9463
- ), /* @__PURE__ */ React23.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React23.createElement(
9999
+ /* @__PURE__ */ React24.createElement(FiArrowLeft3, { size: 14 })
10000
+ ), /* @__PURE__ */ React24.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement(
9464
10001
  "button",
9465
10002
  {
9466
10003
  onClick: () => onDelete(group.id),
9467
10004
  className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
9468
10005
  title: "Remover Grupo"
9469
10006
  },
9470
- /* @__PURE__ */ React23.createElement(FiTrash23, { size: 14 })
9471
- )))), group.children && group.children.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React23.createElement(
10007
+ /* @__PURE__ */ React24.createElement(FiTrash23, { size: 14 })
10008
+ )))), group.children && group.children.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React24.createElement(
9472
10009
  GroupItem,
9473
10010
  {
9474
10011
  key: childGroup.id,
@@ -9500,15 +10037,15 @@ function AncestryBoard({
9500
10037
  userRole
9501
10038
  // [NOVO] Recebe a role do usuário
9502
10039
  }) {
9503
- const [searchTerm, setSearchTerm] = useState23("");
9504
- const [groups, setGroups] = useState23([]);
9505
- const [isLoaded, setIsLoaded] = useState23(false);
9506
- const [pickingGroupId, setPickingGroupId] = useState23(null);
9507
- const [saveStatus, setSaveStatus] = useState23("idle");
10040
+ const [searchTerm, setSearchTerm] = useState24("");
10041
+ const [groups, setGroups] = useState24([]);
10042
+ const [isLoaded, setIsLoaded] = useState24(false);
10043
+ const [pickingGroupId, setPickingGroupId] = useState24(null);
10044
+ const [saveStatus, setSaveStatus] = useState24("idle");
9508
10045
  const canEdit = useMemo11(() => {
9509
10046
  return userRole !== "viewer";
9510
10047
  }, [userRole]);
9511
- useEffect20(() => {
10048
+ useEffect21(() => {
9512
10049
  if (initialGroups && !isLoaded) {
9513
10050
  setGroups(initialGroups);
9514
10051
  setIsLoaded(true);
@@ -9539,7 +10076,7 @@ function AncestryBoard({
9539
10076
  children: sanitizeGroups(g.children || [])
9540
10077
  }));
9541
10078
  };
9542
- useEffect20(() => {
10079
+ useEffect21(() => {
9543
10080
  if (!isLoaded || !onSave) return;
9544
10081
  const timeoutId = setTimeout(async () => {
9545
10082
  setSaveStatus("saving");
@@ -9557,7 +10094,7 @@ function AncestryBoard({
9557
10094
  }, 3e3);
9558
10095
  return () => clearTimeout(timeoutId);
9559
10096
  }, [groups, isLoaded, onSave]);
9560
- useEffect20(() => {
10097
+ useEffect21(() => {
9561
10098
  if (!isOpen) return;
9562
10099
  const handleKeyDown = (e) => {
9563
10100
  if (e.key === "Escape") {
@@ -9712,27 +10249,27 @@ function AncestryBoard({
9712
10249
  });
9713
10250
  };
9714
10251
  if (!isOpen) return null;
9715
- return /* @__PURE__ */ React23.createElement(
10252
+ return /* @__PURE__ */ React24.createElement(
9716
10253
  "div",
9717
10254
  {
9718
10255
  className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
9719
10256
  onClick: onClose
9720
10257
  },
9721
- /* @__PURE__ */ React23.createElement(
10258
+ /* @__PURE__ */ React24.createElement(
9722
10259
  "div",
9723
10260
  {
9724
10261
  className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
9725
10262
  onClick: (e) => e.stopPropagation()
9726
10263
  },
9727
- /* @__PURE__ */ React23.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React23.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React23.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React23.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(FiLoader4, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React23.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React23.createElement(
10264
+ /* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiLoader5, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React24.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React24.createElement(
9728
10265
  "button",
9729
10266
  {
9730
10267
  onClick: handleAddRootGroup,
9731
10268
  className: "\n flex items-center gap-2 px-3 py-1.5 \n bg-white/5 hover:bg-white/10 \n border border-white/10 hover:border-white/20\n backdrop-blur-sm\n text-slate-200 hover:text-white\n rounded-md transition-all duration-200\n text-xs font-medium shadow-sm\n "
9732
10269
  },
9733
- /* @__PURE__ */ React23.createElement(FiPlus8, { size: 14, className: "text-indigo-400" }),
9734
- /* @__PURE__ */ React23.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
9735
- ), /* @__PURE__ */ React23.createElement(
10270
+ /* @__PURE__ */ React24.createElement(FiPlus9, { size: 14, className: "text-indigo-400" }),
10271
+ /* @__PURE__ */ React24.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
10272
+ ), /* @__PURE__ */ React24.createElement(
9736
10273
  "button",
9737
10274
  {
9738
10275
  onClick: onClose,
@@ -9740,11 +10277,11 @@ function AncestryBoard({
9740
10277
  },
9741
10278
  "\xD7"
9742
10279
  ))),
9743
- /* @__PURE__ */ React23.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React23.createElement("div", { className: `
10280
+ /* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement("div", { className: `
9744
10281
  flex flex-col border-r border-white/10 transition-all duration-300 flex-none
9745
10282
  ${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
9746
10283
  min-w-[280px] max-w-[500px] bg-slate-900
9747
- ` }, /* @__PURE__ */ React23.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React23.createElement("div", { className: "relative group" }, /* @__PURE__ */ React23.createElement(FiSearch4, { className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}` }), /* @__PURE__ */ React23.createElement(
10284
+ ` }, /* @__PURE__ */ React24.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React24.createElement("div", { className: "relative group" }, /* @__PURE__ */ React24.createElement(FiSearch4, { className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}` }), /* @__PURE__ */ React24.createElement(
9748
10285
  "input",
9749
10286
  {
9750
10287
  type: "text",
@@ -9757,10 +10294,10 @@ function AncestryBoard({
9757
10294
  onChange: (e) => setSearchTerm(e.target.value),
9758
10295
  autoFocus: !pickingGroupId
9759
10296
  }
9760
- ))), /* @__PURE__ */ React23.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
10297
+ ))), /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
9761
10298
  const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
9762
10299
  const isPicking = !!pickingGroupId;
9763
- return /* @__PURE__ */ React23.createElement(
10300
+ return /* @__PURE__ */ React24.createElement(
9764
10301
  "div",
9765
10302
  {
9766
10303
  key: anc.ancestry_id,
@@ -9772,12 +10309,12 @@ function AncestryBoard({
9772
10309
  ${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
9773
10310
  `
9774
10311
  },
9775
- /* @__PURE__ */ React23.createElement("div", { className: `
10312
+ /* @__PURE__ */ React24.createElement("div", { className: `
9776
10313
  mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
9777
10314
  ${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
9778
- ` }, isPicking ? /* @__PURE__ */ React23.createElement(FiPlus8, { size: 16 }) : /* @__PURE__ */ React23.createElement(FiLayers6, { size: 14 })),
9779
- /* @__PURE__ */ React23.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React23.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React23.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React23.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React23.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
9780
- !isPicking && /* @__PURE__ */ React23.createElement(
10315
+ ` }, isPicking ? /* @__PURE__ */ React24.createElement(FiPlus9, { size: 16 }) : /* @__PURE__ */ React24.createElement(FiLayers6, { size: 14 })),
10316
+ /* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
10317
+ !isPicking && /* @__PURE__ */ React24.createElement(
9781
10318
  "button",
9782
10319
  {
9783
10320
  onClick: (e) => {
@@ -9787,10 +10324,10 @@ function AncestryBoard({
9787
10324
  className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
9788
10325
  title: "Renderizar Ancestralidade"
9789
10326
  },
9790
- /* @__PURE__ */ React23.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React23.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
10327
+ /* @__PURE__ */ React24.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React24.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
9791
10328
  )
9792
10329
  );
9793
- }))), /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React23.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React23.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React23.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React23.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React23.createElement(React23.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React23.createElement(
10330
+ }))), /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React24.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React24.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React24.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React24.createElement(
9794
10331
  GroupItem,
9795
10332
  {
9796
10333
  key: group.id,
@@ -9810,7 +10347,7 @@ function AncestryBoard({
9810
10347
  canEdit
9811
10348
  }
9812
10349
  ))))),
9813
- /* @__PURE__ */ React23.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-between flex-shrink-0" }, /* @__PURE__ */ React23.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ React23.createElement("span", null, groups.length, " grupos raiz"))
10350
+ /* @__PURE__ */ React24.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-between flex-shrink-0" }, /* @__PURE__ */ React24.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ React24.createElement("span", null, groups.length, " grupos raiz"))
9814
10351
  )
9815
10352
  );
9816
10353
  }
@@ -9889,7 +10426,7 @@ function XViewScene({
9889
10426
  delete_file_action,
9890
10427
  check_user_permission
9891
10428
  }) {
9892
- var _a, _b, _c, _d, _e, _f, _g;
10429
+ var _a, _b, _c, _d, _e, _f, _g, _h;
9893
10430
  const { data: session, status } = useSession();
9894
10431
  const router = useRouter();
9895
10432
  const searchParams = useSearchParams();
@@ -9904,7 +10441,7 @@ function XViewScene({
9904
10441
  }
9905
10442
  return null;
9906
10443
  }, [encryptedConfig, session]);
9907
- useEffect21(() => {
10444
+ useEffect22(() => {
9908
10445
  async function verifyPermission() {
9909
10446
  if (!viewParams || !session || !check_user_permission) return;
9910
10447
  const { id, type, owner_id } = viewParams;
@@ -9954,45 +10491,45 @@ function XViewScene({
9954
10491
  }
9955
10492
  return null;
9956
10493
  }, [ownerId, sceneConfigId]);
9957
- const sceneDataRef = useRef18(null);
9958
- const parentDataRef = useRef18(null);
9959
- const ancestryDataRef = useRef18(null);
9960
- const [isLoading, setIsLoading] = useState24(true);
9961
- const [permissionStatus, setPermissionStatus] = useState24("loading");
9962
- const [userPermissionRole, setUserPermissionRole] = useState24(null);
9963
- const [isInitialized, setIsInitialized] = useState24(false);
9964
- const [sceneVersion, setSceneVersion] = useState24(0);
9965
- const [contextMenu, setContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeData: null });
9966
- const [multiContextMenu, setMultiContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeIds: null });
9967
- const [relationshipMenu, setRelationshipMenu] = useState24({ visible: false, x: 0, y: 0, linkObject: null });
9968
- const [creationMode, setCreationMode] = useState24({ isActive: false, sourceNodeData: null });
9969
- const [versionMode, setVersionMode] = useState24({ isActive: false, sourceNodeData: null });
9970
- const [questMode, setQuestMode] = useState24({ isActive: false });
9971
- const [hasFocusedInitial, setHasFocusedInitial] = useState24(false);
9972
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState24(false);
9973
- const [ancestryMode, setAncestryMode] = useState24({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9974
- const [readingMode, setReadingMode] = useState24({
10494
+ const sceneDataRef = useRef19(null);
10495
+ const parentDataRef = useRef19(null);
10496
+ const ancestryDataRef = useRef19(null);
10497
+ const [isLoading, setIsLoading] = useState25(true);
10498
+ const [permissionStatus, setPermissionStatus] = useState25("loading");
10499
+ const [userPermissionRole, setUserPermissionRole] = useState25(null);
10500
+ const [isInitialized, setIsInitialized] = useState25(false);
10501
+ const [sceneVersion, setSceneVersion] = useState25(0);
10502
+ const [contextMenu, setContextMenu] = useState25({ visible: false, x: 0, y: 0, nodeData: null });
10503
+ const [multiContextMenu, setMultiContextMenu] = useState25({ visible: false, x: 0, y: 0, nodeIds: null });
10504
+ const [relationshipMenu, setRelationshipMenu] = useState25({ visible: false, x: 0, y: 0, linkObject: null });
10505
+ const [creationMode, setCreationMode] = useState25({ isActive: false, sourceNodeData: null });
10506
+ const [versionMode, setVersionMode] = useState25({ isActive: false, sourceNodeData: null });
10507
+ const [questMode, setQuestMode] = useState25({ isActive: false });
10508
+ const [hasFocusedInitial, setHasFocusedInitial] = useState25(false);
10509
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState25(false);
10510
+ const [ancestryMode, setAncestryMode] = useState25({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
10511
+ const [readingMode, setReadingMode] = useState25({
9975
10512
  isActive: false,
9976
10513
  ancestry: null,
9977
10514
  branchStack: [],
9978
10515
  autoAbstraction: false
9979
10516
  });
9980
- const [formPosition, setFormPosition] = useState24({ left: 16, top: 16, opacity: 0 });
9981
- const [detailsNode, setDetailsNode] = useState24(null);
9982
- const [detailsLink, setDetailsLink] = useState24(null);
9983
- const [ancestryLinkDetails, setAncestryLinkDetails] = useState24(null);
9984
- const [imageViewer, setImageViewer] = useState24({ visible: false, images: [], startIndex: 0 });
9985
- const [editingAncestryRel, setEditingAncestryRel] = useState24({ visible: false, data: null, path: null });
9986
- const [isImportModalOpen, setIsImportModalOpen] = useState24(false);
9987
- const [importSuccessMessage, setImportSuccessMessage] = useState24("");
9988
- const [highlightedNodeId, setHighlightedNodeId] = useState24(null);
9989
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState24(false);
9990
- const [ancestryBoardData, setAncestryBoardData] = useState24([]);
9991
- const [isSidebarOpen, setIsSidebarOpen] = useState24(false);
9992
- const mountRef = useRef18(null);
9993
- const tooltipRef = useRef18(null);
9994
- const formRef = useRef18(null);
9995
- const stateRef = useRef18({
10517
+ const [formPosition, setFormPosition] = useState25({ left: 16, top: 16, opacity: 0 });
10518
+ const [detailsNode, setDetailsNode] = useState25(null);
10519
+ const [detailsLink, setDetailsLink] = useState25(null);
10520
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState25(null);
10521
+ const [imageViewer, setImageViewer] = useState25({ visible: false, images: [], startIndex: 0 });
10522
+ const [editingAncestryRel, setEditingAncestryRel] = useState25({ visible: false, data: null, path: null });
10523
+ const [isImportModalOpen, setIsImportModalOpen] = useState25(false);
10524
+ const [importSuccessMessage, setImportSuccessMessage] = useState25("");
10525
+ const [highlightedNodeId, setHighlightedNodeId] = useState25(null);
10526
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState25(false);
10527
+ const [ancestryBoardData, setAncestryBoardData] = useState25([]);
10528
+ const [isSidebarOpen, setIsSidebarOpen] = useState25(false);
10529
+ const mountRef = useRef19(null);
10530
+ const tooltipRef = useRef19(null);
10531
+ const formRef = useRef19(null);
10532
+ const stateRef = useRef19({
9996
10533
  readMode: {
9997
10534
  currentMaxIndex: 0,
9998
10535
  progressMap: {}
@@ -10037,10 +10574,10 @@ function XViewScene({
10037
10574
  minWidth: 320,
10038
10575
  maxWidth: maxReadPanelW
10039
10576
  });
10040
- useEffect21(() => {
10577
+ useEffect22(() => {
10041
10578
  stateRef.current.ancestry = ancestryMode;
10042
10579
  }, [ancestryMode]);
10043
- useEffect21(() => {
10580
+ useEffect22(() => {
10044
10581
  var _a2;
10045
10582
  if (!isInitialized) return;
10046
10583
  const map = /* @__PURE__ */ new Map();
@@ -10225,7 +10762,7 @@ function XViewScene({
10225
10762
  });
10226
10763
  }
10227
10764
  return {
10228
- node: effectiveNode || { id: nodeId, name: "Unknown" },
10765
+ ...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
10229
10766
  relationship: treeItem.relationship || {},
10230
10767
  children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
10231
10768
  parallel_branches: processedBranches
@@ -10537,7 +11074,7 @@ function XViewScene({
10537
11074
  }
10538
11075
  });
10539
11076
  }, []);
10540
- useEffect21(() => {
11077
+ useEffect22(() => {
10541
11078
  async function fetchAllData(configPath, ownerId2) {
10542
11079
  var _a2, _b2;
10543
11080
  if (!get_scene_view_data) {
@@ -10641,7 +11178,7 @@ function XViewScene({
10641
11178
  }
10642
11179
  return mesh;
10643
11180
  }, []);
10644
- useEffect21(() => {
11181
+ useEffect22(() => {
10645
11182
  if (!isInitialized || !sceneDataRef.current) return;
10646
11183
  const currentMount = mountRef.current;
10647
11184
  if (!currentMount) return;
@@ -11029,39 +11566,6 @@ function XViewScene({
11029
11566
  }
11030
11567
  }
11031
11568
  }
11032
- function handleCancelAncestryCreation() {
11033
- setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
11034
- if (mountRef.current) mountRef.current.style.cursor = "grab";
11035
- }
11036
- function handleKeyDown(event) {
11037
- var _a2, _b2, _c2, _d2;
11038
- const context = actionHandlerContext;
11039
- if (event.key === "Escape") {
11040
- if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
11041
- if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
11042
- if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
11043
- if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
11044
- if (stateRef.current.ancestry.isActive) handleCancelAncestryCreation();
11045
- if ((_b2 = context.questMode) == null ? void 0 : _b2.isActive) context.setters.setQuestMode({ isActive: false });
11046
- if (stateRef.current.selectedNodes.size > 0) {
11047
- stateRef.current.selectedNodes.clear();
11048
- }
11049
- setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11050
- setMultiContextMenu((prev) => ({ ...prev, visible: false }));
11051
- setRelationshipMenu((prev) => ({ ...prev, visible: false }));
11052
- }
11053
- if (event.key.toLowerCase() === "q") {
11054
- const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_c2 = context.versionMode) == null ? void 0 : _c2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen;
11055
- if (isUiClear) {
11056
- const isView = ((_d2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _d2.toLowerCase()) === "view";
11057
- if (!isView) {
11058
- alert("Nodes de Quest s\xF3 podem ser criados dentro de uma View.");
11059
- return;
11060
- }
11061
- setQuestMode({ isActive: true });
11062
- }
11063
- }
11064
- }
11065
11569
  function handleDoubleClick(event) {
11066
11570
  if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
11067
11571
  if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive) return;
@@ -11114,7 +11618,6 @@ function XViewScene({
11114
11618
  currentMount.addEventListener("dblclick", handleDoubleClick);
11115
11619
  currentMount.addEventListener("pointermove", onPointerMove);
11116
11620
  currentMount.addEventListener("contextmenu", handleContextMenu);
11117
- window.addEventListener("keydown", handleKeyDown);
11118
11621
  const originalBackground = scene.background;
11119
11622
  const clock = new THREE3.Clock();
11120
11623
  let animationFrameId = 0;
@@ -11252,7 +11755,6 @@ function XViewScene({
11252
11755
  return () => {
11253
11756
  cancelAnimationFrame(animationFrameId);
11254
11757
  window.removeEventListener("resize", handleResize);
11255
- window.removeEventListener("keydown", handleKeyDown);
11256
11758
  currentMount.removeEventListener("pointerdown", onPointerDown);
11257
11759
  currentMount.removeEventListener("pointerup", onPointerUp);
11258
11760
  currentMount.removeEventListener("dblclick", handleDoubleClick);
@@ -11422,7 +11924,7 @@ function XViewScene({
11422
11924
  graphGroup.add(newLabel);
11423
11925
  ghostNode.userData.labelObject = newLabel;
11424
11926
  };
11425
- const handleDetailNodeNameChange = (nodeId, newName) => {
11927
+ const handleDetailNodeNameChange = (nodeId, newName, newRawTitle) => {
11426
11928
  const mesh = stateRef.current.nodeObjects[String(nodeId)];
11427
11929
  const { graphGroup } = stateRef.current;
11428
11930
  if (!mesh || !graphGroup) return;
@@ -11432,10 +11934,15 @@ function XViewScene({
11432
11934
  if (oldLabel.material.map) oldLabel.material.map.dispose();
11433
11935
  oldLabel.material.dispose();
11434
11936
  }
11435
- const newLabel = createTextSprite(newName || "");
11937
+ const isQuest = mesh.userData.is_quest;
11938
+ const displayText = isQuest && newRawTitle !== void 0 ? newRawTitle : newName;
11939
+ const newLabel = createTextSprite(displayText || "");
11436
11940
  graphGroup.add(newLabel);
11437
11941
  mesh.userData.labelObject = newLabel;
11438
11942
  mesh.userData.name = newName;
11943
+ if (newRawTitle !== void 0) {
11944
+ mesh.userData.raw_title = newRawTitle;
11945
+ }
11439
11946
  };
11440
11947
  const handleDetailNodeColorChange = (nodeId, newColor) => {
11441
11948
  var _a2;
@@ -11576,9 +12083,30 @@ function XViewScene({
11576
12083
  const handleStartVersioning = (nodeData) => {
11577
12084
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
11578
12085
  };
12086
+ const handleCancelQuest = useCallback4(() => {
12087
+ const { graphGroup, ghostElements } = stateRef.current;
12088
+ if (ghostElements.node && graphGroup) {
12089
+ if (ghostElements.node.userData.labelObject) {
12090
+ graphGroup.remove(ghostElements.node.userData.labelObject);
12091
+ if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
12092
+ ghostElements.node.userData.labelObject.material.dispose();
12093
+ }
12094
+ graphGroup.remove(ghostElements.node);
12095
+ ghostElements.node.traverse((child) => {
12096
+ if (child.material) {
12097
+ if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
12098
+ else child.material.dispose();
12099
+ }
12100
+ if (child.geometry) child.geometry.dispose();
12101
+ });
12102
+ }
12103
+ stateRef.current.ghostElements = { node: null, line: null, aura: null };
12104
+ setQuestMode({ isActive: false });
12105
+ }, []);
11579
12106
  const handleSaveQuestNode = async (context, newQuestData) => {
11580
12107
  const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
11581
12108
  if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
12109
+ const currentCounter = sceneDataRef2.current.quest_counter || 1;
11582
12110
  const newNode = {
11583
12111
  id: short2.generate(),
11584
12112
  ...newQuestData,
@@ -11592,22 +12120,27 @@ function XViewScene({
11592
12120
  const sceneFileData = {
11593
12121
  parent_dbs: sceneDataRef2.current.parent_dbs,
11594
12122
  nodes: sceneDataRef2.current.nodes,
11595
- // <-- Mantém o cenário inicial inalterado
12123
+ // Permanece intacto, como estava no último save de cena inicial
11596
12124
  links: sceneDataRef2.current.links,
11597
- // <-- Mantém o cenário inicial inalterado
11598
12125
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
11599
- quest_links: graphDataRef.current[sceneConfigId2].links
12126
+ quest_links: graphDataRef.current[sceneConfigId2].links,
12127
+ quest_counter: currentCounter + 1
11600
12128
  };
11601
12129
  try {
11602
12130
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
12131
+ sceneDataRef2.current.quest_counter = currentCounter + 1;
11603
12132
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
11604
12133
  parentFileId: sceneConfigId2,
11605
12134
  ownerId: ownerId2,
11606
12135
  datasetName: "Quests Internas (View)"
11607
12136
  });
11608
- const basePosition = stateRef2.current.controls.target.clone();
11609
- const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
11610
- const finalPosition = basePosition.add(offset);
12137
+ const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
12138
+ const { graphGroup, ghostElements } = stateRef2.current;
12139
+ if (ghostElements.node && graphGroup) {
12140
+ if (ghostElements.node.userData.labelObject) graphGroup.remove(ghostElements.node.userData.labelObject);
12141
+ graphGroup.remove(ghostElements.node);
12142
+ }
12143
+ stateRef2.current.ghostElements = { node: null, line: null, aura: null };
11611
12144
  addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
11612
12145
  context.tweenToTarget(finalPosition, 1.2);
11613
12146
  setters.setQuestMode({ isActive: false });
@@ -11627,10 +12160,10 @@ function XViewScene({
11627
12160
  const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
11628
12161
  const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
11629
12162
  let parentInfoToSave = sourceParentInfo;
11630
- if (sourceParentInfo.parentFileId === sceneConfigId2 && targetParentInfo.parentFileId !== sceneConfigId2) {
11631
- parentInfoToSave = targetParentInfo;
11632
- } else if (targetParentInfo.parentFileId === sceneConfigId2 && sourceParentInfo.parentFileId !== sceneConfigId2) {
11633
- parentInfoToSave = sourceParentInfo;
12163
+ const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
12164
+ const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
12165
+ if (isSourceQuest || isTargetQuest) {
12166
+ parentInfoToSave = { parentFileId: sceneConfigId2, ownerId: ownerId2 };
11634
12167
  }
11635
12168
  const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
11636
12169
  const newLink = {
@@ -11645,12 +12178,9 @@ function XViewScene({
11645
12178
  const viewFilePayload = {
11646
12179
  parent_dbs: sceneDataRef2.current.parent_dbs,
11647
12180
  nodes: sceneDataRef2.current.nodes,
11648
- // <-- Usa o estado original intocado
11649
12181
  links: sceneDataRef2.current.links,
11650
- // <-- Usa o estado original intocado
11651
12182
  quest_nodes: specificParentData.nodes,
11652
12183
  quest_links: specificParentData.links
11653
- // Salva a conexão aqui!
11654
12184
  };
11655
12185
  await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
11656
12186
  } else {
@@ -12915,7 +13445,7 @@ function XViewScene({
12915
13445
  const allTypes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes.flatMap((node) => {
12916
13446
  if (Array.isArray(node.type)) return node.type;
12917
13447
  return [node.type];
12918
- })).filter(Boolean);
13448
+ })).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
12919
13449
  return [...new Set(allTypes)];
12920
13450
  }, [parentDataRef.current, sceneVersion]);
12921
13451
  const searchableDbNodes = useMemo12(() => {
@@ -12934,7 +13464,7 @@ function XViewScene({
12934
13464
  [actionHandlerContext]
12935
13465
  );
12936
13466
  const handleSaveCurrentView = useCallback4(async () => {
12937
- var _a2, _b2;
13467
+ var _a2, _b2, _c2;
12938
13468
  const { nodeObjects, allLinks } = stateRef.current;
12939
13469
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
12940
13470
  console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
@@ -12958,19 +13488,20 @@ function XViewScene({
12958
13488
  });
12959
13489
  sceneDataRef.current.nodes = currentNodes;
12960
13490
  sceneDataRef.current.links = currentLinks;
13491
+ const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
12961
13492
  const sceneFileData = {
12962
13493
  parent_dbs: sceneDataRef.current.parent_dbs,
12963
13494
  nodes: currentNodes,
12964
13495
  links: currentLinks,
12965
- quest_nodes: ((_a2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _a2.nodes) || [],
12966
- quest_links: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.links) || []
13496
+ quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
13497
+ quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || []
12967
13498
  };
12968
13499
  try {
12969
13500
  await save_view_data(sceneSaveUrl, sceneFileData);
12970
13501
  } catch (error) {
12971
13502
  console.error("Erro na chamada de save_view_data:", error);
12972
13503
  }
12973
- }, [sceneSaveUrl, save_view_data, sceneConfigId]);
13504
+ }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
12974
13505
  const allAvailableNodes = useMemo12(() => {
12975
13506
  if (!parentDataRef.current) return [];
12976
13507
  return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
@@ -13027,7 +13558,7 @@ function XViewScene({
13027
13558
  }, [sceneVersion, isInitialized]);
13028
13559
  const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
13029
13560
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
13030
- useEffect21(() => {
13561
+ useEffect22(() => {
13031
13562
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
13032
13563
  const nodeObjects = stateRef.current.nodeObjects || {};
13033
13564
  const targetMesh = nodeObjects[String(focusNodeId)];
@@ -13041,7 +13572,7 @@ function XViewScene({
13041
13572
  }
13042
13573
  }
13043
13574
  }, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
13044
- useEffect21(() => {
13575
+ useEffect22(() => {
13045
13576
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
13046
13577
  const ancestries = ancestryDataRef.current || [];
13047
13578
  const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
@@ -13055,21 +13586,121 @@ function XViewScene({
13055
13586
  }
13056
13587
  }
13057
13588
  }, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
13589
+ useEffect22(() => {
13590
+ function handleKeyDown(event) {
13591
+ var _a2, _b2, _c2;
13592
+ const context = actionHandlerContext;
13593
+ if (event.key === "Escape") {
13594
+ if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
13595
+ if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
13596
+ if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
13597
+ if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
13598
+ if (stateRef.current.ancestry.isActive) {
13599
+ setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
13600
+ if (mountRef.current) mountRef.current.style.cursor = "grab";
13601
+ }
13602
+ if (questMode.isActive) {
13603
+ handleCancelQuest();
13604
+ }
13605
+ if (stateRef.current.selectedNodes.size > 0) {
13606
+ stateRef.current.selectedNodes.clear();
13607
+ }
13608
+ setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
13609
+ setMultiContextMenu((prev) => ({ ...prev, visible: false }));
13610
+ setRelationshipMenu((prev) => ({ ...prev, visible: false }));
13611
+ }
13612
+ if (event.key.toLowerCase() === "q") {
13613
+ const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
13614
+ if (isUiClear) {
13615
+ const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
13616
+ if (!isView) return;
13617
+ const { graphGroup, glowTexture, controls, nodeObjects } = stateRef.current;
13618
+ if (graphGroup) {
13619
+ let ghostPosition = controls.target.clone();
13620
+ const existingNodes = Object.values(nodeObjects);
13621
+ let isOccupied = true;
13622
+ let radius = 18;
13623
+ let angle = 0;
13624
+ let attempts = 0;
13625
+ const MIN_CLEARANCE = 15;
13626
+ while (isOccupied && attempts < 30) {
13627
+ isOccupied = existingNodes.some((mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE);
13628
+ if (isOccupied) {
13629
+ ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
13630
+ ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
13631
+ ghostPosition.z = controls.target.z + Math.sin(angle) * radius;
13632
+ angle += Math.PI / 3;
13633
+ radius += 2.5;
13634
+ attempts++;
13635
+ }
13636
+ }
13637
+ const ghostData = {
13638
+ id: "ghost_quest",
13639
+ name: "Nova Quest",
13640
+ color: "#64748b",
13641
+ // Cor padrão de "Backlog"
13642
+ size: "medium",
13643
+ intensity: 0,
13644
+ type: ["quest"]
13645
+ };
13646
+ const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
13647
+ ghostNode.traverse((child) => {
13648
+ if (child.isMesh) {
13649
+ child.material.transparent = true;
13650
+ child.material.opacity = 0.75;
13651
+ }
13652
+ });
13653
+ graphGroup.add(ghostNode);
13654
+ if (ghostNode.userData.labelObject) {
13655
+ graphGroup.add(ghostNode.userData.labelObject);
13656
+ }
13657
+ stateRef.current.ghostElements = {
13658
+ node: ghostNode,
13659
+ line: null,
13660
+ aura: ghostNode.getObjectByName("aura")
13661
+ };
13662
+ context.tweenToTarget(ghostPosition, 1.6);
13663
+ }
13664
+ setQuestMode({ isActive: true });
13665
+ }
13666
+ }
13667
+ }
13668
+ window.addEventListener("keydown", handleKeyDown);
13669
+ return () => window.removeEventListener("keydown", handleKeyDown);
13670
+ }, [
13671
+ contextMenu.visible,
13672
+ multiContextMenu.visible,
13673
+ relationshipMenu.visible,
13674
+ readingMode.isActive,
13675
+ isImportModalOpen,
13676
+ isAncestryBoardOpen,
13677
+ isSidebarOpen,
13678
+ detailsNode,
13679
+ detailsLink,
13680
+ ancestryLinkDetails,
13681
+ imageViewer.visible,
13682
+ editingAncestryRel.visible,
13683
+ questMode.isActive,
13684
+ viewParams,
13685
+ actionHandlerContext,
13686
+ handleCancelQuest
13687
+ // <-- handleCancelQuest adicionado aqui
13688
+ ]);
13058
13689
  if (isLoading || status === "loading" || permissionStatus === "loading") {
13059
- return /* @__PURE__ */ React24.createElement(LoadingScreen, null);
13690
+ return /* @__PURE__ */ React25.createElement(LoadingScreen, null);
13060
13691
  }
13061
13692
  if (permissionStatus === "denied") {
13062
- return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React24.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React24.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React24.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "w-16 h-16 mx-auto" }, /* @__PURE__ */ React24.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" }))), /* @__PURE__ */ React24.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React24.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React24.createElement(
13693
+ return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "w-16 h-16 mx-auto" }, /* @__PURE__ */ React25.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" }))), /* @__PURE__ */ React25.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React25.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React25.createElement(
13063
13694
  "button",
13064
13695
  {
13065
13696
  onClick: () => router.push("/dashboard/scenes"),
13066
13697
  className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
13067
13698
  },
13068
- /* @__PURE__ */ React24.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-5 h-5" }, /* @__PURE__ */ React24.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
13699
+ /* @__PURE__ */ React25.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-5 h-5" }, /* @__PURE__ */ React25.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
13069
13700
  "Voltar para Scenes"
13070
13701
  )));
13071
13702
  }
13072
- return /* @__PURE__ */ React24.createElement(
13703
+ return /* @__PURE__ */ React25.createElement(
13073
13704
  "div",
13074
13705
  {
13075
13706
  ref: mountRef,
@@ -13081,7 +13712,7 @@ function XViewScene({
13081
13712
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
13082
13713
  }
13083
13714
  },
13084
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ React24.createElement(
13715
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ React25.createElement(
13085
13716
  XViewSidebar,
13086
13717
  {
13087
13718
  dbNodes: searchableDbNodes,
@@ -13101,7 +13732,7 @@ function XViewScene({
13101
13732
  userRole: userPermissionRole
13102
13733
  }
13103
13734
  ),
13104
- creationMode.isActive && /* @__PURE__ */ React24.createElement(
13735
+ creationMode.isActive && /* @__PURE__ */ React25.createElement(
13105
13736
  InSceneCreationForm,
13106
13737
  {
13107
13738
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -13126,7 +13757,7 @@ function XViewScene({
13126
13757
  availableAncestries: allAvailableAncestries
13127
13758
  }
13128
13759
  ),
13129
- versionMode.isActive && /* @__PURE__ */ React24.createElement(
13760
+ versionMode.isActive && /* @__PURE__ */ React25.createElement(
13130
13761
  InSceneVersionForm,
13131
13762
  {
13132
13763
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -13145,27 +13776,32 @@ function XViewScene({
13145
13776
  availableAncestries: allAvailableAncestries
13146
13777
  }
13147
13778
  ),
13148
- questMode.isActive && /* @__PURE__ */ React24.createElement(
13779
+ questMode.isActive && /* @__PURE__ */ React25.createElement(
13149
13780
  InSceneQuestForm,
13150
13781
  {
13151
13782
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
13152
- onCancel: () => setQuestMode({ isActive: false }),
13783
+ onCancel: handleCancelQuest,
13784
+ onNameChange: handleGhostNodeNameChange,
13785
+ onColorChange: handleGhostNodeColorChange,
13786
+ onSizeChange: handleGhostNodeSizeChange,
13153
13787
  style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
13154
13788
  refEl: formRef,
13155
13789
  onOpenImageViewer: handleOpenImageViewer,
13156
13790
  onMentionClick: handleAddExistingNode,
13157
13791
  onUploadFile: upload_file_action,
13158
13792
  availableNodes: allAvailableNodes,
13159
- availableAncestries: allAvailableAncestries
13793
+ availableAncestries: allAvailableAncestries,
13794
+ viewName: viewParams == null ? void 0 : viewParams.name,
13795
+ questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
13160
13796
  }
13161
13797
  ),
13162
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React24.createElement(
13798
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React25.createElement(
13163
13799
  "div",
13164
13800
  {
13165
13801
  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"}`,
13166
13802
  style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
13167
13803
  },
13168
- /* @__PURE__ */ React24.createElement(
13804
+ /* @__PURE__ */ React25.createElement(
13169
13805
  "div",
13170
13806
  {
13171
13807
  onPointerDown: (e) => {
@@ -13176,7 +13812,7 @@ function XViewScene({
13176
13812
  title: "Arraste para redimensionar"
13177
13813
  }
13178
13814
  ),
13179
- /* @__PURE__ */ React24.createElement(
13815
+ /* @__PURE__ */ React25.createElement(
13180
13816
  DescriptionReadModePanel,
13181
13817
  {
13182
13818
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -13211,7 +13847,7 @@ function XViewScene({
13211
13847
  }
13212
13848
  )
13213
13849
  ),
13214
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React24.createElement(
13850
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React25.createElement(
13215
13851
  CreateAncestryPanel,
13216
13852
  {
13217
13853
  ancestryMode,
@@ -13238,7 +13874,7 @@ function XViewScene({
13238
13874
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
13239
13875
  }
13240
13876
  ),
13241
- editingAncestryRel.visible && /* @__PURE__ */ React24.createElement(
13877
+ editingAncestryRel.visible && /* @__PURE__ */ React25.createElement(
13242
13878
  AncestryRelationshipPanel,
13243
13879
  {
13244
13880
  data: editingAncestryRel.data,
@@ -13252,7 +13888,28 @@ function XViewScene({
13252
13888
  onUploadFile: upload_file_action
13253
13889
  }
13254
13890
  ),
13255
- detailsNode && /* @__PURE__ */ React24.createElement(
13891
+ detailsNode && detailsNode.is_quest && /* @__PURE__ */ React25.createElement(
13892
+ QuestDetailsPanel,
13893
+ {
13894
+ node: detailsNode,
13895
+ onClose: () => setDetailsNode(null),
13896
+ onSave: (data) => userActionHandlers.handleSaveNodeDetails(actionHandlerContext, data),
13897
+ onNameChange: handleDetailNodeNameChange,
13898
+ onColorChange: handleDetailNodeColorChange,
13899
+ onSizeChange: handleDetailNodeSizeChange,
13900
+ onDataUpdate: setDetailsNode,
13901
+ onOpenImageViewer: handleOpenImageViewer,
13902
+ existingTypes: existingNodeTypes,
13903
+ availableNodes: allAvailableNodes,
13904
+ availableAncestries: allAvailableAncestries,
13905
+ onOpenReference: handleOpenReference,
13906
+ onMentionClick: handleAddExistingNode,
13907
+ onUploadFile: upload_file_action,
13908
+ userRole: userPermissionRole,
13909
+ currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
13910
+ }
13911
+ ),
13912
+ detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React25.createElement(
13256
13913
  NodeDetailsPanel,
13257
13914
  {
13258
13915
  node: detailsNode,
@@ -13279,7 +13936,7 @@ function XViewScene({
13279
13936
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
13280
13937
  }
13281
13938
  ),
13282
- detailsLink && /* @__PURE__ */ React24.createElement(
13939
+ detailsLink && /* @__PURE__ */ React25.createElement(
13283
13940
  RelationshipDetailsPanel,
13284
13941
  {
13285
13942
  link: detailsLink,
@@ -13293,7 +13950,7 @@ function XViewScene({
13293
13950
  userRole: userPermissionRole
13294
13951
  }
13295
13952
  ),
13296
- ancestryLinkDetails && /* @__PURE__ */ React24.createElement(
13953
+ ancestryLinkDetails && /* @__PURE__ */ React25.createElement(
13297
13954
  AncestryLinkDetailsPanel,
13298
13955
  {
13299
13956
  data: ancestryLinkDetails,
@@ -13304,7 +13961,7 @@ function XViewScene({
13304
13961
  onUploadFile: upload_file_action
13305
13962
  }
13306
13963
  ),
13307
- /* @__PURE__ */ React24.createElement(
13964
+ /* @__PURE__ */ React25.createElement(
13308
13965
  "div",
13309
13966
  {
13310
13967
  ref: tooltipRef,
@@ -13331,7 +13988,7 @@ function XViewScene({
13331
13988
  }
13332
13989
  }
13333
13990
  ),
13334
- /* @__PURE__ */ React24.createElement(
13991
+ /* @__PURE__ */ React25.createElement(
13335
13992
  ContextMenu,
13336
13993
  {
13337
13994
  data: contextMenu,
@@ -13354,7 +14011,7 @@ function XViewScene({
13354
14011
  onFocusNode: handleFocusNode
13355
14012
  }
13356
14013
  ),
13357
- /* @__PURE__ */ React24.createElement(
14014
+ /* @__PURE__ */ React25.createElement(
13358
14015
  MultiNodeContextMenu,
13359
14016
  {
13360
14017
  data: multiContextMenu,
@@ -13365,7 +14022,7 @@ function XViewScene({
13365
14022
  onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
13366
14023
  }
13367
14024
  ),
13368
- /* @__PURE__ */ React24.createElement(
14025
+ /* @__PURE__ */ React25.createElement(
13369
14026
  RelationshipContextMenu,
13370
14027
  {
13371
14028
  data: relationshipMenu,
@@ -13383,8 +14040,8 @@ function XViewScene({
13383
14040
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
13384
14041
  }
13385
14042
  ),
13386
- /* @__PURE__ */ React24.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
13387
- /* @__PURE__ */ React24.createElement(
14043
+ /* @__PURE__ */ React25.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
14044
+ /* @__PURE__ */ React25.createElement(
13388
14045
  AncestryBoard,
13389
14046
  {
13390
14047
  isOpen: isAncestryBoardOpen,
@@ -13397,14 +14054,14 @@ function XViewScene({
13397
14054
  userRole: userPermissionRole
13398
14055
  }
13399
14056
  ),
13400
- /* @__PURE__ */ React24.createElement(
14057
+ /* @__PURE__ */ React25.createElement(
13401
14058
  ImportParentFileModal,
13402
14059
  {
13403
14060
  isOpen: isImportModalOpen,
13404
14061
  onClose: () => setIsImportModalOpen(false),
13405
14062
  onConfirm: handleConfirmImport,
13406
14063
  session,
13407
- parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
14064
+ parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
13408
14065
  onFetchAvailableFiles: import_parent_file_modal_get,
13409
14066
  currentViewName: viewParams == null ? void 0 : viewParams.name,
13410
14067
  currentAncestries: ancestryDataRef.current || []
@@ -13441,6 +14098,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
13441
14098
  }
13442
14099
  const sceneData = sceneResponse.data;
13443
14100
  const parentDbObjects = sceneData.parent_dbs || [];
14101
+ if (type && type.toLowerCase().includes("database")) {
14102
+ const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
14103
+ if (!selfExists) {
14104
+ parentDbObjects.push({ db_id: scene_config, owner_id });
14105
+ }
14106
+ }
13444
14107
  const parentResponsesPromises = parentDbObjects.map(
13445
14108
  (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
13446
14109
  );
@@ -13458,21 +14121,32 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
13458
14121
  );
13459
14122
  }
13460
14123
  }
13461
- parentData[scene_config] = {
13462
- dataset_name: "Quests Internas (View)",
13463
- nodes: sceneData.quest_nodes || [],
13464
- links: sceneData.quest_links || []
13465
- };
14124
+ if (type && type.toLowerCase() === "view") {
14125
+ parentData[scene_config] = {
14126
+ dataset_name: "Quests Internas (View)",
14127
+ nodes: sceneData.quest_nodes || [],
14128
+ links: sceneData.quest_links || []
14129
+ };
14130
+ }
13466
14131
  const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
13467
14132
  const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
13468
14133
  const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
13469
14134
  const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
13470
14135
  const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
14136
+ var _a2, _b2;
13471
14137
  const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
13472
14138
  if (nodeTypes.includes("quest")) {
14139
+ const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
14140
+ if (dbQuestNode) {
14141
+ return { ...sceneNode, ...dbQuestNode };
14142
+ }
13473
14143
  return sceneNode;
13474
14144
  }
13475
- return parentNodeMap.get(String(sceneNode.id));
14145
+ const dbNode = parentNodeMap.get(String(sceneNode.id));
14146
+ if (dbNode) {
14147
+ return { ...sceneNode, ...dbNode };
14148
+ }
14149
+ return null;
13476
14150
  }).filter(Boolean);
13477
14151
  const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
13478
14152
  const validatedLinks = (sceneData.links || []).filter((sceneLink) => {