@lv-x-software-house/x_view 1.2.5-dev.1 → 1.2.5-dev.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +321 -57
- package/dist/index.mjs +321 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -149,6 +149,7 @@ function ContextMenu({
|
|
|
149
149
|
const [menuView, setMenuView] = (0, import_react.useState)("main");
|
|
150
150
|
const [selectedAncestry, setSelectedAncestry] = (0, import_react.useState)(null);
|
|
151
151
|
const [versionSubMenu, setVersionSubMenu] = (0, import_react.useState)(null);
|
|
152
|
+
const [labelSubMenu, setLabelSubMenu] = (0, import_react.useState)(null);
|
|
152
153
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react.useState)(false);
|
|
153
154
|
const [selectedQuestStatus, setSelectedQuestStatus] = (0, import_react.useState)(null);
|
|
154
155
|
const ability = (0, import_react.useMemo)(() => defineAbilityFor(userRole), [userRole]);
|
|
@@ -157,6 +158,7 @@ function ContextMenu({
|
|
|
157
158
|
setMenuView("main");
|
|
158
159
|
setSelectedAncestry(null);
|
|
159
160
|
setVersionSubMenu(null);
|
|
161
|
+
setLabelSubMenu(null);
|
|
160
162
|
setSelectedQuestStatus(null);
|
|
161
163
|
}
|
|
162
164
|
}, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
|
|
@@ -172,7 +174,7 @@ function ContextMenu({
|
|
|
172
174
|
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
173
175
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
174
176
|
setMenuPos({ left, top });
|
|
175
|
-
}, [data, menuView, versionSubMenu, selectedQuestStatus]);
|
|
177
|
+
}, [data, menuView, versionSubMenu, labelSubMenu, selectedQuestStatus]);
|
|
176
178
|
(0, import_react.useEffect)(() => {
|
|
177
179
|
if (!data.visible) return;
|
|
178
180
|
const handleClickOutside = (e) => {
|
|
@@ -224,7 +226,21 @@ function ContextMenu({
|
|
|
224
226
|
var _a2;
|
|
225
227
|
return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
|
|
226
228
|
});
|
|
227
|
-
const
|
|
229
|
+
const getLabelForConnection = (conn) => {
|
|
230
|
+
if (conn.direction === "outgoing") return conn.link.source_label || null;
|
|
231
|
+
if (conn.direction === "incoming") return conn.link.target_label || null;
|
|
232
|
+
return null;
|
|
233
|
+
};
|
|
234
|
+
const commonWithLabel = commonConnections.filter((c) => getLabelForConnection(c));
|
|
235
|
+
const commonWithoutLabel = commonConnections.filter((c) => !getLabelForConnection(c));
|
|
236
|
+
const labelGroups = commonWithLabel.reduce((acc, conn) => {
|
|
237
|
+
const label = getLabelForConnection(conn);
|
|
238
|
+
if (!acc[label]) acc[label] = [];
|
|
239
|
+
acc[label].push(conn);
|
|
240
|
+
return acc;
|
|
241
|
+
}, {});
|
|
242
|
+
const labelGroupEntries = Object.entries(labelGroups).sort(([a], [b]) => a.localeCompare(b));
|
|
243
|
+
const groupedConnections = commonWithoutLabel.reduce((acc, conn) => {
|
|
228
244
|
var _a2;
|
|
229
245
|
const { targetNode } = conn;
|
|
230
246
|
const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
|
|
@@ -352,11 +368,32 @@ function ContextMenu({
|
|
|
352
368
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
353
369
|
))));
|
|
354
370
|
};
|
|
371
|
+
const renderLabelSubMenuView = () => {
|
|
372
|
+
const group = labelSubMenu;
|
|
373
|
+
const isScrollable = group.connections.length > 10;
|
|
374
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
375
|
+
setLabelSubMenu(null);
|
|
376
|
+
setMenuView("connections");
|
|
377
|
+
}, className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-1.5 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-violet-400 flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-violet-300/80 truncate", title: group.label }, group.label))), group.connections.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(group.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__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, group.connections.map((conn) => /* @__PURE__ */ import_react.default.createElement(
|
|
378
|
+
"button",
|
|
379
|
+
{
|
|
380
|
+
key: conn.targetNode.id,
|
|
381
|
+
onClick: () => handleExpandAndClose([conn.link]),
|
|
382
|
+
className: baseButtonClass,
|
|
383
|
+
title: `Expandir conex\xE3o com ${conn.targetNode.name}`
|
|
384
|
+
},
|
|
385
|
+
/* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" }), /* @__PURE__ */ import_react.default.createElement("polyline", { points: "12 5 19 12 12 19" })),
|
|
386
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
387
|
+
))));
|
|
388
|
+
};
|
|
355
389
|
const renderConnectionsView = () => {
|
|
356
390
|
if (versionSubMenu) {
|
|
357
391
|
return renderVersionSubMenuView();
|
|
358
392
|
}
|
|
359
|
-
|
|
393
|
+
if (labelSubMenu) {
|
|
394
|
+
return renderLabelSubMenuView();
|
|
395
|
+
}
|
|
396
|
+
const totalItems = availableAncestries.length + labelGroupEntries.length + finalRenderableConnections.length + (questConnections.length > 0 ? 1 : 0);
|
|
360
397
|
const isScrollable = totalItems > 10;
|
|
361
398
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ import_react.default.createElement(
|
|
362
399
|
"button",
|
|
@@ -368,7 +405,20 @@ function ContextMenu({
|
|
|
368
405
|
},
|
|
369
406
|
/* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "21", r: "2" })),
|
|
370
407
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
|
|
371
|
-
))),
|
|
408
|
+
))), labelGroupEntries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${availableAncestries.length > 0 ? "mt-2" : ""} ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), labelGroupEntries.map(([label, conns]) => /* @__PURE__ */ import_react.default.createElement(
|
|
409
|
+
"button",
|
|
410
|
+
{
|
|
411
|
+
key: label,
|
|
412
|
+
onClick: () => {
|
|
413
|
+
setLabelSubMenu({ label, connections: conns });
|
|
414
|
+
},
|
|
415
|
+
className: baseButtonClass,
|
|
416
|
+
title: `Ver grupo: ${label}`
|
|
417
|
+
},
|
|
418
|
+
/* @__PURE__ */ import_react.default.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-violet-400" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })),
|
|
419
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, label),
|
|
420
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-violet-500/20 text-violet-300 rounded-full" }, conns.length)
|
|
421
|
+
))), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, (availableAncestries.length > 0 || labelGroupEntries.length > 0) && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), finalRenderableConnections.map((group) => {
|
|
372
422
|
if (group.isVersionGroup) {
|
|
373
423
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
374
424
|
"button",
|
|
@@ -446,11 +496,18 @@ function ContextMenu({
|
|
|
446
496
|
))));
|
|
447
497
|
};
|
|
448
498
|
const renderAncestryActionsView = () => {
|
|
499
|
+
var _a2, _b2;
|
|
449
500
|
const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
|
|
450
|
-
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
451
|
-
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry);
|
|
501
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
502
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "full");
|
|
503
|
+
onClose();
|
|
504
|
+
}, className: baseButtonClass, title: "Renderizar Ancestralidade Completa" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Renderizar Ancestralidade")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
505
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "ancestry_only");
|
|
506
|
+
onClose();
|
|
507
|
+
}, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Ancestralidade (Radial)" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 2v3m0 14v3m10-10h-3m-14 0H2m15.66-6.34-2.12 2.12m-9.08 9.08-2.12 2.12m13.32 0-2.12-2.12m-9.08-9.08-2.12-2.12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "\xC1rvore de Ancestralidade")), ((_b2 = (_a2 = selectedAncestry == null ? void 0 : selectedAncestry.abstraction_tree) == null ? void 0 : _a2.children) == null ? void 0 : _b2.length) > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
508
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "abstraction_only");
|
|
452
509
|
onClose();
|
|
453
|
-
}, className: baseButtonClass, title: "Renderizar
|
|
510
|
+
}, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Abstra\xE7\xE3o (Vertical)" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 6.5h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10 17.5h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.5 10v4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17.5 10v4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "\xC1rvore de Abstra\xE7\xE3o"))), ability.can("update", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
454
511
|
onEditAncestry == null ? void 0 : onEditAncestry(selectedAncestry);
|
|
455
512
|
onClose();
|
|
456
513
|
}, className: baseButtonClass, title: "Editar Ancestralidade" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M12 20h9" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Editar Ancestralidade")), (ability.can("update", "Ancestry") || ability.can("delete", "Ancestry")) && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), ability.can("delete", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
@@ -697,7 +754,7 @@ function XViewSidebar({
|
|
|
697
754
|
"div",
|
|
698
755
|
{
|
|
699
756
|
ref: containerRef,
|
|
700
|
-
className: "ui-overlay fixed left-0 top-0 h-
|
|
757
|
+
className: "ui-overlay fixed left-0 top-0 h-[100dvh] w-[min(92vw,320px)] z-40 overflow-hidden",
|
|
701
758
|
onPointerDown: swallow,
|
|
702
759
|
onPointerMove: swallow,
|
|
703
760
|
onPointerUp: swallow,
|
|
@@ -706,7 +763,7 @@ function XViewSidebar({
|
|
|
706
763
|
onContextMenu: swallow,
|
|
707
764
|
onDoubleClick: swallow
|
|
708
765
|
},
|
|
709
|
-
/* @__PURE__ */ import_react2.default.createElement("div", { className: "h-full flex flex-col bg-slate-950/80 backdrop-blur-xl border-r border-white/10 shadow-[0_0_40px_rgba(0,0,0,0.45)]" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative px-4 py-3 border-b border-white/10 flex items-center gap-2" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_10px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "text-sm font-medium text-slate-100" }, "Ferramentas"), /* @__PURE__ */ import_react2.default.createElement(
|
|
766
|
+
/* @__PURE__ */ import_react2.default.createElement("div", { className: "h-full flex flex-col overflow-hidden bg-slate-950/80 backdrop-blur-xl border-r border-white/10 shadow-[0_0_40px_rgba(0,0,0,0.45)]" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative px-4 py-3 border-b border-white/10 flex items-center gap-2" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_10px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "text-sm font-medium text-slate-100" }, "Ferramentas"), /* @__PURE__ */ import_react2.default.createElement(
|
|
710
767
|
"button",
|
|
711
768
|
{
|
|
712
769
|
className: "ml-auto p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
@@ -763,7 +820,7 @@ function XViewSidebar({
|
|
|
763
820
|
autoComplete: "off"
|
|
764
821
|
}
|
|
765
822
|
)
|
|
766
|
-
), showList && /* @__PURE__ */ import_react2.default.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[
|
|
823
|
+
), showList && /* @__PURE__ */ import_react2.default.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[min(448px,50dvh)] overflow-y-auto rounded-lg bg-slate-900/95 border border-white/10 shadow-xl" }, filteredAndSorted.length > 0 ? filteredAndSorted.map((n) => {
|
|
767
824
|
const inView = isNodeInView(n.id);
|
|
768
825
|
const active = selectedNodeId === n.id;
|
|
769
826
|
const typeLabel = Array.isArray(n.type) ? n.type.join(", ") : n.type;
|
|
@@ -3139,6 +3196,7 @@ function calculateNodePositions(nodes) {
|
|
|
3139
3196
|
return positions;
|
|
3140
3197
|
}
|
|
3141
3198
|
function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, isSceneBusy, parentData, ancestryData }) {
|
|
3199
|
+
var _a, _b;
|
|
3142
3200
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
3143
3201
|
let content = "";
|
|
3144
3202
|
let positionTarget = null;
|
|
@@ -3151,17 +3209,21 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3151
3209
|
content = generateTooltipHtml(hoveredNode.userData, parentData, ancestryData);
|
|
3152
3210
|
}
|
|
3153
3211
|
} else if (hoveredLink && !isSceneBusy) {
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3212
|
+
const linkData = hoveredLink.userData.isAncestryLink ? hoveredLink.userData.relationship || {} : hoveredLink.userData;
|
|
3213
|
+
const hasContent = ((_a = linkData.name) == null ? void 0 : _a.trim()) || ((_b = linkData.description) == null ? void 0 : _b.trim());
|
|
3214
|
+
if (hasContent) {
|
|
3215
|
+
currentId = `link_${hoveredLink.userData.id}`;
|
|
3216
|
+
if (hoveredLink.userData.isCurved) {
|
|
3217
|
+
const positions = hoveredLink.geometry.attributes.position.array;
|
|
3218
|
+
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
3219
|
+
positionTarget = new THREE2.Vector3(positions[midIndex], positions[midIndex + 1], positions[midIndex + 2]);
|
|
3220
|
+
} else {
|
|
3221
|
+
positionTarget = new THREE2.Vector3().addVectors(hoveredLink.userData.sourceNode.position, hoveredLink.userData.targetNode.position).multiplyScalar(0.5);
|
|
3222
|
+
}
|
|
3223
|
+
isLink = true;
|
|
3224
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
3225
|
+
content = generateLinkTooltipHtml(linkData, parentData, ancestryData);
|
|
3226
|
+
}
|
|
3165
3227
|
}
|
|
3166
3228
|
}
|
|
3167
3229
|
if (positionTarget) {
|
|
@@ -3470,9 +3532,9 @@ function CustomPropertyDisplay({
|
|
|
3470
3532
|
};
|
|
3471
3533
|
const handleRemoveListItem = (j) => setTempProp((p) => ({ ...p, value: p.value.filter((_, k) => k !== j) }));
|
|
3472
3534
|
const handleListItemChange = (j, f, v) => setTempProp((p) => {
|
|
3473
|
-
const
|
|
3474
|
-
|
|
3475
|
-
return { ...p, value:
|
|
3535
|
+
const newValue2 = [...p.value];
|
|
3536
|
+
newValue2[j] = { ...newValue2[j], [f]: v };
|
|
3537
|
+
return { ...p, value: newValue2 };
|
|
3476
3538
|
});
|
|
3477
3539
|
const baseInput = "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-400/60 transition-all duration-150";
|
|
3478
3540
|
const renderEditView = () => {
|
|
@@ -3526,14 +3588,14 @@ function CustomPropertyDisplay({
|
|
|
3526
3588
|
const inputClass = `${baseInput} ${noSpinnerClass}`;
|
|
3527
3589
|
const handleDateTypeChange = (newDateType) => {
|
|
3528
3590
|
var _a3, _b2, _c2;
|
|
3529
|
-
let
|
|
3591
|
+
let newValue2 = { type: newDateType };
|
|
3530
3592
|
if (newDateType === "Date Interval") {
|
|
3531
|
-
|
|
3532
|
-
|
|
3593
|
+
newValue2.start = ((_a3 = tempProp.value) == null ? void 0 : _a3.start) || "";
|
|
3594
|
+
newValue2.end = ((_b2 = tempProp.value) == null ? void 0 : _b2.end) || "";
|
|
3533
3595
|
} else {
|
|
3534
|
-
|
|
3596
|
+
newValue2.value = ((_c2 = tempProp.value) == null ? void 0 : _c2.type) === newDateType ? tempProp.value.value : "";
|
|
3535
3597
|
}
|
|
3536
|
-
handlePropChange("value",
|
|
3598
|
+
handlePropChange("value", newValue2);
|
|
3537
3599
|
};
|
|
3538
3600
|
const handleDateValueChange = (dateField, dateValue) => {
|
|
3539
3601
|
handlePropChange("value", { ...tempProp.value, [dateField]: dateValue });
|
|
@@ -4381,7 +4443,7 @@ ${space}${bullet} `);
|
|
|
4381
4443
|
}
|
|
4382
4444
|
),
|
|
4383
4445
|
/* @__PURE__ */ import_react6.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 shrink-0" }),
|
|
4384
|
-
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-sm font-medium text-slate-200" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ import_react6.default.createElement("button", { onClick: handleClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
|
|
4446
|
+
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shrink-0" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-sm font-medium text-slate-200 truncate" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ import_react6.default.createElement("button", { onClick: handleClose, className: "w-9 h-9 flex-shrink-0 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
|
|
4385
4447
|
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
4386
4448
|
"button",
|
|
4387
4449
|
{
|
|
@@ -5496,7 +5558,7 @@ function AncestryRelationshipPanel({
|
|
|
5496
5558
|
onImageClick: handleImageClickFromText,
|
|
5497
5559
|
onSaveDescription: handleSaveDescriptionInline
|
|
5498
5560
|
}
|
|
5499
|
-
) : /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react9.default.createElement("div",
|
|
5561
|
+
) : /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-cyan-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o de Ancestralidade")), /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Editar Rela\xE7\xE3o")), /* @__PURE__ */ import_react9.default.createElement("button", { onClick: onClose, className: "w-9 h-9 flex-shrink-0 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")), /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 pb-4 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react9.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o da Rela\xE7\xE3o"), /* @__PURE__ */ import_react9.default.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__ */ import_react9.default.createElement(
|
|
5500
5562
|
DescriptionDisplay,
|
|
5501
5563
|
{
|
|
5502
5564
|
description,
|
|
@@ -5801,6 +5863,7 @@ function CreateAncestryPanel({
|
|
|
5801
5863
|
} = ancestryMode;
|
|
5802
5864
|
const [isSaving, setIsSaving] = (0, import_react11.useState)(false);
|
|
5803
5865
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react11.useState)(false);
|
|
5866
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react11.useState)(false);
|
|
5804
5867
|
const [showDeleteBranchConfirm, setShowDeleteBranchConfirm] = (0, import_react11.useState)(false);
|
|
5805
5868
|
const handleCopyLink = (e) => {
|
|
5806
5869
|
e.stopPropagation();
|
|
@@ -5868,12 +5931,14 @@ function CreateAncestryPanel({
|
|
|
5868
5931
|
};
|
|
5869
5932
|
const handleSelectAncestryParent = (nodeId, isAbstraction = false) => {
|
|
5870
5933
|
setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
|
|
5934
|
+
setHasUnsavedChanges(true);
|
|
5871
5935
|
};
|
|
5872
5936
|
const handleToggleAddMode = (isAbstraction = false) => {
|
|
5873
5937
|
if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
|
|
5874
5938
|
setTargetRenderNodeId(null);
|
|
5875
5939
|
}
|
|
5876
5940
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5941
|
+
setHasUnsavedChanges(true);
|
|
5877
5942
|
};
|
|
5878
5943
|
const handleRemoveNode = (0, import_react11.useCallback)((pathToRemove, isAbstraction = false) => {
|
|
5879
5944
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
@@ -5891,6 +5956,7 @@ function CreateAncestryPanel({
|
|
|
5891
5956
|
const indexToRemove = pathToRemove[pathToRemove.length - 1];
|
|
5892
5957
|
if (currentParent.children && currentParent.children.length > indexToRemove) {
|
|
5893
5958
|
currentParent.children.splice(indexToRemove, 1);
|
|
5959
|
+
setHasUnsavedChanges(true);
|
|
5894
5960
|
}
|
|
5895
5961
|
return { ...prev, [treeKey]: newTree };
|
|
5896
5962
|
});
|
|
@@ -5949,6 +6015,7 @@ function CreateAncestryPanel({
|
|
|
5949
6015
|
updateGlobalTree(rootTreeClone);
|
|
5950
6016
|
}
|
|
5951
6017
|
setAncestryMode((prev) => ({ ...prev, [treeKey]: rootTreeClone }));
|
|
6018
|
+
setHasUnsavedChanges(true);
|
|
5952
6019
|
} else {
|
|
5953
6020
|
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5954
6021
|
}
|
|
@@ -6021,6 +6088,7 @@ function CreateAncestryPanel({
|
|
|
6021
6088
|
const handleAddProp = () => {
|
|
6022
6089
|
const newProp = createNewCustomProperty(customProps);
|
|
6023
6090
|
setCustomProps((p) => [...p, newProp]);
|
|
6091
|
+
setHasUnsavedChanges(true);
|
|
6024
6092
|
setTimeout(() => {
|
|
6025
6093
|
var _a;
|
|
6026
6094
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -6029,11 +6097,13 @@ function CreateAncestryPanel({
|
|
|
6029
6097
|
const handleRemoveProp = (i) => {
|
|
6030
6098
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
6031
6099
|
setCustomProps(newProps);
|
|
6100
|
+
setHasUnsavedChanges(true);
|
|
6032
6101
|
};
|
|
6033
6102
|
const handleUpdateProp = (index, updatedProp) => {
|
|
6034
6103
|
const newProps = [...customProps];
|
|
6035
6104
|
newProps[index] = updatedProp;
|
|
6036
6105
|
setCustomProps(newProps);
|
|
6106
|
+
setHasUnsavedChanges(true);
|
|
6037
6107
|
};
|
|
6038
6108
|
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
6039
6109
|
(0, import_react11.useEffect)(() => {
|
|
@@ -6143,6 +6213,7 @@ function CreateAncestryPanel({
|
|
|
6143
6213
|
updateGlobalTree(rootTreeClone);
|
|
6144
6214
|
setBranchStack([...branchStack]);
|
|
6145
6215
|
setIsPickerOpen(false);
|
|
6216
|
+
setHasUnsavedChanges(true);
|
|
6146
6217
|
try {
|
|
6147
6218
|
setIsSaving(true);
|
|
6148
6219
|
const rootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6156,6 +6227,7 @@ function CreateAncestryPanel({
|
|
|
6156
6227
|
rootExtras
|
|
6157
6228
|
);
|
|
6158
6229
|
setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate, ancestryMode.abstraction_tree));
|
|
6230
|
+
setHasUnsavedChanges(false);
|
|
6159
6231
|
if (onRenderFullAncestry) {
|
|
6160
6232
|
const fullTreePayload = {
|
|
6161
6233
|
ancestry_id: ancestryMode.currentAncestryId || "temp_root",
|
|
@@ -6198,6 +6270,7 @@ function CreateAncestryPanel({
|
|
|
6198
6270
|
if (branchIndex !== -1) {
|
|
6199
6271
|
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
6200
6272
|
updateGlobalTree(rootTreeClone);
|
|
6273
|
+
setHasUnsavedChanges(true);
|
|
6201
6274
|
try {
|
|
6202
6275
|
setIsSaving(true);
|
|
6203
6276
|
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6219,6 +6292,7 @@ function CreateAncestryPanel({
|
|
|
6219
6292
|
isPrivate,
|
|
6220
6293
|
ancestryMode.abstraction_tree
|
|
6221
6294
|
));
|
|
6295
|
+
setHasUnsavedChanges(false);
|
|
6222
6296
|
if (onClearAncestryVisuals) {
|
|
6223
6297
|
onClearAncestryVisuals(currentStep.branchId);
|
|
6224
6298
|
}
|
|
@@ -6251,6 +6325,7 @@ function CreateAncestryPanel({
|
|
|
6251
6325
|
if (branchIndex !== -1) {
|
|
6252
6326
|
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
6253
6327
|
updateGlobalTree(rootTreeClone);
|
|
6328
|
+
setHasUnsavedChanges(true);
|
|
6254
6329
|
try {
|
|
6255
6330
|
setIsSaving(true);
|
|
6256
6331
|
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6272,6 +6347,7 @@ function CreateAncestryPanel({
|
|
|
6272
6347
|
isPrivate,
|
|
6273
6348
|
ancestryMode.abstraction_tree
|
|
6274
6349
|
));
|
|
6350
|
+
setHasUnsavedChanges(false);
|
|
6275
6351
|
if (onClearAncestryVisuals) {
|
|
6276
6352
|
onClearAncestryVisuals(currentStep.branchId);
|
|
6277
6353
|
}
|
|
@@ -6533,6 +6609,7 @@ function CreateAncestryPanel({
|
|
|
6533
6609
|
}
|
|
6534
6610
|
setBranchStack(parentStack);
|
|
6535
6611
|
setTargetScrollSectionId(targetFocusId);
|
|
6612
|
+
setHasUnsavedChanges(true);
|
|
6536
6613
|
if (onRenderFullAncestry) {
|
|
6537
6614
|
const parentStack2 = currentStack;
|
|
6538
6615
|
const rotation = parentStack2.reduce((acc, step) => {
|
|
@@ -6594,7 +6671,6 @@ function CreateAncestryPanel({
|
|
|
6594
6671
|
direction,
|
|
6595
6672
|
tree: {
|
|
6596
6673
|
node: nodeData,
|
|
6597
|
-
node_id: nodeId,
|
|
6598
6674
|
children: [],
|
|
6599
6675
|
relationship: {}
|
|
6600
6676
|
}
|
|
@@ -6616,6 +6692,7 @@ function CreateAncestryPanel({
|
|
|
6616
6692
|
savedMaxIndex: parentIndexToSave,
|
|
6617
6693
|
entryDirection: direction
|
|
6618
6694
|
}]);
|
|
6695
|
+
setHasUnsavedChanges(true);
|
|
6619
6696
|
if (branch && branch.tree && onRenderFullAncestry) {
|
|
6620
6697
|
const branchAncestryObj = {
|
|
6621
6698
|
ancestry_id: branch.id,
|
|
@@ -6666,6 +6743,10 @@ function CreateAncestryPanel({
|
|
|
6666
6743
|
const currentInputName = overrides.ancestryName !== void 0 ? overrides.ancestryName : ancestryName;
|
|
6667
6744
|
const currentInputDesc = overrides.description !== void 0 ? overrides.description : description;
|
|
6668
6745
|
const currentInputSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
6746
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
6747
|
+
onClose();
|
|
6748
|
+
return;
|
|
6749
|
+
}
|
|
6669
6750
|
if (!currentInputName.trim()) {
|
|
6670
6751
|
alert("O nome n\xE3o pode estar vazio.");
|
|
6671
6752
|
return;
|
|
@@ -6673,11 +6754,7 @@ function CreateAncestryPanel({
|
|
|
6673
6754
|
setIsSaving(true);
|
|
6674
6755
|
const processedSections = processDescriptionForSave(currentInputDesc, currentInputSections);
|
|
6675
6756
|
setExistingSections(processedSections);
|
|
6676
|
-
const updatedRootTree =
|
|
6677
|
-
ancestryMode.tree,
|
|
6678
|
-
currentInputDesc,
|
|
6679
|
-
processedSections
|
|
6680
|
-
);
|
|
6757
|
+
const updatedRootTree = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
6681
6758
|
const extrasObj = {
|
|
6682
6759
|
...toObjectFromCustomProps(customProps.filter((p) => !p.isEditing)),
|
|
6683
6760
|
is_private: isPrivate
|
|
@@ -6719,6 +6796,7 @@ function CreateAncestryPanel({
|
|
|
6719
6796
|
isPrivate,
|
|
6720
6797
|
ancestryMode.abstraction_tree
|
|
6721
6798
|
));
|
|
6799
|
+
setHasUnsavedChanges(false);
|
|
6722
6800
|
if (onRenderFullAncestry) {
|
|
6723
6801
|
const rotation = branchStack.reduce((acc, step) => {
|
|
6724
6802
|
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
@@ -6770,6 +6848,7 @@ function CreateAncestryPanel({
|
|
|
6770
6848
|
updatedRootTree,
|
|
6771
6849
|
extrasObj
|
|
6772
6850
|
);
|
|
6851
|
+
setHasUnsavedChanges(false);
|
|
6773
6852
|
setLastSavedSnapshot(takeSnapshot(
|
|
6774
6853
|
updatedRootTree,
|
|
6775
6854
|
currentInputName,
|
|
@@ -6792,6 +6871,7 @@ function CreateAncestryPanel({
|
|
|
6792
6871
|
const newTreeString = JSON.stringify(newRootTree);
|
|
6793
6872
|
if (currentTreeString !== newTreeString) {
|
|
6794
6873
|
updateGlobalTree(newRootTree);
|
|
6874
|
+
setHasUnsavedChanges(true);
|
|
6795
6875
|
}
|
|
6796
6876
|
}, [description, existingSections]);
|
|
6797
6877
|
const handleTriggerFullRender = () => {
|
|
@@ -6814,6 +6894,7 @@ function CreateAncestryPanel({
|
|
|
6814
6894
|
};
|
|
6815
6895
|
const handleSaveDescriptionInline = (newDesc) => {
|
|
6816
6896
|
setDescription(newDesc);
|
|
6897
|
+
setHasUnsavedChanges(true);
|
|
6817
6898
|
handleLocalSave(true, { description: newDesc });
|
|
6818
6899
|
};
|
|
6819
6900
|
const swallow = (e) => e.stopPropagation();
|
|
@@ -6943,7 +7024,11 @@ function CreateAncestryPanel({
|
|
|
6943
7024
|
{
|
|
6944
7025
|
type: "text",
|
|
6945
7026
|
value: ancestryName,
|
|
6946
|
-
onChange: (e) =>
|
|
7027
|
+
onChange: (e) => {
|
|
7028
|
+
setAncestryName(e.target.value);
|
|
7029
|
+
setHasUnsavedChanges(true);
|
|
7030
|
+
},
|
|
7031
|
+
readOnly: isContextLinked,
|
|
6947
7032
|
placeholder: "Nome da Ancestralidade",
|
|
6948
7033
|
className: "text-xl sm:text-2xl font-semibold tracking-tight bg-transparent border-none p-0 focus:ring-2 focus:ring-indigo-500 rounded-md -ml-1.5 px-1.5 w-full outline-none transition-all focus:bg-slate-800/70"
|
|
6949
7034
|
}
|
|
@@ -7592,9 +7677,9 @@ function InSceneCreationForm({
|
|
|
7592
7677
|
};
|
|
7593
7678
|
const handleToggleImageMode = () => {
|
|
7594
7679
|
var _a2, _b;
|
|
7595
|
-
const
|
|
7596
|
-
setUseImageAsTexture(
|
|
7597
|
-
if (
|
|
7680
|
+
const newValue2 = !useImageAsTexture;
|
|
7681
|
+
setUseImageAsTexture(newValue2);
|
|
7682
|
+
if (newValue2) {
|
|
7598
7683
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
7599
7684
|
if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
|
|
7600
7685
|
const url = firstImageProp.value[0].value;
|
|
@@ -7892,9 +7977,9 @@ function InSceneVersionForm({
|
|
|
7892
7977
|
};
|
|
7893
7978
|
const handleToggleImageMode = () => {
|
|
7894
7979
|
var _a, _b;
|
|
7895
|
-
const
|
|
7896
|
-
setUseImageAsTexture(
|
|
7897
|
-
if (
|
|
7980
|
+
const newValue2 = !useImageAsTexture;
|
|
7981
|
+
setUseImageAsTexture(newValue2);
|
|
7982
|
+
if (newValue2) {
|
|
7898
7983
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
7899
7984
|
if (firstImageProp && ((_b = (_a = firstImageProp.value) == null ? void 0 : _a[0]) == null ? void 0 : _b.value)) {
|
|
7900
7985
|
const url = firstImageProp.value[0].value;
|
|
@@ -8314,6 +8399,7 @@ function NodeDetailsPanel({
|
|
|
8314
8399
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
8315
8400
|
});
|
|
8316
8401
|
const [selectedImageUrl, setSelectedImageUrl] = (0, import_react17.useState)((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
8402
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react17.useState)(false);
|
|
8317
8403
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8318
8404
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8319
8405
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -8351,6 +8437,7 @@ function NodeDetailsPanel({
|
|
|
8351
8437
|
else if ((node == null ? void 0 : node.useImageAsTexture) === "false") setUseImageAsTexture(false);
|
|
8352
8438
|
else setUseImageAsTexture(!!(node == null ? void 0 : node.useImageAsTexture));
|
|
8353
8439
|
setSelectedImageUrl((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
8440
|
+
setHasUnsavedChanges(false);
|
|
8354
8441
|
}
|
|
8355
8442
|
}, [node]);
|
|
8356
8443
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
@@ -8377,6 +8464,7 @@ function NodeDetailsPanel({
|
|
|
8377
8464
|
setIntensity(val);
|
|
8378
8465
|
onIntensityChange == null ? void 0 : onIntensityChange(node.id, val);
|
|
8379
8466
|
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, intensity: val });
|
|
8467
|
+
setHasUnsavedChanges(true);
|
|
8380
8468
|
};
|
|
8381
8469
|
const handleCopyLink = () => {
|
|
8382
8470
|
if (!(node == null ? void 0 : node.id)) return;
|
|
@@ -8394,14 +8482,17 @@ function NodeDetailsPanel({
|
|
|
8394
8482
|
const v = e.target.value;
|
|
8395
8483
|
setName(v);
|
|
8396
8484
|
onNameChange == null ? void 0 : onNameChange(node.id, v);
|
|
8485
|
+
setHasUnsavedChanges(true);
|
|
8397
8486
|
};
|
|
8398
8487
|
const handleColorChange = (val) => {
|
|
8399
8488
|
setColor(val);
|
|
8400
8489
|
onColorChange == null ? void 0 : onColorChange(node.id, val);
|
|
8490
|
+
setHasUnsavedChanges(true);
|
|
8401
8491
|
};
|
|
8402
8492
|
const handleSizeChange = (newSize) => {
|
|
8403
8493
|
setSize(newSize);
|
|
8404
8494
|
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
8495
|
+
setHasUnsavedChanges(true);
|
|
8405
8496
|
};
|
|
8406
8497
|
const handleAddType = (newType) => {
|
|
8407
8498
|
const trimmed = newType.trim();
|
|
@@ -8409,10 +8500,12 @@ function NodeDetailsPanel({
|
|
|
8409
8500
|
setTypes([...types, trimmed]);
|
|
8410
8501
|
setTypeInput("");
|
|
8411
8502
|
setShowTypeSuggestions(false);
|
|
8503
|
+
setHasUnsavedChanges(true);
|
|
8412
8504
|
}
|
|
8413
8505
|
};
|
|
8414
8506
|
const handleRemoveType = (indexToRemove) => {
|
|
8415
8507
|
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
8508
|
+
setHasUnsavedChanges(true);
|
|
8416
8509
|
};
|
|
8417
8510
|
const handleTypeInputKeyDown = (e) => {
|
|
8418
8511
|
if (e.key === "Enter") {
|
|
@@ -8425,6 +8518,7 @@ function NodeDetailsPanel({
|
|
|
8425
8518
|
const handleAddProp = () => {
|
|
8426
8519
|
const newProp = createNewCustomProperty(customProps);
|
|
8427
8520
|
setCustomProps((p) => [...p, newProp]);
|
|
8521
|
+
setHasUnsavedChanges(true);
|
|
8428
8522
|
setTimeout(() => {
|
|
8429
8523
|
var _a;
|
|
8430
8524
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -8433,19 +8527,21 @@ function NodeDetailsPanel({
|
|
|
8433
8527
|
const handleRemoveProp = (i) => {
|
|
8434
8528
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8435
8529
|
setCustomProps(newProps);
|
|
8530
|
+
setHasUnsavedChanges(true);
|
|
8436
8531
|
triggerAutoSave({ customProps: newProps });
|
|
8437
8532
|
};
|
|
8438
8533
|
const handleUpdateProp = (index, updatedProp) => {
|
|
8439
8534
|
const newProps = [...customProps];
|
|
8440
8535
|
newProps[index] = updatedProp;
|
|
8441
8536
|
setCustomProps(newProps);
|
|
8537
|
+
setHasUnsavedChanges(true);
|
|
8442
8538
|
if (!updatedProp.isEditing) {
|
|
8443
8539
|
triggerAutoSave({ customProps: newProps });
|
|
8444
8540
|
}
|
|
8445
8541
|
};
|
|
8446
8542
|
const handleToggleImageMode = () => {
|
|
8447
|
-
const newValue = !useImageAsTexture;
|
|
8448
8543
|
setUseImageAsTexture(newValue);
|
|
8544
|
+
setHasUnsavedChanges(true);
|
|
8449
8545
|
let activeUrl = null;
|
|
8450
8546
|
if (newValue) {
|
|
8451
8547
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
@@ -8467,6 +8563,7 @@ function NodeDetailsPanel({
|
|
|
8467
8563
|
};
|
|
8468
8564
|
const handleSelectTexture = (url) => {
|
|
8469
8565
|
setSelectedImageUrl(url);
|
|
8566
|
+
setHasUnsavedChanges(true);
|
|
8470
8567
|
onImageChange == null ? void 0 : onImageChange(true, url, color);
|
|
8471
8568
|
onDataUpdate == null ? void 0 : onDataUpdate({
|
|
8472
8569
|
...node,
|
|
@@ -8477,6 +8574,7 @@ function NodeDetailsPanel({
|
|
|
8477
8574
|
};
|
|
8478
8575
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
8479
8576
|
setDescription(newDescription);
|
|
8577
|
+
setHasUnsavedChanges(true);
|
|
8480
8578
|
onDataUpdate({ ...node, description: newDescription });
|
|
8481
8579
|
triggerAutoSave({ description: newDescription });
|
|
8482
8580
|
};
|
|
@@ -8487,6 +8585,10 @@ function NodeDetailsPanel({
|
|
|
8487
8585
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8488
8586
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8489
8587
|
const currentIntensity = overrides.intensity !== void 0 ? overrides.intensity : intensity;
|
|
8588
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
8589
|
+
onClose();
|
|
8590
|
+
return;
|
|
8591
|
+
}
|
|
8490
8592
|
if (!currentName.trim() || currentTypes.length === 0) {
|
|
8491
8593
|
alert("O campo 'Nome' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8492
8594
|
return;
|
|
@@ -8511,6 +8613,7 @@ function NodeDetailsPanel({
|
|
|
8511
8613
|
};
|
|
8512
8614
|
await onSave(dataToSave, keepOpen);
|
|
8513
8615
|
onDataUpdate(dataToSave);
|
|
8616
|
+
setHasUnsavedChanges(false);
|
|
8514
8617
|
if (!keepOpen) {
|
|
8515
8618
|
onClose();
|
|
8516
8619
|
}
|
|
@@ -8577,7 +8680,7 @@ function NodeDetailsPanel({
|
|
|
8577
8680
|
onImageClick: handleImageClickFromText,
|
|
8578
8681
|
onSaveDescription: handleSaveDescriptionInline
|
|
8579
8682
|
}
|
|
8580
|
-
) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react17.default.createElement("div",
|
|
8683
|
+
) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react17.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react17.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ import_react17.default.createElement(
|
|
8581
8684
|
"button",
|
|
8582
8685
|
{
|
|
8583
8686
|
onClick: handleCopyLink,
|
|
@@ -8585,7 +8688,7 @@ function NodeDetailsPanel({
|
|
|
8585
8688
|
title: isLinkCopied ? "Link Copiado!" : "Copiar link para este Node"
|
|
8586
8689
|
},
|
|
8587
8690
|
isLinkCopied ? /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiLink, { size: 12 })
|
|
8588
|
-
)), /* @__PURE__ */ import_react17.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react17.default.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__ */ import_react17.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react17.default.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__ */ import_react17.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react17.default.createElement(
|
|
8691
|
+
)), /* @__PURE__ */ import_react17.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react17.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 flex-shrink-0 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__ */ import_react17.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react17.default.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__ */ import_react17.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react17.default.createElement(
|
|
8589
8692
|
"button",
|
|
8590
8693
|
{
|
|
8591
8694
|
type: "button",
|
|
@@ -8747,6 +8850,7 @@ function NodeDetailsPanel({
|
|
|
8747
8850
|
initialValue: description,
|
|
8748
8851
|
onSave: (newDescription) => {
|
|
8749
8852
|
setDescription(newDescription);
|
|
8853
|
+
setHasUnsavedChanges(true);
|
|
8750
8854
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8751
8855
|
triggerAutoSave({ description: newDescription });
|
|
8752
8856
|
},
|
|
@@ -8806,6 +8910,7 @@ function QuestDetailsPanel({
|
|
|
8806
8910
|
const [existingSections, setExistingSections] = (0, import_react18.useState)((node == null ? void 0 : node.description_sections) || []);
|
|
8807
8911
|
const [isSaving, setIsSaving] = (0, import_react18.useState)(false);
|
|
8808
8912
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react18.useState)(false);
|
|
8913
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react18.useState)(false);
|
|
8809
8914
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8810
8915
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8811
8916
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -8837,6 +8942,7 @@ function QuestDetailsPanel({
|
|
|
8837
8942
|
setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8838
8943
|
setExistingSections((node == null ? void 0 : node.description_sections) || []);
|
|
8839
8944
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
8945
|
+
setHasUnsavedChanges(false);
|
|
8840
8946
|
}
|
|
8841
8947
|
}, [node]);
|
|
8842
8948
|
(0, import_react18.useEffect)(() => {
|
|
@@ -8868,16 +8974,19 @@ function QuestDetailsPanel({
|
|
|
8868
8974
|
setRawTitle(val);
|
|
8869
8975
|
const newStandardName = questPrefix ? `${questPrefix} - \xBB ${val || "Sem t\xEDtulo"}` : val;
|
|
8870
8976
|
onNameChange == null ? void 0 : onNameChange(node.id, newStandardName, val);
|
|
8977
|
+
setHasUnsavedChanges(true);
|
|
8871
8978
|
};
|
|
8872
8979
|
const handleSizeChange = (newSize) => {
|
|
8873
8980
|
setSize(newSize);
|
|
8874
8981
|
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
8982
|
+
setHasUnsavedChanges(true);
|
|
8875
8983
|
};
|
|
8876
8984
|
const handleStatusChange = (newStatus) => {
|
|
8877
8985
|
setStatus(newStatus);
|
|
8878
8986
|
const newColor = QUEST_STATUS_COLORS3[newStatus];
|
|
8879
8987
|
onColorChange == null ? void 0 : onColorChange(node.id, newColor);
|
|
8880
8988
|
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
|
|
8989
|
+
setHasUnsavedChanges(true);
|
|
8881
8990
|
};
|
|
8882
8991
|
const handleAddType = (newType) => {
|
|
8883
8992
|
const trimmed = newType.trim();
|
|
@@ -8885,11 +8994,13 @@ function QuestDetailsPanel({
|
|
|
8885
8994
|
setTypes([...types, trimmed]);
|
|
8886
8995
|
setTypeInput("");
|
|
8887
8996
|
setShowTypeSuggestions(false);
|
|
8997
|
+
setHasUnsavedChanges(true);
|
|
8888
8998
|
}
|
|
8889
8999
|
};
|
|
8890
9000
|
const handleRemoveType = (indexToRemove) => {
|
|
8891
9001
|
if (types[indexToRemove] === "quest") return;
|
|
8892
9002
|
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
9003
|
+
setHasUnsavedChanges(true);
|
|
8893
9004
|
};
|
|
8894
9005
|
const handleTypeInputKeyDown = (e) => {
|
|
8895
9006
|
if (e.key === "Enter") {
|
|
@@ -8902,6 +9013,7 @@ function QuestDetailsPanel({
|
|
|
8902
9013
|
const handleAddProp = () => {
|
|
8903
9014
|
const newProp = createNewCustomProperty(customProps);
|
|
8904
9015
|
setCustomProps((p) => [...p, newProp]);
|
|
9016
|
+
setHasUnsavedChanges(true);
|
|
8905
9017
|
setTimeout(() => {
|
|
8906
9018
|
var _a2;
|
|
8907
9019
|
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -8910,18 +9022,21 @@ function QuestDetailsPanel({
|
|
|
8910
9022
|
const handleRemoveProp = (i) => {
|
|
8911
9023
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8912
9024
|
setCustomProps(newProps);
|
|
9025
|
+
setHasUnsavedChanges(true);
|
|
8913
9026
|
triggerAutoSave({ customProps: newProps });
|
|
8914
9027
|
};
|
|
8915
9028
|
const handleUpdateProp = (index, updatedProp) => {
|
|
8916
9029
|
const newProps = [...customProps];
|
|
8917
9030
|
newProps[index] = updatedProp;
|
|
8918
9031
|
setCustomProps(newProps);
|
|
9032
|
+
setHasUnsavedChanges(true);
|
|
8919
9033
|
if (!updatedProp.isEditing) {
|
|
8920
9034
|
triggerAutoSave({ customProps: newProps });
|
|
8921
9035
|
}
|
|
8922
9036
|
};
|
|
8923
9037
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
8924
9038
|
setDescription(newDescription);
|
|
9039
|
+
setHasUnsavedChanges(true);
|
|
8925
9040
|
onDataUpdate({ ...node, description: newDescription });
|
|
8926
9041
|
triggerAutoSave({ description: newDescription });
|
|
8927
9042
|
};
|
|
@@ -8933,6 +9048,10 @@ function QuestDetailsPanel({
|
|
|
8933
9048
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8934
9049
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8935
9050
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
9051
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
9052
|
+
onClose();
|
|
9053
|
+
return;
|
|
9054
|
+
}
|
|
8936
9055
|
if (!currentRawTitle.trim() || currentTypes.length === 0) {
|
|
8937
9056
|
alert("O campo 'T\xEDtulo' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8938
9057
|
return;
|
|
@@ -8962,6 +9081,7 @@ function QuestDetailsPanel({
|
|
|
8962
9081
|
};
|
|
8963
9082
|
await onSave(dataToSave, keepOpen);
|
|
8964
9083
|
onDataUpdate(dataToSave);
|
|
9084
|
+
setHasUnsavedChanges(false);
|
|
8965
9085
|
if (!keepOpen) {
|
|
8966
9086
|
onClose();
|
|
8967
9087
|
}
|
|
@@ -9019,7 +9139,7 @@ function QuestDetailsPanel({
|
|
|
9019
9139
|
onImageClick: handleImageClickFromText,
|
|
9020
9140
|
onSaveDescription: handleSaveDescriptionInline
|
|
9021
9141
|
}
|
|
9022
|
-
) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react18.default.createElement("div",
|
|
9142
|
+
) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiLink, { size: 12 }))), /* @__PURE__ */ import_react18.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 flex-shrink-0 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__ */ import_react18.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react18.default.createElement(
|
|
9023
9143
|
"input",
|
|
9024
9144
|
{
|
|
9025
9145
|
type: "text",
|
|
@@ -9193,9 +9313,12 @@ function RelationshipDetailsPanel({
|
|
|
9193
9313
|
const [description, setDescription] = (0, import_react20.useState)((link == null ? void 0 : link.description) ?? "");
|
|
9194
9314
|
const [customProps, setCustomProps] = (0, import_react20.useState)(() => extractCustomPropsFromNode(link || {}));
|
|
9195
9315
|
const [existingSections, setExistingSections] = (0, import_react20.useState)((link == null ? void 0 : link.description_sections) || []);
|
|
9316
|
+
const [sourceLabel, setSourceLabel] = (0, import_react20.useState)((link == null ? void 0 : link.source_label) ?? "");
|
|
9317
|
+
const [targetLabel, setTargetLabel] = (0, import_react20.useState)((link == null ? void 0 : link.target_label) ?? "");
|
|
9196
9318
|
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react20.useState)(false);
|
|
9197
9319
|
const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
|
|
9198
9320
|
const [isReadMode, setIsReadMode] = (0, import_react20.useState)(false);
|
|
9321
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
|
|
9199
9322
|
const propsEndRef = (0, import_react20.useRef)(null);
|
|
9200
9323
|
const canEdit = (0, import_react20.useMemo)(() => {
|
|
9201
9324
|
const ability = defineAbilityFor(userRole);
|
|
@@ -9206,12 +9329,16 @@ function RelationshipDetailsPanel({
|
|
|
9206
9329
|
setDescription((link == null ? void 0 : link.description) ?? "");
|
|
9207
9330
|
setExistingSections((link == null ? void 0 : link.description_sections) || []);
|
|
9208
9331
|
setCustomProps(extractCustomPropsFromNode(link || {}));
|
|
9332
|
+
setSourceLabel((link == null ? void 0 : link.source_label) ?? "");
|
|
9333
|
+
setTargetLabel((link == null ? void 0 : link.target_label) ?? "");
|
|
9334
|
+
setHasUnsavedChanges(false);
|
|
9209
9335
|
}, [link]);
|
|
9210
9336
|
const swallow = (e) => e.stopPropagation();
|
|
9211
9337
|
const handleAddProp = () => {
|
|
9212
9338
|
if (!canEdit) return;
|
|
9213
9339
|
const newProp = createNewCustomProperty(customProps);
|
|
9214
9340
|
setCustomProps((p) => [...p, newProp]);
|
|
9341
|
+
setHasUnsavedChanges(true);
|
|
9215
9342
|
setTimeout(() => {
|
|
9216
9343
|
var _a;
|
|
9217
9344
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -9223,6 +9350,12 @@ function RelationshipDetailsPanel({
|
|
|
9223
9350
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
9224
9351
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
9225
9352
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
9353
|
+
const currentSourceLabel = overrides.sourceLabel !== void 0 ? overrides.sourceLabel : sourceLabel;
|
|
9354
|
+
const currentTargetLabel = overrides.targetLabel !== void 0 ? overrides.targetLabel : targetLabel;
|
|
9355
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
9356
|
+
onClose();
|
|
9357
|
+
return;
|
|
9358
|
+
}
|
|
9226
9359
|
setIsSaving(true);
|
|
9227
9360
|
try {
|
|
9228
9361
|
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
@@ -9238,8 +9371,11 @@ function RelationshipDetailsPanel({
|
|
|
9238
9371
|
isCurved: link.isCurved,
|
|
9239
9372
|
curveOffset: link.curveOffset
|
|
9240
9373
|
};
|
|
9374
|
+
if (currentSourceLabel.trim()) dataToSave.source_label = currentSourceLabel.trim();
|
|
9375
|
+
if (currentTargetLabel.trim()) dataToSave.target_label = currentTargetLabel.trim();
|
|
9241
9376
|
await onSave(dataToSave, keepOpen);
|
|
9242
9377
|
onDataUpdate(dataToSave);
|
|
9378
|
+
setHasUnsavedChanges(false);
|
|
9243
9379
|
if (!keepOpen) {
|
|
9244
9380
|
onClose();
|
|
9245
9381
|
}
|
|
@@ -9253,18 +9389,21 @@ function RelationshipDetailsPanel({
|
|
|
9253
9389
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
9254
9390
|
if (!canEdit) return;
|
|
9255
9391
|
setDescription(newDescription);
|
|
9392
|
+
setHasUnsavedChanges(true);
|
|
9256
9393
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9257
9394
|
triggerAutoSave({ description: newDescription });
|
|
9258
9395
|
};
|
|
9259
9396
|
const handleRemoveProp = (i) => {
|
|
9260
9397
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
9261
9398
|
setCustomProps(newProps);
|
|
9399
|
+
setHasUnsavedChanges(true);
|
|
9262
9400
|
triggerAutoSave({ customProps: newProps });
|
|
9263
9401
|
};
|
|
9264
9402
|
const handleUpdateProp = (index, updatedProp) => {
|
|
9265
9403
|
const newProps = [...customProps];
|
|
9266
9404
|
newProps[index] = updatedProp;
|
|
9267
9405
|
setCustomProps(newProps);
|
|
9406
|
+
setHasUnsavedChanges(true);
|
|
9268
9407
|
if (!updatedProp.isEditing) {
|
|
9269
9408
|
triggerAutoSave({ customProps: newProps });
|
|
9270
9409
|
}
|
|
@@ -9312,19 +9451,52 @@ function RelationshipDetailsPanel({
|
|
|
9312
9451
|
onImageClick: handleImageClickFromText,
|
|
9313
9452
|
onSaveDescription: handleSaveDescriptionInline
|
|
9314
9453
|
}
|
|
9315
|
-
) : /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ import_react20.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react20.default.createElement("div",
|
|
9454
|
+
) : /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ import_react20.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ import_react20.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ import_react20.default.createElement("button", { onClick: onClose, disabled: isSaving, className: "w-9 h-9 flex-shrink-0 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__ */ import_react20.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ import_react20.default.createElement(
|
|
9316
9455
|
"input",
|
|
9317
9456
|
{
|
|
9318
9457
|
type: "text",
|
|
9319
9458
|
value: name,
|
|
9320
|
-
onChange: (e) =>
|
|
9459
|
+
onChange: (e) => {
|
|
9460
|
+
setName(e.target.value);
|
|
9461
|
+
setHasUnsavedChanges(true);
|
|
9462
|
+
},
|
|
9321
9463
|
placeholder: "Ex: Controla, Pertence a, Fornece...",
|
|
9322
9464
|
disabled: !canEdit,
|
|
9323
9465
|
className: `w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-400/60
|
|
9324
9466
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9325
9467
|
`
|
|
9326
9468
|
}
|
|
9327
|
-
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.
|
|
9469
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "rounded-xl border border-white/8 bg-slate-800/30 p-3 space-y-3" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react20.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-violet-400 flex-shrink-0" }, /* @__PURE__ */ import_react20.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react20.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-xs font-medium text-violet-300/80 uppercase tracking-wider" }, "Labels de Agrupamento")), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-[11px] text-slate-400 leading-relaxed" }, "Labels agrupam conex\xF5es no menu de Conex\xF5es. Cada lado da conex\xE3o pode ter sua pr\xF3pria label."), /* @__PURE__ */ import_react20.default.createElement("div", { className: "grid grid-cols-2 gap-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-[11px] text-slate-400" }, "Label do Source"), /* @__PURE__ */ import_react20.default.createElement(
|
|
9470
|
+
"input",
|
|
9471
|
+
{
|
|
9472
|
+
type: "text",
|
|
9473
|
+
value: sourceLabel,
|
|
9474
|
+
onChange: (e) => {
|
|
9475
|
+
setSourceLabel(e.target.value);
|
|
9476
|
+
setHasUnsavedChanges(true);
|
|
9477
|
+
},
|
|
9478
|
+
placeholder: "Ex: Conceitos",
|
|
9479
|
+
disabled: !canEdit,
|
|
9480
|
+
className: `w-full bg-slate-900/60 p-2 text-xs rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-violet-400/60 placeholder:text-slate-600
|
|
9481
|
+
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9482
|
+
`
|
|
9483
|
+
}
|
|
9484
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-[11px] text-slate-400" }, "Label do Target"), /* @__PURE__ */ import_react20.default.createElement(
|
|
9485
|
+
"input",
|
|
9486
|
+
{
|
|
9487
|
+
type: "text",
|
|
9488
|
+
value: targetLabel,
|
|
9489
|
+
onChange: (e) => {
|
|
9490
|
+
setTargetLabel(e.target.value);
|
|
9491
|
+
setHasUnsavedChanges(true);
|
|
9492
|
+
},
|
|
9493
|
+
placeholder: "Ex: Refer\xEAncias",
|
|
9494
|
+
disabled: !canEdit,
|
|
9495
|
+
className: `w-full bg-slate-900/60 p-2 text-xs rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-violet-400/60 placeholder:text-slate-600
|
|
9496
|
+
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9497
|
+
`
|
|
9498
|
+
}
|
|
9499
|
+
)))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement(
|
|
9328
9500
|
DescriptionDisplay,
|
|
9329
9501
|
{
|
|
9330
9502
|
description,
|
|
@@ -9394,6 +9566,7 @@ function RelationshipDetailsPanel({
|
|
|
9394
9566
|
onSave: (newDescription) => {
|
|
9395
9567
|
if (!canEdit) return;
|
|
9396
9568
|
setDescription(newDescription);
|
|
9569
|
+
setHasUnsavedChanges(true);
|
|
9397
9570
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9398
9571
|
triggerAutoSave({ description: newDescription });
|
|
9399
9572
|
},
|
|
@@ -9841,7 +10014,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9841
10014
|
onMentionClick,
|
|
9842
10015
|
onImageClick: handleImageClickFromText
|
|
9843
10016
|
}
|
|
9844
|
-
) : /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ import_react24.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react24.default.createElement("div",
|
|
10017
|
+
) : /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ import_react24.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react24.default.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__ */ import_react24.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ import_react24.default.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ import_react24.default.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ import_react24.default.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ import_react24.default.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ import_react24.default.createElement("button", { onClick: onClose, className: "w-9 h-9 flex-shrink-0 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")), /* @__PURE__ */ import_react24.default.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ import_react24.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react24.default.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react24.default.createElement(
|
|
9845
10018
|
"button",
|
|
9846
10019
|
{
|
|
9847
10020
|
onClick: () => setIsReadMode(true),
|
|
@@ -10621,6 +10794,7 @@ function XViewScene({
|
|
|
10621
10794
|
});
|
|
10622
10795
|
const [isImportModalOpen, setIsImportModalOpen] = (0, import_react26.useState)(false);
|
|
10623
10796
|
const [importSuccessMessage, setImportSuccessMessage] = (0, import_react26.useState)("");
|
|
10797
|
+
const [invalidTargetError, setInvalidTargetError] = (0, import_react26.useState)(null);
|
|
10624
10798
|
const [highlightedNodeId, setHighlightedNodeId] = (0, import_react26.useState)(null);
|
|
10625
10799
|
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react26.useState)(false);
|
|
10626
10800
|
const [ancestryBoardData, setAncestryBoardData] = (0, import_react26.useState)([]);
|
|
@@ -11282,6 +11456,7 @@ function XViewScene({
|
|
|
11282
11456
|
boardPromise
|
|
11283
11457
|
]);
|
|
11284
11458
|
if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
|
|
11459
|
+
console.log("XViewScene - View Members:", sceneResponse.data.scene.members);
|
|
11285
11460
|
if (focusNodeId) {
|
|
11286
11461
|
let targetNode = sceneResponse.data.scene.nodes.find(
|
|
11287
11462
|
(n) => String(n.id) === String(focusNodeId)
|
|
@@ -13522,7 +13697,7 @@ function XViewScene({
|
|
|
13522
13697
|
sceneVersion
|
|
13523
13698
|
]);
|
|
13524
13699
|
const handleStartReadingAncestry = (0, import_react26.useCallback)(
|
|
13525
|
-
async (ancestryObject) => {
|
|
13700
|
+
async (ancestryObject, renderMode = "full") => {
|
|
13526
13701
|
setContextMenu(
|
|
13527
13702
|
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13528
13703
|
);
|
|
@@ -13538,14 +13713,20 @@ function XViewScene({
|
|
|
13538
13713
|
const hasDescription = ancestryObject.description && ancestryObject.description.trim() !== "";
|
|
13539
13714
|
const hasMainTreeNodes = ancestryObject.tree.children && ancestryObject.tree.children.length > 0;
|
|
13540
13715
|
const hasAbstractionNodes = ancestryObject.abstraction_tree && ancestryObject.abstraction_tree.children && ancestryObject.abstraction_tree.children.length > 0;
|
|
13541
|
-
const
|
|
13716
|
+
const isFull = renderMode === "full";
|
|
13717
|
+
const isAncestryOnly = renderMode === "ancestry_only";
|
|
13718
|
+
const isAbstractionOnly = renderMode === "abstraction_only";
|
|
13719
|
+
let shouldRenderAbstraction = isAbstractionOnly;
|
|
13720
|
+
if (isFull) {
|
|
13721
|
+
shouldRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
|
|
13722
|
+
}
|
|
13542
13723
|
setReadingMode({
|
|
13543
|
-
isActive: hasDescription,
|
|
13724
|
+
isActive: isFull ? hasDescription : false,
|
|
13544
13725
|
ancestry: ancestryObject,
|
|
13545
13726
|
branchStack: [],
|
|
13546
|
-
autoAbstraction:
|
|
13727
|
+
autoAbstraction: shouldRenderAbstraction
|
|
13547
13728
|
});
|
|
13548
|
-
if (
|
|
13729
|
+
if (shouldRenderAbstraction) {
|
|
13549
13730
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
13550
13731
|
} else {
|
|
13551
13732
|
const initialSections = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
@@ -14291,6 +14472,9 @@ function XViewScene({
|
|
|
14291
14472
|
}, 300);
|
|
14292
14473
|
} else {
|
|
14293
14474
|
setHasFocusedInitial(true);
|
|
14475
|
+
setInvalidTargetError(
|
|
14476
|
+
"O link aponta para um item que n\xE3o foi encontrado ou foi exclu\xEDdo."
|
|
14477
|
+
);
|
|
14294
14478
|
}
|
|
14295
14479
|
}
|
|
14296
14480
|
}, [
|
|
@@ -14313,6 +14497,9 @@ function XViewScene({
|
|
|
14313
14497
|
}, 300);
|
|
14314
14498
|
} else {
|
|
14315
14499
|
setHasOpenedInitialAncestry(true);
|
|
14500
|
+
setInvalidTargetError(
|
|
14501
|
+
"O link aponta para uma ancestralidade que n\xE3o foi encontrada ou foi exclu\xEDda."
|
|
14502
|
+
);
|
|
14316
14503
|
}
|
|
14317
14504
|
}
|
|
14318
14505
|
}, [
|
|
@@ -14922,6 +15109,83 @@ function XViewScene({
|
|
|
14922
15109
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
14923
15110
|
currentAncestries: ancestryDataRef.current || []
|
|
14924
15111
|
}
|
|
15112
|
+
),
|
|
15113
|
+
invalidTargetError && /* @__PURE__ */ import_react26.default.createElement(
|
|
15114
|
+
"div",
|
|
15115
|
+
{
|
|
15116
|
+
className: "ui-overlay",
|
|
15117
|
+
style: {
|
|
15118
|
+
position: "fixed",
|
|
15119
|
+
top: "24px",
|
|
15120
|
+
left: "50%",
|
|
15121
|
+
transform: "translateX(-50%)",
|
|
15122
|
+
zIndex: 1e4,
|
|
15123
|
+
padding: "16px 24px",
|
|
15124
|
+
background: "rgba(30, 20, 20, 0.85)",
|
|
15125
|
+
backdropFilter: "blur(12px)",
|
|
15126
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
15127
|
+
border: "1px solid rgba(255, 70, 70, 0.35)",
|
|
15128
|
+
borderRadius: "16px",
|
|
15129
|
+
boxShadow: "0 12px 40px rgba(0,0,0,0.5), 0 0 30px rgba(255, 50, 50, 0.1)",
|
|
15130
|
+
color: "#ffa0a0",
|
|
15131
|
+
display: "flex",
|
|
15132
|
+
alignItems: "center",
|
|
15133
|
+
gap: "16px",
|
|
15134
|
+
fontFamily: "Inter, sans-serif",
|
|
15135
|
+
animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
|
|
15136
|
+
}
|
|
15137
|
+
},
|
|
15138
|
+
/* @__PURE__ */ import_react26.default.createElement("style", null, `
|
|
15139
|
+
@keyframes fadeInDown {
|
|
15140
|
+
from { opacity: 0; transform: translate(-50%, -20px); }
|
|
15141
|
+
to { opacity: 1; transform: translate(-50%, 0); }
|
|
15142
|
+
}
|
|
15143
|
+
`),
|
|
15144
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
15145
|
+
"svg",
|
|
15146
|
+
{
|
|
15147
|
+
width: "20",
|
|
15148
|
+
height: "20",
|
|
15149
|
+
viewBox: "0 0 24 24",
|
|
15150
|
+
fill: "none",
|
|
15151
|
+
stroke: "currentColor",
|
|
15152
|
+
strokeWidth: "2",
|
|
15153
|
+
strokeLinecap: "round",
|
|
15154
|
+
strokeLinejoin: "round"
|
|
15155
|
+
},
|
|
15156
|
+
/* @__PURE__ */ import_react26.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
15157
|
+
/* @__PURE__ */ import_react26.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
15158
|
+
/* @__PURE__ */ import_react26.default.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
15159
|
+
),
|
|
15160
|
+
/* @__PURE__ */ import_react26.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
|
|
15161
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
15162
|
+
"button",
|
|
15163
|
+
{
|
|
15164
|
+
onClick: () => setInvalidTargetError(null),
|
|
15165
|
+
style: {
|
|
15166
|
+
background: "rgba(255, 255, 255, 0.1)",
|
|
15167
|
+
border: "none",
|
|
15168
|
+
color: "white",
|
|
15169
|
+
padding: "4px 10px",
|
|
15170
|
+
borderRadius: "8px",
|
|
15171
|
+
cursor: "pointer",
|
|
15172
|
+
fontSize: "12px",
|
|
15173
|
+
fontWeight: 600,
|
|
15174
|
+
transition: "all 0.2s",
|
|
15175
|
+
marginLeft: "8px",
|
|
15176
|
+
border: "1px solid rgba(255,255,255,0.1)"
|
|
15177
|
+
},
|
|
15178
|
+
onMouseOver: (e) => {
|
|
15179
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
15180
|
+
e.currentTarget.style.transform = "translateY(-1px)";
|
|
15181
|
+
},
|
|
15182
|
+
onMouseOut: (e) => {
|
|
15183
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.1)";
|
|
15184
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
15185
|
+
}
|
|
15186
|
+
},
|
|
15187
|
+
"Fechar"
|
|
15188
|
+
)
|
|
14925
15189
|
)
|
|
14926
15190
|
);
|
|
14927
15191
|
}
|