@lv-x-software-house/x_view 1.2.4-dev.1 → 1.2.4-dev.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.
- package/dist/index.js +671 -335
- package/dist/index.mjs +597 -261
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import
|
|
2
|
+
import React24, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef18, useState as useState24, 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";
|
|
@@ -3097,7 +3097,7 @@ function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
|
3097
3097
|
|
|
3098
3098
|
// src/components/CustomPropertyDisplay.jsx
|
|
3099
3099
|
import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
3100
|
-
import { FiCheck, FiX, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
|
|
3100
|
+
import { FiCheck, FiX as FiX2, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
|
|
3101
3101
|
function CustomPropertyDisplay({
|
|
3102
3102
|
prop,
|
|
3103
3103
|
onUpdate,
|
|
@@ -3388,7 +3388,7 @@ function CustomPropertyDisplay({
|
|
|
3388
3388
|
default:
|
|
3389
3389
|
return /* @__PURE__ */ React3.createElement("input", { type: "text", placeholder: "Valor", value: tempProp.value, onChange: (e) => handlePropChange("value", e.target.value), className: baseInput });
|
|
3390
3390
|
}
|
|
3391
|
-
})()), /* @__PURE__ */ React3.createElement("div", { className: "flex justify-end items-center gap-2 pt-1" }, /* @__PURE__ */ React3.createElement("button", { onClick: handleCancel, type: "button", className: "w-8 h-8 grid place-items-center rounded-lg hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React3.createElement(
|
|
3391
|
+
})()), /* @__PURE__ */ React3.createElement("div", { className: "flex justify-end items-center gap-2 pt-1" }, /* @__PURE__ */ React3.createElement("button", { onClick: handleCancel, type: "button", className: "w-8 h-8 grid place-items-center rounded-lg hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React3.createElement(FiX2, { className: "text-red-400" })), /* @__PURE__ */ React3.createElement("button", { onClick: handleSave, type: "button", className: "w-8 h-8 grid place-items-center rounded-lg hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React3.createElement(FiCheck, { className: "text-green-400" }))));
|
|
3392
3392
|
};
|
|
3393
3393
|
const renderDisplayView = () => /* @__PURE__ */ React3.createElement("div", { className: "w-full space-y-2 text-sm" }, /* @__PURE__ */ React3.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React3.createElement("p", { className: "font-semibold text-slate-200" }, prop.key), /* @__PURE__ */ React3.createElement("span", { className: "text-xs capitalize bg-slate-700/50 px-2 py-0.5 rounded text-slate-400" }, prop.type)), /* @__PURE__ */ React3.createElement("div", { className: "text-slate-300 pl-1" }, (() => {
|
|
3394
3394
|
switch (prop.type) {
|
|
@@ -7024,7 +7024,7 @@ function CreateAncestryPanel({
|
|
|
7024
7024
|
|
|
7025
7025
|
// src/components/ImageViewer.jsx
|
|
7026
7026
|
import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
|
|
7027
|
-
import { FiX as
|
|
7027
|
+
import { FiX as FiX3, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
7028
7028
|
function ImageViewer({ data, onClose }) {
|
|
7029
7029
|
var _a;
|
|
7030
7030
|
const { images = [], startIndex = 0, visible } = data;
|
|
@@ -7109,7 +7109,7 @@ function ImageViewer({ data, onClose }) {
|
|
|
7109
7109
|
className: "absolute top-4 right-4 z-10 w-10 h-10 flex items-center justify-center bg-white/10 hover:bg-white/20 rounded-full text-white text-2xl transition-colors",
|
|
7110
7110
|
"aria-label": "Fechar"
|
|
7111
7111
|
},
|
|
7112
|
-
/* @__PURE__ */ React11.createElement(
|
|
7112
|
+
/* @__PURE__ */ React11.createElement(FiX3, null)
|
|
7113
7113
|
),
|
|
7114
7114
|
/* @__PURE__ */ React11.createElement("div", { className: "relative max-w-full max-h-full flex items-center justify-center" }, isLoading && /* @__PURE__ */ React11.createElement("div", { className: "absolute inset-0 flex items-center justify-center" }, /* @__PURE__ */ React11.createElement("div", { className: "h-10 w-10 border-2 border-white/40 border-t-white rounded-full animate-spin" })), loadedSrc && /* @__PURE__ */ React11.createElement(
|
|
7115
7115
|
"img",
|
|
@@ -7245,7 +7245,7 @@ function ColorPicker({ color, onChange, disabled }) {
|
|
|
7245
7245
|
}
|
|
7246
7246
|
|
|
7247
7247
|
// src/components/InSceneCreationForm.jsx
|
|
7248
|
-
import { FiPlus as FiPlus3, FiMaximize2, FiX as
|
|
7248
|
+
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX4, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
|
|
7249
7249
|
function InSceneCreationForm({
|
|
7250
7250
|
onSave,
|
|
7251
7251
|
onCancel,
|
|
@@ -7463,7 +7463,7 @@ function InSceneCreationForm({
|
|
|
7463
7463
|
onClick: () => handleRemoveType(index),
|
|
7464
7464
|
className: "hover:text-white transition-colors"
|
|
7465
7465
|
},
|
|
7466
|
-
/* @__PURE__ */ React13.createElement(
|
|
7466
|
+
/* @__PURE__ */ React13.createElement(FiX4, { size: 12 })
|
|
7467
7467
|
))), /* @__PURE__ */ React13.createElement(
|
|
7468
7468
|
"input",
|
|
7469
7469
|
{
|
|
@@ -7835,9 +7835,181 @@ function InSceneVersionForm({
|
|
|
7835
7835
|
));
|
|
7836
7836
|
}
|
|
7837
7837
|
|
|
7838
|
+
// src/components/InSceneQuestForm.jsx
|
|
7839
|
+
import React15, { useState as useState16, useRef as useRef12 } from "react";
|
|
7840
|
+
import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget } from "react-icons/fi";
|
|
7841
|
+
var QUEST_STATUS_COLORS = {
|
|
7842
|
+
"Backlog": "#64748b",
|
|
7843
|
+
// Slate (Cinza azulado)
|
|
7844
|
+
"In Progress": "#eab308",
|
|
7845
|
+
// Yellow (Amarelo)
|
|
7846
|
+
"Review": "#a855f7",
|
|
7847
|
+
// Purple (Roxo)
|
|
7848
|
+
"Done": "#22c55e"
|
|
7849
|
+
// Green (Verde)
|
|
7850
|
+
};
|
|
7851
|
+
function InSceneQuestForm({
|
|
7852
|
+
onSave,
|
|
7853
|
+
onCancel,
|
|
7854
|
+
style,
|
|
7855
|
+
refEl,
|
|
7856
|
+
onOpenImageViewer,
|
|
7857
|
+
availableNodes = [],
|
|
7858
|
+
availableAncestries = [],
|
|
7859
|
+
onMentionClick,
|
|
7860
|
+
onUploadFile
|
|
7861
|
+
}) {
|
|
7862
|
+
const [name, setName] = useState16("");
|
|
7863
|
+
const [types, setTypes] = useState16(["quest"]);
|
|
7864
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7865
|
+
const [status, setStatus] = useState16("Backlog");
|
|
7866
|
+
const [size, setSize] = useState16("medium");
|
|
7867
|
+
const [intensity, setIntensity] = useState16(0);
|
|
7868
|
+
const [description, setDescription] = useState16("");
|
|
7869
|
+
const [customProps, setCustomProps] = useState16([]);
|
|
7870
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7871
|
+
const propsEndRef = useRef12(null);
|
|
7872
|
+
const handleAddProp = () => {
|
|
7873
|
+
const newProp = createNewCustomProperty(customProps);
|
|
7874
|
+
setCustomProps([...customProps, newProp]);
|
|
7875
|
+
setTimeout(() => {
|
|
7876
|
+
var _a;
|
|
7877
|
+
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
7878
|
+
}, 100);
|
|
7879
|
+
};
|
|
7880
|
+
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
7881
|
+
const handleUpdateProp = (index, updatedProp) => {
|
|
7882
|
+
const newProps = [...customProps];
|
|
7883
|
+
newProps[index] = updatedProp;
|
|
7884
|
+
setCustomProps(newProps);
|
|
7885
|
+
};
|
|
7886
|
+
const handleAddType = (newType) => {
|
|
7887
|
+
const trimmed = newType.trim().toLowerCase();
|
|
7888
|
+
if (trimmed && !types.includes(trimmed)) {
|
|
7889
|
+
setTypes([...types, trimmed]);
|
|
7890
|
+
setTypeInput("");
|
|
7891
|
+
}
|
|
7892
|
+
};
|
|
7893
|
+
const handleRemoveType = (indexToRemove) => {
|
|
7894
|
+
if (types[indexToRemove] === "quest") return;
|
|
7895
|
+
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
7896
|
+
};
|
|
7897
|
+
const handleTypeInputKeyDown = (e) => {
|
|
7898
|
+
if (e.key === "Enter") {
|
|
7899
|
+
e.preventDefault();
|
|
7900
|
+
handleAddType(typeInput);
|
|
7901
|
+
} else if (e.key === "Backspace" && typeInput === "" && types.length > 1) {
|
|
7902
|
+
handleRemoveType(types.length - 1);
|
|
7903
|
+
}
|
|
7904
|
+
};
|
|
7905
|
+
const handleSubmit = (e) => {
|
|
7906
|
+
e.preventDefault();
|
|
7907
|
+
if (!name.trim()) {
|
|
7908
|
+
alert("O campo 'Nome' \xE9 obrigat\xF3rio.");
|
|
7909
|
+
return;
|
|
7910
|
+
}
|
|
7911
|
+
const additionalData = toObjectFromCustomProps(
|
|
7912
|
+
customProps.filter((prop) => prop.key.trim() && !prop.isEditing)
|
|
7913
|
+
);
|
|
7914
|
+
const processedSections = processDescriptionForSave(description, []);
|
|
7915
|
+
onSave({
|
|
7916
|
+
name: name.trim(),
|
|
7917
|
+
type: types,
|
|
7918
|
+
color: QUEST_STATUS_COLORS[status],
|
|
7919
|
+
// Cor atrelada ao status
|
|
7920
|
+
status,
|
|
7921
|
+
size,
|
|
7922
|
+
intensity,
|
|
7923
|
+
description: description.trim(),
|
|
7924
|
+
description_sections: processedSections,
|
|
7925
|
+
useImageAsTexture: false,
|
|
7926
|
+
textureImageUrl: null,
|
|
7927
|
+
...additionalData
|
|
7928
|
+
});
|
|
7929
|
+
};
|
|
7930
|
+
const swallow = (e) => e.stopPropagation();
|
|
7931
|
+
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
7932
|
+
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
7933
|
+
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
7934
|
+
"div",
|
|
7935
|
+
{
|
|
7936
|
+
ref: refEl,
|
|
7937
|
+
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 w-[min(92vw,440px)] overflow-hidden",
|
|
7938
|
+
style,
|
|
7939
|
+
onPointerDown: swallow,
|
|
7940
|
+
onClick: swallow,
|
|
7941
|
+
onWheel: swallow,
|
|
7942
|
+
onContextMenu: swallow,
|
|
7943
|
+
onDoubleClick: swallow
|
|
7944
|
+
},
|
|
7945
|
+
/* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS[status]}, transparent)` } }),
|
|
7946
|
+
/* @__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")),
|
|
7947
|
+
/* @__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(
|
|
7948
|
+
"select",
|
|
7949
|
+
{
|
|
7950
|
+
value: status,
|
|
7951
|
+
onChange: (e) => setStatus(e.target.value),
|
|
7952
|
+
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",
|
|
7953
|
+
style: { borderLeft: `4px solid ${QUEST_STATUS_COLORS[status]}` }
|
|
7954
|
+
},
|
|
7955
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Backlog" }, "Backlog"),
|
|
7956
|
+
/* @__PURE__ */ React15.createElement("option", { value: "In Progress" }, "In Progress"),
|
|
7957
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Review" }, "Review"),
|
|
7958
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Done" }, "Done")
|
|
7959
|
+
)), /* @__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(FiX, { size: 12 })))), /* @__PURE__ */ React15.createElement(
|
|
7960
|
+
"input",
|
|
7961
|
+
{
|
|
7962
|
+
type: "text",
|
|
7963
|
+
value: typeInput,
|
|
7964
|
+
onChange: (e) => setTypeInput(e.target.value),
|
|
7965
|
+
onKeyDown: handleTypeInputKeyDown,
|
|
7966
|
+
onBlur: () => {
|
|
7967
|
+
if (typeInput.trim()) handleAddType(typeInput);
|
|
7968
|
+
},
|
|
7969
|
+
className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
|
|
7970
|
+
placeholder: "Ex.: Bugfix",
|
|
7971
|
+
autoComplete: "off"
|
|
7972
|
+
}
|
|
7973
|
+
))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React15.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React15.createElement(
|
|
7974
|
+
DescriptionDisplay,
|
|
7975
|
+
{
|
|
7976
|
+
description,
|
|
7977
|
+
savedSections: [],
|
|
7978
|
+
availableNodes,
|
|
7979
|
+
availableAncestries,
|
|
7980
|
+
onMentionClick,
|
|
7981
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7982
|
+
}
|
|
7983
|
+
), /* @__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(
|
|
7984
|
+
CustomPropertyDisplay,
|
|
7985
|
+
{
|
|
7986
|
+
key: prop.id,
|
|
7987
|
+
prop,
|
|
7988
|
+
onUpdate: (updatedProp) => handleUpdateProp(index, updatedProp),
|
|
7989
|
+
onRemove: () => handleRemoveProp(index),
|
|
7990
|
+
onOpenImageViewer,
|
|
7991
|
+
unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type),
|
|
7992
|
+
onUploadFile
|
|
7993
|
+
}
|
|
7994
|
+
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: onCancel, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm" }, "Cancelar"), /* @__PURE__ */ React15.createElement("button", { type: "submit", className: "px-4 py-2 rounded-lg bg-gradient-to-tr from-indigo-600 to-indigo-400 hover:from-indigo-500 hover:to-indigo-300 transition-colors font-semibold text-sm shadow-[0_8px_24px_rgba(99,102,241,0.35)]" }, "Salvar Quest")))
|
|
7995
|
+
), isDescriptionModalOpen && /* @__PURE__ */ React15.createElement(
|
|
7996
|
+
DescriptionEditModal,
|
|
7997
|
+
{
|
|
7998
|
+
isOpen: isDescriptionModalOpen,
|
|
7999
|
+
title: "Editar Descri\xE7\xE3o da Quest",
|
|
8000
|
+
initialValue: description,
|
|
8001
|
+
onSave: (newDescription) => setDescription(newDescription),
|
|
8002
|
+
onClose: () => setIsDescriptionModalOpen(false),
|
|
8003
|
+
availableNodes,
|
|
8004
|
+
availableAncestries,
|
|
8005
|
+
availableImages
|
|
8006
|
+
}
|
|
8007
|
+
));
|
|
8008
|
+
}
|
|
8009
|
+
|
|
7838
8010
|
// src/components/NodeDetailsPanel.jsx
|
|
7839
|
-
import
|
|
7840
|
-
import { FiPlus as
|
|
8011
|
+
import React16, { useState as useState17, useEffect as useEffect15, useRef as useRef13 } from "react";
|
|
8012
|
+
import { FiPlus as FiPlus6, FiMaximize2 as FiMaximize23, FiX as FiX5, FiCheck as FiCheck10, FiImage as FiImage3, FiEdit2 as FiEdit27, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
|
|
7841
8013
|
function NodeDetailsPanel({
|
|
7842
8014
|
node,
|
|
7843
8015
|
onClose,
|
|
@@ -7858,27 +8030,27 @@ function NodeDetailsPanel({
|
|
|
7858
8030
|
userRole,
|
|
7859
8031
|
currentDatasetName
|
|
7860
8032
|
}) {
|
|
7861
|
-
const [name, setName] =
|
|
7862
|
-
const [types, setTypes] =
|
|
7863
|
-
const [typeInput, setTypeInput] =
|
|
7864
|
-
const [color, setColor] =
|
|
7865
|
-
const [size, setSize] =
|
|
7866
|
-
const [description, setDescription] =
|
|
7867
|
-
const [intensity, setIntensity] =
|
|
7868
|
-
const [customProps, setCustomProps] =
|
|
7869
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
7870
|
-
const [filteredTypes, setFilteredTypes] =
|
|
7871
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7872
|
-
const [isReadMode, setIsReadMode] =
|
|
7873
|
-
const [existingSections, setExistingSections] =
|
|
7874
|
-
const [isSaving, setIsSaving] =
|
|
7875
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
7876
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
8033
|
+
const [name, setName] = useState17((node == null ? void 0 : node.name) ?? "");
|
|
8034
|
+
const [types, setTypes] = useState17([]);
|
|
8035
|
+
const [typeInput, setTypeInput] = useState17("");
|
|
8036
|
+
const [color, setColor] = useState17((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
8037
|
+
const [size, setSize] = useState17((node == null ? void 0 : node.size) ?? "medium");
|
|
8038
|
+
const [description, setDescription] = useState17((node == null ? void 0 : node.description) ?? "");
|
|
8039
|
+
const [intensity, setIntensity] = useState17((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8040
|
+
const [customProps, setCustomProps] = useState17(() => extractCustomPropsFromNode(node || {}));
|
|
8041
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState17(false);
|
|
8042
|
+
const [filteredTypes, setFilteredTypes] = useState17([]);
|
|
8043
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
|
|
8044
|
+
const [isReadMode, setIsReadMode] = useState17(false);
|
|
8045
|
+
const [existingSections, setExistingSections] = useState17((node == null ? void 0 : node.description_sections) || []);
|
|
8046
|
+
const [isSaving, setIsSaving] = useState17(false);
|
|
8047
|
+
const [isLinkCopied, setIsLinkCopied] = useState17(false);
|
|
8048
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState17(() => {
|
|
7877
8049
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7878
8050
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7879
8051
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7880
8052
|
});
|
|
7881
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
8053
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState17((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7882
8054
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7883
8055
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7884
8056
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -7888,8 +8060,8 @@ function NodeDetailsPanel({
|
|
|
7888
8060
|
useEffect15(() => {
|
|
7889
8061
|
setWidth(isReadMode ? 700 : 440);
|
|
7890
8062
|
}, [isReadMode, setWidth]);
|
|
7891
|
-
const prevNodeIdRef =
|
|
7892
|
-
const propsEndRef =
|
|
8063
|
+
const prevNodeIdRef = useRef13(null);
|
|
8064
|
+
const propsEndRef = useRef13(null);
|
|
7893
8065
|
const canEdit = userRole !== "viewer";
|
|
7894
8066
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
7895
8067
|
const handleImageClickFromText = (url, name2) => {
|
|
@@ -8097,7 +8269,7 @@ function NodeDetailsPanel({
|
|
|
8097
8269
|
onClose();
|
|
8098
8270
|
};
|
|
8099
8271
|
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
8100
|
-
return /* @__PURE__ */
|
|
8272
|
+
return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
|
|
8101
8273
|
"div",
|
|
8102
8274
|
{
|
|
8103
8275
|
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"}`,
|
|
@@ -8110,7 +8282,7 @@ function NodeDetailsPanel({
|
|
|
8110
8282
|
onContextMenu: swallow,
|
|
8111
8283
|
onDoubleClick: swallow
|
|
8112
8284
|
},
|
|
8113
|
-
/* @__PURE__ */
|
|
8285
|
+
/* @__PURE__ */ React16.createElement(
|
|
8114
8286
|
"div",
|
|
8115
8287
|
{
|
|
8116
8288
|
onPointerDown: (e) => {
|
|
@@ -8121,7 +8293,7 @@ function NodeDetailsPanel({
|
|
|
8121
8293
|
title: "Arraste para redimensionar"
|
|
8122
8294
|
}
|
|
8123
8295
|
),
|
|
8124
|
-
isReadMode ? /* @__PURE__ */
|
|
8296
|
+
isReadMode ? /* @__PURE__ */ React16.createElement(
|
|
8125
8297
|
DescriptionReadModePanel,
|
|
8126
8298
|
{
|
|
8127
8299
|
title: name || (node == null ? void 0 : node.name),
|
|
@@ -8142,23 +8314,23 @@ function NodeDetailsPanel({
|
|
|
8142
8314
|
onImageClick: handleImageClickFromText,
|
|
8143
8315
|
onSaveDescription: handleSaveDescriptionInline
|
|
8144
8316
|
}
|
|
8145
|
-
) : /* @__PURE__ */
|
|
8317
|
+
) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React16.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React16.createElement("div", null, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React16.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__ */ React16.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React16.createElement(
|
|
8146
8318
|
"button",
|
|
8147
8319
|
{
|
|
8148
8320
|
onClick: handleCopyLink,
|
|
8149
8321
|
className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-indigo-400"}`,
|
|
8150
8322
|
title: isLinkCopied ? "Link Copiado!" : "Copiar link para este Node"
|
|
8151
8323
|
},
|
|
8152
|
-
isLinkCopied ? /* @__PURE__ */
|
|
8153
|
-
)), /* @__PURE__ */
|
|
8324
|
+
isLinkCopied ? /* @__PURE__ */ React16.createElement(FiCheck10, { size: 12 }) : /* @__PURE__ */ React16.createElement(FiLink5, { size: 12 })
|
|
8325
|
+
)), /* @__PURE__ */ React16.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ React16.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__ */ React16.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ React16.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__ */ React16.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__ */ React16.createElement(
|
|
8154
8326
|
"button",
|
|
8155
8327
|
{
|
|
8156
8328
|
type: "button",
|
|
8157
8329
|
onClick: () => handleRemoveType(index),
|
|
8158
8330
|
className: "hover:text-white transition-colors"
|
|
8159
8331
|
},
|
|
8160
|
-
/* @__PURE__ */
|
|
8161
|
-
))), canEdit && /* @__PURE__ */
|
|
8332
|
+
/* @__PURE__ */ React16.createElement(FiX5, { size: 12 })
|
|
8333
|
+
))), canEdit && /* @__PURE__ */ React16.createElement(
|
|
8162
8334
|
"input",
|
|
8163
8335
|
{
|
|
8164
8336
|
type: "text",
|
|
@@ -8179,7 +8351,7 @@ function NodeDetailsPanel({
|
|
|
8179
8351
|
placeholder: types.length === 0 ? "Ex.: Cliente" : "",
|
|
8180
8352
|
autoComplete: "off"
|
|
8181
8353
|
}
|
|
8182
|
-
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */
|
|
8354
|
+
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React16.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__ */ React16.createElement(
|
|
8183
8355
|
"li",
|
|
8184
8356
|
{
|
|
8185
8357
|
key: index,
|
|
@@ -8190,7 +8362,7 @@ function NodeDetailsPanel({
|
|
|
8190
8362
|
}
|
|
8191
8363
|
},
|
|
8192
8364
|
suggestedType
|
|
8193
|
-
))))), /* @__PURE__ */
|
|
8365
|
+
))))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ React16.createElement(
|
|
8194
8366
|
"input",
|
|
8195
8367
|
{
|
|
8196
8368
|
type: "text",
|
|
@@ -8199,7 +8371,7 @@ function NodeDetailsPanel({
|
|
|
8199
8371
|
readOnly: !canEdit,
|
|
8200
8372
|
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"}`
|
|
8201
8373
|
}
|
|
8202
|
-
)), /* @__PURE__ */
|
|
8374
|
+
)), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React16.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__ */ React16.createElement(
|
|
8203
8375
|
DescriptionDisplay,
|
|
8204
8376
|
{
|
|
8205
8377
|
description,
|
|
@@ -8211,7 +8383,7 @@ function NodeDetailsPanel({
|
|
|
8211
8383
|
onImageClick: handleImageClickFromText,
|
|
8212
8384
|
onSaveDescription: handleSaveDescriptionInline
|
|
8213
8385
|
}
|
|
8214
|
-
), /* @__PURE__ */
|
|
8386
|
+
), /* @__PURE__ */ React16.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__ */ React16.createElement(
|
|
8215
8387
|
"button",
|
|
8216
8388
|
{
|
|
8217
8389
|
type: "button",
|
|
@@ -8219,8 +8391,8 @@ function NodeDetailsPanel({
|
|
|
8219
8391
|
className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`,
|
|
8220
8392
|
title: "Modo de Leitura"
|
|
8221
8393
|
},
|
|
8222
|
-
/* @__PURE__ */
|
|
8223
|
-
), canEdit && /* @__PURE__ */
|
|
8394
|
+
/* @__PURE__ */ React16.createElement(FiBookOpen3, { size: 14 })
|
|
8395
|
+
), canEdit && /* @__PURE__ */ React16.createElement(
|
|
8224
8396
|
"button",
|
|
8225
8397
|
{
|
|
8226
8398
|
type: "button",
|
|
@@ -8228,17 +8400,17 @@ function NodeDetailsPanel({
|
|
|
8228
8400
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8229
8401
|
title: "Editar descri\xE7\xE3o (Modo de Escrita)"
|
|
8230
8402
|
},
|
|
8231
|
-
/* @__PURE__ */
|
|
8232
|
-
)), canEdit && !description && /* @__PURE__ */
|
|
8403
|
+
/* @__PURE__ */ React16.createElement(FiEdit27, { size: 14 })
|
|
8404
|
+
)), canEdit && !description && /* @__PURE__ */ React16.createElement(
|
|
8233
8405
|
"div",
|
|
8234
8406
|
{
|
|
8235
8407
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8236
8408
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8237
8409
|
},
|
|
8238
8410
|
"Adicionar descri\xE7\xE3o..."
|
|
8239
|
-
))), /* @__PURE__ */
|
|
8411
|
+
))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Size"), /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
|
|
8240
8412
|
const isSelected = size === s;
|
|
8241
|
-
return /* @__PURE__ */
|
|
8413
|
+
return /* @__PURE__ */ React16.createElement(
|
|
8242
8414
|
"button",
|
|
8243
8415
|
{
|
|
8244
8416
|
key: s,
|
|
@@ -8246,10 +8418,10 @@ function NodeDetailsPanel({
|
|
|
8246
8418
|
onClick: () => canEdit && handleSizeChange(s),
|
|
8247
8419
|
className: `flex items-center gap-2 group focus:outline-none ${canEdit ? "cursor-pointer" : "cursor-default opacity-80"}`
|
|
8248
8420
|
},
|
|
8249
|
-
/* @__PURE__ */
|
|
8250
|
-
/* @__PURE__ */
|
|
8421
|
+
/* @__PURE__ */ React16.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__ */ React16.createElement(FiCheck10, { size: 12, className: "text-white" })),
|
|
8422
|
+
/* @__PURE__ */ React16.createElement("span", { className: `text-sm capitalize transition-colors ${isSelected ? "text-white font-medium" : "text-slate-400 " + (canEdit ? "group-hover:text-slate-300" : "")}` }, s)
|
|
8251
8423
|
);
|
|
8252
|
-
}))), /* @__PURE__ */
|
|
8424
|
+
}))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Cor e Brilho"), canEdit && hasImages && /* @__PURE__ */ React16.createElement("label", { className: "flex items-center gap-2 cursor-pointer group" }, /* @__PURE__ */ React16.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${useImageAsTexture ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, useImageAsTexture && /* @__PURE__ */ React16.createElement(FiCheck10, { size: 12, className: "text-white" })), /* @__PURE__ */ React16.createElement(
|
|
8253
8425
|
"input",
|
|
8254
8426
|
{
|
|
8255
8427
|
type: "checkbox",
|
|
@@ -8257,14 +8429,14 @@ function NodeDetailsPanel({
|
|
|
8257
8429
|
onChange: handleToggleImageMode,
|
|
8258
8430
|
className: "hidden"
|
|
8259
8431
|
}
|
|
8260
|
-
), /* @__PURE__ */
|
|
8432
|
+
), /* @__PURE__ */ React16.createElement("span", { className: `text-xs ${useImageAsTexture ? "text-indigo-300" : "text-slate-400 group-hover:text-slate-300"}` }, "Usar imagem para representar o node"))), /* @__PURE__ */ React16.createElement(
|
|
8261
8433
|
ColorPicker,
|
|
8262
8434
|
{
|
|
8263
8435
|
color,
|
|
8264
8436
|
onChange: handleColorChange,
|
|
8265
8437
|
disabled: !canEdit || useImageAsTexture
|
|
8266
8438
|
}
|
|
8267
|
-
), /* @__PURE__ */
|
|
8439
|
+
), /* @__PURE__ */ React16.createElement("div", { className: "mt-3 flex items-center gap-3" }, /* @__PURE__ */ React16.createElement(FiSun2, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React16.createElement(
|
|
8268
8440
|
"input",
|
|
8269
8441
|
{
|
|
8270
8442
|
type: "range",
|
|
@@ -8277,7 +8449,7 @@ function NodeDetailsPanel({
|
|
|
8277
8449
|
className: `w-full h-1.5 bg-slate-700 rounded-lg appearance-none ${canEdit ? "cursor-pointer accent-indigo-500 hover:accent-indigo-400" : "cursor-default accent-slate-500"}`,
|
|
8278
8450
|
title: `Intensidade do brilho: ${intensity}`
|
|
8279
8451
|
}
|
|
8280
|
-
), /* @__PURE__ */
|
|
8452
|
+
), /* @__PURE__ */ React16.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React16.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ React16.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React16.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React16.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__ */ React16.createElement(FiPlus6, { size: 14 }), " Adicionar")), /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React16.createElement(
|
|
8281
8453
|
CustomPropertyDisplay,
|
|
8282
8454
|
{
|
|
8283
8455
|
key: prop.id,
|
|
@@ -8292,7 +8464,7 @@ function NodeDetailsPanel({
|
|
|
8292
8464
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
8293
8465
|
readOnly: !canEdit
|
|
8294
8466
|
}
|
|
8295
|
-
)), /* @__PURE__ */
|
|
8467
|
+
)), /* @__PURE__ */ React16.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React16.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__ */ React16.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React16.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React16.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__ */ React16.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__ */ React16.createElement(
|
|
8296
8468
|
"button",
|
|
8297
8469
|
{
|
|
8298
8470
|
onClick: () => handleSave(false),
|
|
@@ -8301,10 +8473,10 @@ function NodeDetailsPanel({
|
|
|
8301
8473
|
${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"}
|
|
8302
8474
|
`
|
|
8303
8475
|
},
|
|
8304
|
-
isSaving && /* @__PURE__ */
|
|
8476
|
+
isSaving && /* @__PURE__ */ React16.createElement(FiLoader2, { className: "animate-spin" }),
|
|
8305
8477
|
isSaving ? "Salvando..." : "Salvar"
|
|
8306
8478
|
)))
|
|
8307
|
-
), isDescriptionModalOpen && canEdit && /* @__PURE__ */
|
|
8479
|
+
), isDescriptionModalOpen && canEdit && /* @__PURE__ */ React16.createElement(
|
|
8308
8480
|
DescriptionEditModal,
|
|
8309
8481
|
{
|
|
8310
8482
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8324,7 +8496,7 @@ function NodeDetailsPanel({
|
|
|
8324
8496
|
}
|
|
8325
8497
|
|
|
8326
8498
|
// src/components/MultiNodeContextMenu.jsx
|
|
8327
|
-
import
|
|
8499
|
+
import React17, { useLayoutEffect as useLayoutEffect3, useRef as useRef14, useState as useState18, useEffect as useEffect16 } from "react";
|
|
8328
8500
|
function MultiNodeContextMenu({
|
|
8329
8501
|
data,
|
|
8330
8502
|
userRole,
|
|
@@ -8333,9 +8505,9 @@ function MultiNodeContextMenu({
|
|
|
8333
8505
|
onDismissOtherNodes,
|
|
8334
8506
|
onDeleteNodes
|
|
8335
8507
|
}) {
|
|
8336
|
-
const menuRef =
|
|
8337
|
-
const [menuPos, setMenuPos] =
|
|
8338
|
-
const [isConfirmingDelete, setIsConfirmingDelete] =
|
|
8508
|
+
const menuRef = useRef14(null);
|
|
8509
|
+
const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
|
|
8510
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState18(false);
|
|
8339
8511
|
const ability = defineAbilityFor(userRole);
|
|
8340
8512
|
const canDelete = ability.can("delete", "Node");
|
|
8341
8513
|
useLayoutEffect3(() => {
|
|
@@ -8366,7 +8538,7 @@ function MultiNodeContextMenu({
|
|
|
8366
8538
|
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";
|
|
8367
8539
|
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";
|
|
8368
8540
|
const nodeCount = data.nodeIds.size;
|
|
8369
|
-
return /* @__PURE__ */
|
|
8541
|
+
return /* @__PURE__ */ React17.createElement(
|
|
8370
8542
|
"div",
|
|
8371
8543
|
{
|
|
8372
8544
|
ref: menuRef,
|
|
@@ -8380,28 +8552,28 @@ function MultiNodeContextMenu({
|
|
|
8380
8552
|
onContextMenu: swallow,
|
|
8381
8553
|
onDoubleClick: swallow
|
|
8382
8554
|
},
|
|
8383
|
-
/* @__PURE__ */
|
|
8384
|
-
/* @__PURE__ */
|
|
8555
|
+
/* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
8556
|
+
/* @__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(
|
|
8385
8557
|
"button",
|
|
8386
8558
|
{
|
|
8387
8559
|
onClick: () => setIsConfirmingDelete(false),
|
|
8388
8560
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8389
8561
|
},
|
|
8390
8562
|
"Cancelar"
|
|
8391
|
-
), /* @__PURE__ */
|
|
8563
|
+
), /* @__PURE__ */ React17.createElement(
|
|
8392
8564
|
"button",
|
|
8393
8565
|
{
|
|
8394
8566
|
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8395
8567
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8396
8568
|
},
|
|
8397
8569
|
"Excluir"
|
|
8398
|
-
))) : /* @__PURE__ */
|
|
8570
|
+
))) : /* @__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, ")"))))))
|
|
8399
8571
|
);
|
|
8400
8572
|
}
|
|
8401
8573
|
|
|
8402
8574
|
// src/components/RelationshipDetailsPanel.jsx
|
|
8403
|
-
import
|
|
8404
|
-
import { FiPlus as
|
|
8575
|
+
import React18, { useState as useState19, useEffect as useEffect17, useRef as useRef15, useMemo as useMemo9 } from "react";
|
|
8576
|
+
import { FiPlus as FiPlus7, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
8405
8577
|
function RelationshipDetailsPanel({
|
|
8406
8578
|
link,
|
|
8407
8579
|
onClose,
|
|
@@ -8415,14 +8587,14 @@ function RelationshipDetailsPanel({
|
|
|
8415
8587
|
onUploadFile,
|
|
8416
8588
|
userRole
|
|
8417
8589
|
}) {
|
|
8418
|
-
const [name, setName] =
|
|
8419
|
-
const [description, setDescription] =
|
|
8420
|
-
const [customProps, setCustomProps] =
|
|
8421
|
-
const [existingSections, setExistingSections] =
|
|
8422
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
8423
|
-
const [isSaving, setIsSaving] =
|
|
8424
|
-
const [isReadMode, setIsReadMode] =
|
|
8425
|
-
const propsEndRef =
|
|
8590
|
+
const [name, setName] = useState19((link == null ? void 0 : link.name) ?? "");
|
|
8591
|
+
const [description, setDescription] = useState19((link == null ? void 0 : link.description) ?? "");
|
|
8592
|
+
const [customProps, setCustomProps] = useState19(() => extractCustomPropsFromNode(link || {}));
|
|
8593
|
+
const [existingSections, setExistingSections] = useState19((link == null ? void 0 : link.description_sections) || []);
|
|
8594
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState19(false);
|
|
8595
|
+
const [isSaving, setIsSaving] = useState19(false);
|
|
8596
|
+
const [isReadMode, setIsReadMode] = useState19(false);
|
|
8597
|
+
const propsEndRef = useRef15(null);
|
|
8426
8598
|
const canEdit = useMemo9(() => {
|
|
8427
8599
|
const ability = defineAbilityFor(userRole);
|
|
8428
8600
|
return ability.can("update", "Connection");
|
|
@@ -8502,7 +8674,7 @@ function RelationshipDetailsPanel({
|
|
|
8502
8674
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
8503
8675
|
}
|
|
8504
8676
|
};
|
|
8505
|
-
return /* @__PURE__ */
|
|
8677
|
+
return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
|
|
8506
8678
|
"div",
|
|
8507
8679
|
{
|
|
8508
8680
|
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
|
|
@@ -8517,7 +8689,7 @@ function RelationshipDetailsPanel({
|
|
|
8517
8689
|
onContextMenu: swallow,
|
|
8518
8690
|
onDoubleClick: swallow
|
|
8519
8691
|
},
|
|
8520
|
-
isReadMode ? /* @__PURE__ */
|
|
8692
|
+
isReadMode ? /* @__PURE__ */ React18.createElement(
|
|
8521
8693
|
DescriptionReadModePanel,
|
|
8522
8694
|
{
|
|
8523
8695
|
title: name || "Rela\xE7\xE3o",
|
|
@@ -8538,7 +8710,7 @@ function RelationshipDetailsPanel({
|
|
|
8538
8710
|
onImageClick: handleImageClickFromText,
|
|
8539
8711
|
onSaveDescription: handleSaveDescriptionInline
|
|
8540
8712
|
}
|
|
8541
|
-
) : /* @__PURE__ */
|
|
8713
|
+
) : /* @__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(
|
|
8542
8714
|
"input",
|
|
8543
8715
|
{
|
|
8544
8716
|
type: "text",
|
|
@@ -8550,7 +8722,7 @@ function RelationshipDetailsPanel({
|
|
|
8550
8722
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
8551
8723
|
`
|
|
8552
8724
|
}
|
|
8553
|
-
)), /* @__PURE__ */
|
|
8725
|
+
)), /* @__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(
|
|
8554
8726
|
DescriptionDisplay,
|
|
8555
8727
|
{
|
|
8556
8728
|
description,
|
|
@@ -8562,7 +8734,7 @@ function RelationshipDetailsPanel({
|
|
|
8562
8734
|
onImageClick: handleImageClickFromText,
|
|
8563
8735
|
onSaveDescription: handleSaveDescriptionInline
|
|
8564
8736
|
}
|
|
8565
|
-
), /* @__PURE__ */
|
|
8737
|
+
), /* @__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(
|
|
8566
8738
|
"button",
|
|
8567
8739
|
{
|
|
8568
8740
|
type: "button",
|
|
@@ -8570,8 +8742,8 @@ function RelationshipDetailsPanel({
|
|
|
8570
8742
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors border-r border-white/5",
|
|
8571
8743
|
title: "Modo de Leitura"
|
|
8572
8744
|
},
|
|
8573
|
-
/* @__PURE__ */
|
|
8574
|
-
), canEdit && /* @__PURE__ */
|
|
8745
|
+
/* @__PURE__ */ React18.createElement(FiBookOpen4, { size: 14 })
|
|
8746
|
+
), canEdit && /* @__PURE__ */ React18.createElement(
|
|
8575
8747
|
"button",
|
|
8576
8748
|
{
|
|
8577
8749
|
type: "button",
|
|
@@ -8579,15 +8751,15 @@ function RelationshipDetailsPanel({
|
|
|
8579
8751
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8580
8752
|
title: "Editar descri\xE7\xE3o"
|
|
8581
8753
|
},
|
|
8582
|
-
/* @__PURE__ */
|
|
8583
|
-
)), !description && canEdit && /* @__PURE__ */
|
|
8754
|
+
/* @__PURE__ */ React18.createElement(FiEdit28, { size: 14 })
|
|
8755
|
+
)), !description && canEdit && /* @__PURE__ */ React18.createElement(
|
|
8584
8756
|
"div",
|
|
8585
8757
|
{
|
|
8586
8758
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8587
8759
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8588
8760
|
},
|
|
8589
8761
|
"Adicionar descri\xE7\xE3o..."
|
|
8590
|
-
))), /* @__PURE__ */
|
|
8762
|
+
))), /* @__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(
|
|
8591
8763
|
CustomPropertyDisplay,
|
|
8592
8764
|
{
|
|
8593
8765
|
key: prop.id,
|
|
@@ -8599,7 +8771,7 @@ function RelationshipDetailsPanel({
|
|
|
8599
8771
|
onUploadFile,
|
|
8600
8772
|
disabled: !canEdit
|
|
8601
8773
|
}
|
|
8602
|
-
)), /* @__PURE__ */
|
|
8774
|
+
)), /* @__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(
|
|
8603
8775
|
"button",
|
|
8604
8776
|
{
|
|
8605
8777
|
onClick: () => handleSave(false),
|
|
@@ -8608,10 +8780,10 @@ function RelationshipDetailsPanel({
|
|
|
8608
8780
|
${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"}
|
|
8609
8781
|
`
|
|
8610
8782
|
},
|
|
8611
|
-
isSaving && /* @__PURE__ */
|
|
8783
|
+
isSaving && /* @__PURE__ */ React18.createElement(FiLoader3, { className: "animate-spin" }),
|
|
8612
8784
|
isSaving ? "Salvando..." : "Salvar"
|
|
8613
8785
|
)))
|
|
8614
|
-
), isDescriptionModalOpen && /* @__PURE__ */
|
|
8786
|
+
), isDescriptionModalOpen && /* @__PURE__ */ React18.createElement(
|
|
8615
8787
|
DescriptionEditModal,
|
|
8616
8788
|
{
|
|
8617
8789
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8632,7 +8804,7 @@ function RelationshipDetailsPanel({
|
|
|
8632
8804
|
}
|
|
8633
8805
|
|
|
8634
8806
|
// src/components/RelationshipContextMenu.jsx
|
|
8635
|
-
import
|
|
8807
|
+
import React19, { useLayoutEffect as useLayoutEffect4, useRef as useRef16, useState as useState20, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8636
8808
|
function RelationshipContextMenu({
|
|
8637
8809
|
data,
|
|
8638
8810
|
userRole,
|
|
@@ -8642,9 +8814,9 @@ function RelationshipContextMenu({
|
|
|
8642
8814
|
onDelete,
|
|
8643
8815
|
onClose
|
|
8644
8816
|
}) {
|
|
8645
|
-
const menuRef =
|
|
8646
|
-
const [menuPos, setMenuPos] =
|
|
8647
|
-
const [isConfirmingDelete, setIsConfirmingDelete] =
|
|
8817
|
+
const menuRef = useRef16(null);
|
|
8818
|
+
const [menuPos, setMenuPos] = useState20({ left: 0, top: 0 });
|
|
8819
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState20(false);
|
|
8648
8820
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8649
8821
|
const sourceName = useMemo10(
|
|
8650
8822
|
() => {
|
|
@@ -8689,7 +8861,7 @@ function RelationshipContextMenu({
|
|
|
8689
8861
|
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";
|
|
8690
8862
|
const canUpdate = ability.can("update", "Connection");
|
|
8691
8863
|
const canDelete = ability.can("delete", "Connection");
|
|
8692
|
-
return /* @__PURE__ */
|
|
8864
|
+
return /* @__PURE__ */ React19.createElement(
|
|
8693
8865
|
"div",
|
|
8694
8866
|
{
|
|
8695
8867
|
ref: menuRef,
|
|
@@ -8703,29 +8875,29 @@ function RelationshipContextMenu({
|
|
|
8703
8875
|
onContextMenu: swallow,
|
|
8704
8876
|
onDoubleClick: swallow
|
|
8705
8877
|
},
|
|
8706
|
-
/* @__PURE__ */
|
|
8707
|
-
/* @__PURE__ */
|
|
8878
|
+
/* @__PURE__ */ React19.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
8879
|
+
/* @__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(
|
|
8708
8880
|
"button",
|
|
8709
8881
|
{
|
|
8710
8882
|
onClick: () => setIsConfirmingDelete(false),
|
|
8711
8883
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8712
8884
|
},
|
|
8713
8885
|
"Cancelar"
|
|
8714
|
-
), /* @__PURE__ */
|
|
8886
|
+
), /* @__PURE__ */ React19.createElement(
|
|
8715
8887
|
"button",
|
|
8716
8888
|
{
|
|
8717
8889
|
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8718
8890
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8719
8891
|
},
|
|
8720
8892
|
"Excluir"
|
|
8721
|
-
))) : /* @__PURE__ */
|
|
8893
|
+
))) : /* @__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(
|
|
8722
8894
|
"button",
|
|
8723
8895
|
{
|
|
8724
8896
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
8725
8897
|
className: baseButtonClass,
|
|
8726
8898
|
title: "Desconectar ponta ligada ao Source"
|
|
8727
8899
|
},
|
|
8728
|
-
/* @__PURE__ */
|
|
8900
|
+
/* @__PURE__ */ React19.createElement(
|
|
8729
8901
|
"svg",
|
|
8730
8902
|
{
|
|
8731
8903
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8738,18 +8910,18 @@ function RelationshipContextMenu({
|
|
|
8738
8910
|
strokeLinecap: "round",
|
|
8739
8911
|
strokeLinejoin: "round"
|
|
8740
8912
|
},
|
|
8741
|
-
/* @__PURE__ */
|
|
8742
|
-
/* @__PURE__ */
|
|
8913
|
+
/* @__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" }),
|
|
8914
|
+
/* @__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" })
|
|
8743
8915
|
),
|
|
8744
|
-
/* @__PURE__ */
|
|
8745
|
-
), /* @__PURE__ */
|
|
8916
|
+
/* @__PURE__ */ React19.createElement("span", null, "Desconectar Source (", sourceName, ")")
|
|
8917
|
+
), /* @__PURE__ */ React19.createElement(
|
|
8746
8918
|
"button",
|
|
8747
8919
|
{
|
|
8748
8920
|
onClick: () => onRelinkTarget == null ? void 0 : onRelinkTarget(data.linkObject),
|
|
8749
8921
|
className: baseButtonClass,
|
|
8750
8922
|
title: "Desconectar ponta ligada ao Target"
|
|
8751
8923
|
},
|
|
8752
|
-
/* @__PURE__ */
|
|
8924
|
+
/* @__PURE__ */ React19.createElement(
|
|
8753
8925
|
"svg",
|
|
8754
8926
|
{
|
|
8755
8927
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8762,21 +8934,21 @@ function RelationshipContextMenu({
|
|
|
8762
8934
|
strokeLinecap: "round",
|
|
8763
8935
|
strokeLinejoin: "round"
|
|
8764
8936
|
},
|
|
8765
|
-
/* @__PURE__ */
|
|
8766
|
-
/* @__PURE__ */
|
|
8767
|
-
/* @__PURE__ */
|
|
8768
|
-
/* @__PURE__ */
|
|
8769
|
-
/* @__PURE__ */
|
|
8937
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "16 3 21 3 21 8" }),
|
|
8938
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
|
|
8939
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "21 16 21 21 16 21" }),
|
|
8940
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
|
|
8941
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
|
|
8770
8942
|
),
|
|
8771
|
-
/* @__PURE__ */
|
|
8772
|
-
), /* @__PURE__ */
|
|
8943
|
+
/* @__PURE__ */ React19.createElement("span", null, "Desconectar Target (", targetName, ")")
|
|
8944
|
+
), /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ React19.createElement(
|
|
8773
8945
|
"button",
|
|
8774
8946
|
{
|
|
8775
8947
|
onClick: () => onOpenDetails == null ? void 0 : onOpenDetails(data.linkObject),
|
|
8776
8948
|
className: baseButtonClass,
|
|
8777
8949
|
title: "Abrir detalhes da rela\xE7\xE3o"
|
|
8778
8950
|
},
|
|
8779
|
-
/* @__PURE__ */
|
|
8951
|
+
/* @__PURE__ */ React19.createElement(
|
|
8780
8952
|
"svg",
|
|
8781
8953
|
{
|
|
8782
8954
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8789,19 +8961,19 @@ function RelationshipContextMenu({
|
|
|
8789
8961
|
strokeLinecap: "round",
|
|
8790
8962
|
strokeLinejoin: "round"
|
|
8791
8963
|
},
|
|
8792
|
-
/* @__PURE__ */
|
|
8793
|
-
/* @__PURE__ */
|
|
8794
|
-
/* @__PURE__ */
|
|
8964
|
+
/* @__PURE__ */ React19.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
8965
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
8966
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
|
|
8795
8967
|
),
|
|
8796
|
-
/* @__PURE__ */
|
|
8797
|
-
), canDelete && /* @__PURE__ */
|
|
8968
|
+
/* @__PURE__ */ React19.createElement("span", null, "Abrir Detalhes")
|
|
8969
|
+
), canDelete && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React19.createElement(
|
|
8798
8970
|
"button",
|
|
8799
8971
|
{
|
|
8800
8972
|
onClick: () => setIsConfirmingDelete(true),
|
|
8801
8973
|
className: dangerButtonClass,
|
|
8802
8974
|
title: "Excluir esta conex\xE3o"
|
|
8803
8975
|
},
|
|
8804
|
-
/* @__PURE__ */
|
|
8976
|
+
/* @__PURE__ */ React19.createElement(
|
|
8805
8977
|
"svg",
|
|
8806
8978
|
{
|
|
8807
8979
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8814,19 +8986,19 @@ function RelationshipContextMenu({
|
|
|
8814
8986
|
strokeLinecap: "round",
|
|
8815
8987
|
strokeLinejoin: "round"
|
|
8816
8988
|
},
|
|
8817
|
-
/* @__PURE__ */
|
|
8818
|
-
/* @__PURE__ */
|
|
8819
|
-
/* @__PURE__ */
|
|
8820
|
-
/* @__PURE__ */
|
|
8821
|
-
/* @__PURE__ */
|
|
8989
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "3 6 5 6 21 6" }),
|
|
8990
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
|
|
8991
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M10 11v6" }),
|
|
8992
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M14 11v6" }),
|
|
8993
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
8822
8994
|
),
|
|
8823
|
-
/* @__PURE__ */
|
|
8995
|
+
/* @__PURE__ */ React19.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
8824
8996
|
)))))
|
|
8825
8997
|
);
|
|
8826
8998
|
}
|
|
8827
8999
|
|
|
8828
9000
|
// src/components/LoadingScreen.jsx
|
|
8829
|
-
import
|
|
9001
|
+
import React20 from "react";
|
|
8830
9002
|
var styles = {
|
|
8831
9003
|
loadingOverlay: {
|
|
8832
9004
|
position: "fixed",
|
|
@@ -8858,11 +9030,11 @@ var styles = {
|
|
|
8858
9030
|
`
|
|
8859
9031
|
};
|
|
8860
9032
|
function LoadingScreen() {
|
|
8861
|
-
return /* @__PURE__ */
|
|
9033
|
+
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 })));
|
|
8862
9034
|
}
|
|
8863
9035
|
|
|
8864
9036
|
// src/components/ImportParentFileModal.jsx
|
|
8865
|
-
import
|
|
9037
|
+
import React21, { useEffect as useEffect19, useState as useState21 } from "react";
|
|
8866
9038
|
function ImportParentFileModal({
|
|
8867
9039
|
isOpen,
|
|
8868
9040
|
onClose,
|
|
@@ -8873,11 +9045,11 @@ function ImportParentFileModal({
|
|
|
8873
9045
|
onFetchAvailableFiles,
|
|
8874
9046
|
currentViewName
|
|
8875
9047
|
}) {
|
|
8876
|
-
const [activeTab, setActiveTab] =
|
|
8877
|
-
const [availableDbs, setAvailableDbs] =
|
|
8878
|
-
const [availableViews, setAvailableViews] =
|
|
8879
|
-
const [selectedItem, setSelectedItem] =
|
|
8880
|
-
const [isLoading, setIsLoading] =
|
|
9048
|
+
const [activeTab, setActiveTab] = useState21("databases");
|
|
9049
|
+
const [availableDbs, setAvailableDbs] = useState21([]);
|
|
9050
|
+
const [availableViews, setAvailableViews] = useState21([]);
|
|
9051
|
+
const [selectedItem, setSelectedItem] = useState21(null);
|
|
9052
|
+
const [isLoading, setIsLoading] = useState21(false);
|
|
8881
9053
|
useEffect19(() => {
|
|
8882
9054
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8883
9055
|
const fetchData = async () => {
|
|
@@ -8943,13 +9115,13 @@ function ImportParentFileModal({
|
|
|
8943
9115
|
const swallow = (e) => e.stopPropagation();
|
|
8944
9116
|
const currentList = activeTab === "databases" ? availableDbs : availableViews;
|
|
8945
9117
|
const emptyMessage = activeTab === "databases" ? "Nenhum novo arquivo parent dispon\xEDvel." : "Nenhuma view dispon\xEDvel para importa\xE7\xE3o.";
|
|
8946
|
-
return /* @__PURE__ */
|
|
9118
|
+
return /* @__PURE__ */ React21.createElement(
|
|
8947
9119
|
"div",
|
|
8948
9120
|
{
|
|
8949
9121
|
className: "ui-overlay fixed inset-0 z-[1200] flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
|
8950
9122
|
onClick: onClose
|
|
8951
9123
|
},
|
|
8952
|
-
/* @__PURE__ */
|
|
9124
|
+
/* @__PURE__ */ React21.createElement(
|
|
8953
9125
|
"div",
|
|
8954
9126
|
{
|
|
8955
9127
|
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]",
|
|
@@ -8961,14 +9133,14 @@ function ImportParentFileModal({
|
|
|
8961
9133
|
onContextMenu: swallow,
|
|
8962
9134
|
onDoubleClick: swallow
|
|
8963
9135
|
},
|
|
8964
|
-
/* @__PURE__ */
|
|
9136
|
+
/* @__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(
|
|
8965
9137
|
"button",
|
|
8966
9138
|
{
|
|
8967
9139
|
onClick: onClose,
|
|
8968
9140
|
className: "p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8969
9141
|
title: "Fechar"
|
|
8970
9142
|
},
|
|
8971
|
-
/* @__PURE__ */
|
|
9143
|
+
/* @__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(
|
|
8972
9144
|
"path",
|
|
8973
9145
|
{
|
|
8974
9146
|
fillRule: "evenodd",
|
|
@@ -8977,14 +9149,14 @@ function ImportParentFileModal({
|
|
|
8977
9149
|
}
|
|
8978
9150
|
))
|
|
8979
9151
|
)),
|
|
8980
|
-
/* @__PURE__ */
|
|
9152
|
+
/* @__PURE__ */ React21.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ React21.createElement(
|
|
8981
9153
|
"button",
|
|
8982
9154
|
{
|
|
8983
9155
|
onClick: () => setActiveTab("databases"),
|
|
8984
9156
|
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"}`
|
|
8985
9157
|
},
|
|
8986
9158
|
"Arquivos Parent"
|
|
8987
|
-
), /* @__PURE__ */
|
|
9159
|
+
), /* @__PURE__ */ React21.createElement(
|
|
8988
9160
|
"button",
|
|
8989
9161
|
{
|
|
8990
9162
|
onClick: () => setActiveTab("views"),
|
|
@@ -8992,24 +9164,24 @@ function ImportParentFileModal({
|
|
|
8992
9164
|
},
|
|
8993
9165
|
"Views (Ancestralidades)"
|
|
8994
9166
|
)),
|
|
8995
|
-
/* @__PURE__ */
|
|
9167
|
+
/* @__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(
|
|
8996
9168
|
"div",
|
|
8997
9169
|
{
|
|
8998
9170
|
key: item.id,
|
|
8999
9171
|
onClick: () => setSelectedItem(item),
|
|
9000
9172
|
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"}`
|
|
9001
9173
|
},
|
|
9002
|
-
/* @__PURE__ */
|
|
9003
|
-
item.description && /* @__PURE__ */
|
|
9004
|
-
)) : /* @__PURE__ */
|
|
9005
|
-
/* @__PURE__ */
|
|
9174
|
+
/* @__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")),
|
|
9175
|
+
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)
|
|
9176
|
+
)) : /* @__PURE__ */ React21.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
|
|
9177
|
+
/* @__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(
|
|
9006
9178
|
"button",
|
|
9007
9179
|
{
|
|
9008
9180
|
onClick: onClose,
|
|
9009
9181
|
className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm text-slate-300"
|
|
9010
9182
|
},
|
|
9011
9183
|
"Cancelar"
|
|
9012
|
-
), /* @__PURE__ */
|
|
9184
|
+
), /* @__PURE__ */ React21.createElement(
|
|
9013
9185
|
"button",
|
|
9014
9186
|
{
|
|
9015
9187
|
onClick: handleConfirm,
|
|
@@ -9023,7 +9195,7 @@ function ImportParentFileModal({
|
|
|
9023
9195
|
}
|
|
9024
9196
|
|
|
9025
9197
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
9026
|
-
import
|
|
9198
|
+
import React22, { useState as useState22 } from "react";
|
|
9027
9199
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
9028
9200
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
9029
9201
|
var _a, _b, _c, _d;
|
|
@@ -9033,21 +9205,21 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9033
9205
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
9034
9206
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
9035
9207
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
9036
|
-
const [isReadMode, setIsReadMode] =
|
|
9208
|
+
const [isReadMode, setIsReadMode] = useState22(false);
|
|
9037
9209
|
const swallow = (e) => e.stopPropagation();
|
|
9038
9210
|
const handleImageClickFromText = (url, name) => {
|
|
9039
9211
|
if (onOpenImageViewer) {
|
|
9040
9212
|
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
9041
9213
|
}
|
|
9042
9214
|
};
|
|
9043
|
-
return /* @__PURE__ */
|
|
9215
|
+
return /* @__PURE__ */ React22.createElement(
|
|
9044
9216
|
"div",
|
|
9045
9217
|
{
|
|
9046
9218
|
className: "ui-overlay fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[1200]",
|
|
9047
9219
|
onClick: onClose,
|
|
9048
9220
|
onPointerDown: swallow
|
|
9049
9221
|
},
|
|
9050
|
-
/* @__PURE__ */
|
|
9222
|
+
/* @__PURE__ */ React22.createElement(
|
|
9051
9223
|
"div",
|
|
9052
9224
|
{
|
|
9053
9225
|
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
|
|
@@ -9055,7 +9227,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9055
9227
|
`,
|
|
9056
9228
|
onClick: swallow
|
|
9057
9229
|
},
|
|
9058
|
-
isReadMode ? /* @__PURE__ */
|
|
9230
|
+
isReadMode ? /* @__PURE__ */ React22.createElement(
|
|
9059
9231
|
DescriptionReadModePanel,
|
|
9060
9232
|
{
|
|
9061
9233
|
title: `${sourceName} \u2794 ${targetName}`,
|
|
@@ -9067,15 +9239,15 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9067
9239
|
onMentionClick,
|
|
9068
9240
|
onImageClick: handleImageClickFromText
|
|
9069
9241
|
}
|
|
9070
|
-
) : /* @__PURE__ */
|
|
9242
|
+
) : /* @__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(
|
|
9071
9243
|
"button",
|
|
9072
9244
|
{
|
|
9073
9245
|
onClick: () => setIsReadMode(true),
|
|
9074
9246
|
className: "p-1 text-slate-400 hover:text-white transition-colors",
|
|
9075
9247
|
title: "Modo de Leitura"
|
|
9076
9248
|
},
|
|
9077
|
-
/* @__PURE__ */
|
|
9078
|
-
)), /* @__PURE__ */
|
|
9249
|
+
/* @__PURE__ */ React22.createElement(FiBookOpen5, { size: 14 })
|
|
9250
|
+
)), /* @__PURE__ */ React22.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ React22.createElement(
|
|
9079
9251
|
DescriptionDisplay,
|
|
9080
9252
|
{
|
|
9081
9253
|
description,
|
|
@@ -9084,7 +9256,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9084
9256
|
onMentionClick,
|
|
9085
9257
|
onImageClick: handleImageClickFromText
|
|
9086
9258
|
}
|
|
9087
|
-
))), customProps.length > 0 && /* @__PURE__ */
|
|
9259
|
+
))), 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(
|
|
9088
9260
|
CustomPropertyDisplay,
|
|
9089
9261
|
{
|
|
9090
9262
|
key: prop.id,
|
|
@@ -9093,25 +9265,25 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9093
9265
|
onOpenImageViewer,
|
|
9094
9266
|
onUploadFile
|
|
9095
9267
|
}
|
|
9096
|
-
)))), !description && customProps.length === 0 && /* @__PURE__ */
|
|
9268
|
+
)))), !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".')))
|
|
9097
9269
|
)
|
|
9098
9270
|
);
|
|
9099
9271
|
}
|
|
9100
9272
|
|
|
9101
9273
|
// src/components/AncestryBoard.jsx
|
|
9102
|
-
import
|
|
9274
|
+
import React23, { useState as useState23, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef17 } from "react";
|
|
9103
9275
|
import {
|
|
9104
9276
|
FiSearch as FiSearch4,
|
|
9105
9277
|
FiLayers as FiLayers6,
|
|
9106
9278
|
FiCornerUpRight as FiCornerUpRight4,
|
|
9107
9279
|
FiPlay,
|
|
9108
|
-
FiPlus as
|
|
9280
|
+
FiPlus as FiPlus8,
|
|
9109
9281
|
FiTrash2 as FiTrash23,
|
|
9110
9282
|
FiArrowLeft as FiArrowLeft3,
|
|
9111
9283
|
FiArrowRight,
|
|
9112
9284
|
FiCheckCircle,
|
|
9113
9285
|
FiLoader as FiLoader4,
|
|
9114
|
-
FiX as
|
|
9286
|
+
FiX as FiX6,
|
|
9115
9287
|
FiAlertTriangle
|
|
9116
9288
|
} from "react-icons/fi";
|
|
9117
9289
|
var GroupItem = ({
|
|
@@ -9133,7 +9305,7 @@ var GroupItem = ({
|
|
|
9133
9305
|
}) => {
|
|
9134
9306
|
const canIndent = index > 0;
|
|
9135
9307
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
9136
|
-
const textareaRef =
|
|
9308
|
+
const textareaRef = useRef17(null);
|
|
9137
9309
|
const adjustHeight = () => {
|
|
9138
9310
|
const textarea = textareaRef.current;
|
|
9139
9311
|
if (textarea) {
|
|
@@ -9144,10 +9316,10 @@ var GroupItem = ({
|
|
|
9144
9316
|
useEffect20(() => {
|
|
9145
9317
|
adjustHeight();
|
|
9146
9318
|
}, [group.text]);
|
|
9147
|
-
return /* @__PURE__ */
|
|
9319
|
+
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: `
|
|
9148
9320
|
flex flex-col gap-2 py-2 px-3 transition-all duration-200
|
|
9149
9321
|
${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
|
|
9150
|
-
` }, /* @__PURE__ */
|
|
9322
|
+
` }, /* @__PURE__ */ React23.createElement(
|
|
9151
9323
|
"textarea",
|
|
9152
9324
|
{
|
|
9153
9325
|
ref: textareaRef,
|
|
@@ -9164,9 +9336,9 @@ var GroupItem = ({
|
|
|
9164
9336
|
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9165
9337
|
}
|
|
9166
9338
|
}
|
|
9167
|
-
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */
|
|
9339
|
+
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9168
9340
|
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9169
|
-
return /* @__PURE__ */
|
|
9341
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9170
9342
|
"div",
|
|
9171
9343
|
{
|
|
9172
9344
|
key: anc.ancestry_id,
|
|
@@ -9178,28 +9350,28 @@ var GroupItem = ({
|
|
|
9178
9350
|
},
|
|
9179
9351
|
isValid ? (
|
|
9180
9352
|
// [MANTIDO] Botão Play visível para todos
|
|
9181
|
-
/* @__PURE__ */
|
|
9353
|
+
/* @__PURE__ */ React23.createElement(
|
|
9182
9354
|
"button",
|
|
9183
9355
|
{
|
|
9184
9356
|
onClick: () => onPlayAncestry(anc.ancestry_id),
|
|
9185
9357
|
className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
|
|
9186
9358
|
title: "Renderizar no cen\xE1rio"
|
|
9187
9359
|
},
|
|
9188
|
-
/* @__PURE__ */
|
|
9360
|
+
/* @__PURE__ */ React23.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9189
9361
|
)
|
|
9190
|
-
) : /* @__PURE__ */
|
|
9191
|
-
/* @__PURE__ */
|
|
9192
|
-
canEdit && /* @__PURE__ */
|
|
9362
|
+
) : /* @__PURE__ */ React23.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React23.createElement(FiAlertTriangle, { size: 10 })),
|
|
9363
|
+
/* @__PURE__ */ React23.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
|
|
9364
|
+
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(
|
|
9193
9365
|
"button",
|
|
9194
9366
|
{
|
|
9195
9367
|
onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
|
|
9196
9368
|
className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
|
|
9197
9369
|
title: "Remover men\xE7\xE3o"
|
|
9198
9370
|
},
|
|
9199
|
-
/* @__PURE__ */
|
|
9371
|
+
/* @__PURE__ */ React23.createElement(FiX6, { size: 12 })
|
|
9200
9372
|
))
|
|
9201
9373
|
);
|
|
9202
|
-
})), canEdit && /* @__PURE__ */
|
|
9374
|
+
})), 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(
|
|
9203
9375
|
"button",
|
|
9204
9376
|
{
|
|
9205
9377
|
onClick: () => onRequestPickAncestry(group.id),
|
|
@@ -9209,17 +9381,17 @@ var GroupItem = ({
|
|
|
9209
9381
|
`,
|
|
9210
9382
|
title: "Adicionar Ancestralidade a este grupo"
|
|
9211
9383
|
},
|
|
9212
|
-
isPickingForThisGroup ? /* @__PURE__ */
|
|
9384
|
+
isPickingForThisGroup ? /* @__PURE__ */ React23.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React23.createElement(FiSearch4, { size: 12 }),
|
|
9213
9385
|
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
9214
|
-
), /* @__PURE__ */
|
|
9386
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9215
9387
|
"button",
|
|
9216
9388
|
{
|
|
9217
9389
|
onClick: () => onAddSubgroup(group.id),
|
|
9218
9390
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9219
9391
|
title: "Criar Subgrupo"
|
|
9220
9392
|
},
|
|
9221
|
-
/* @__PURE__ */
|
|
9222
|
-
)), /* @__PURE__ */
|
|
9393
|
+
/* @__PURE__ */ React23.createElement(FiPlus8, { size: 14 })
|
|
9394
|
+
)), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React23.createElement(
|
|
9223
9395
|
"button",
|
|
9224
9396
|
{
|
|
9225
9397
|
onClick: () => onIndent(group.id),
|
|
@@ -9227,24 +9399,24 @@ var GroupItem = ({
|
|
|
9227
9399
|
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
9228
9400
|
title: "Aninhar no grupo acima"
|
|
9229
9401
|
},
|
|
9230
|
-
/* @__PURE__ */
|
|
9231
|
-
), /* @__PURE__ */
|
|
9402
|
+
/* @__PURE__ */ React23.createElement(FiArrowRight, { size: 14 })
|
|
9403
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9232
9404
|
"button",
|
|
9233
9405
|
{
|
|
9234
9406
|
onClick: () => onOutdent(group.id),
|
|
9235
9407
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9236
9408
|
title: "Desaninhar"
|
|
9237
9409
|
},
|
|
9238
|
-
/* @__PURE__ */
|
|
9239
|
-
), /* @__PURE__ */
|
|
9410
|
+
/* @__PURE__ */ React23.createElement(FiArrowLeft3, { size: 14 })
|
|
9411
|
+
), /* @__PURE__ */ React23.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React23.createElement(
|
|
9240
9412
|
"button",
|
|
9241
9413
|
{
|
|
9242
9414
|
onClick: () => onDelete(group.id),
|
|
9243
9415
|
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
9244
9416
|
title: "Remover Grupo"
|
|
9245
9417
|
},
|
|
9246
|
-
/* @__PURE__ */
|
|
9247
|
-
)))), group.children && group.children.length > 0 && /* @__PURE__ */
|
|
9418
|
+
/* @__PURE__ */ React23.createElement(FiTrash23, { size: 14 })
|
|
9419
|
+
)))), group.children && group.children.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React23.createElement(
|
|
9248
9420
|
GroupItem,
|
|
9249
9421
|
{
|
|
9250
9422
|
key: childGroup.id,
|
|
@@ -9276,11 +9448,11 @@ function AncestryBoard({
|
|
|
9276
9448
|
userRole
|
|
9277
9449
|
// [NOVO] Recebe a role do usuário
|
|
9278
9450
|
}) {
|
|
9279
|
-
const [searchTerm, setSearchTerm] =
|
|
9280
|
-
const [groups, setGroups] =
|
|
9281
|
-
const [isLoaded, setIsLoaded] =
|
|
9282
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
9283
|
-
const [saveStatus, setSaveStatus] =
|
|
9451
|
+
const [searchTerm, setSearchTerm] = useState23("");
|
|
9452
|
+
const [groups, setGroups] = useState23([]);
|
|
9453
|
+
const [isLoaded, setIsLoaded] = useState23(false);
|
|
9454
|
+
const [pickingGroupId, setPickingGroupId] = useState23(null);
|
|
9455
|
+
const [saveStatus, setSaveStatus] = useState23("idle");
|
|
9284
9456
|
const canEdit = useMemo11(() => {
|
|
9285
9457
|
return userRole !== "viewer";
|
|
9286
9458
|
}, [userRole]);
|
|
@@ -9488,27 +9660,27 @@ function AncestryBoard({
|
|
|
9488
9660
|
});
|
|
9489
9661
|
};
|
|
9490
9662
|
if (!isOpen) return null;
|
|
9491
|
-
return /* @__PURE__ */
|
|
9663
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9492
9664
|
"div",
|
|
9493
9665
|
{
|
|
9494
9666
|
className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
|
|
9495
9667
|
onClick: onClose
|
|
9496
9668
|
},
|
|
9497
|
-
/* @__PURE__ */
|
|
9669
|
+
/* @__PURE__ */ React23.createElement(
|
|
9498
9670
|
"div",
|
|
9499
9671
|
{
|
|
9500
9672
|
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",
|
|
9501
9673
|
onClick: (e) => e.stopPropagation()
|
|
9502
9674
|
},
|
|
9503
|
-
/* @__PURE__ */
|
|
9675
|
+
/* @__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(
|
|
9504
9676
|
"button",
|
|
9505
9677
|
{
|
|
9506
9678
|
onClick: handleAddRootGroup,
|
|
9507
9679
|
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 "
|
|
9508
9680
|
},
|
|
9509
|
-
/* @__PURE__ */
|
|
9510
|
-
/* @__PURE__ */
|
|
9511
|
-
), /* @__PURE__ */
|
|
9681
|
+
/* @__PURE__ */ React23.createElement(FiPlus8, { size: 14, className: "text-indigo-400" }),
|
|
9682
|
+
/* @__PURE__ */ React23.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
|
|
9683
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9512
9684
|
"button",
|
|
9513
9685
|
{
|
|
9514
9686
|
onClick: onClose,
|
|
@@ -9516,11 +9688,11 @@ function AncestryBoard({
|
|
|
9516
9688
|
},
|
|
9517
9689
|
"\xD7"
|
|
9518
9690
|
))),
|
|
9519
|
-
/* @__PURE__ */
|
|
9691
|
+
/* @__PURE__ */ React23.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React23.createElement("div", { className: `
|
|
9520
9692
|
flex flex-col border-r border-white/10 transition-all duration-300 flex-none
|
|
9521
9693
|
${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
|
|
9522
9694
|
min-w-[280px] max-w-[500px] bg-slate-900
|
|
9523
|
-
` }, /* @__PURE__ */
|
|
9695
|
+
` }, /* @__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(
|
|
9524
9696
|
"input",
|
|
9525
9697
|
{
|
|
9526
9698
|
type: "text",
|
|
@@ -9533,10 +9705,10 @@ function AncestryBoard({
|
|
|
9533
9705
|
onChange: (e) => setSearchTerm(e.target.value),
|
|
9534
9706
|
autoFocus: !pickingGroupId
|
|
9535
9707
|
}
|
|
9536
|
-
))), /* @__PURE__ */
|
|
9708
|
+
))), /* @__PURE__ */ React23.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
|
|
9537
9709
|
const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
|
|
9538
9710
|
const isPicking = !!pickingGroupId;
|
|
9539
|
-
return /* @__PURE__ */
|
|
9711
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9540
9712
|
"div",
|
|
9541
9713
|
{
|
|
9542
9714
|
key: anc.ancestry_id,
|
|
@@ -9548,12 +9720,12 @@ function AncestryBoard({
|
|
|
9548
9720
|
${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"}
|
|
9549
9721
|
`
|
|
9550
9722
|
},
|
|
9551
|
-
/* @__PURE__ */
|
|
9723
|
+
/* @__PURE__ */ React23.createElement("div", { className: `
|
|
9552
9724
|
mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
|
|
9553
9725
|
${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"}
|
|
9554
|
-
` }, isPicking ? /* @__PURE__ */
|
|
9555
|
-
/* @__PURE__ */
|
|
9556
|
-
!isPicking && /* @__PURE__ */
|
|
9726
|
+
` }, isPicking ? /* @__PURE__ */ React23.createElement(FiPlus8, { size: 16 }) : /* @__PURE__ */ React23.createElement(FiLayers6, { size: 14 })),
|
|
9727
|
+
/* @__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)),
|
|
9728
|
+
!isPicking && /* @__PURE__ */ React23.createElement(
|
|
9557
9729
|
"button",
|
|
9558
9730
|
{
|
|
9559
9731
|
onClick: (e) => {
|
|
@@ -9563,10 +9735,10 @@ function AncestryBoard({
|
|
|
9563
9735
|
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",
|
|
9564
9736
|
title: "Renderizar Ancestralidade"
|
|
9565
9737
|
},
|
|
9566
|
-
/* @__PURE__ */
|
|
9738
|
+
/* @__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" }))
|
|
9567
9739
|
)
|
|
9568
9740
|
);
|
|
9569
|
-
}))), /* @__PURE__ */
|
|
9741
|
+
}))), /* @__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(
|
|
9570
9742
|
GroupItem,
|
|
9571
9743
|
{
|
|
9572
9744
|
key: group.id,
|
|
@@ -9586,7 +9758,7 @@ function AncestryBoard({
|
|
|
9586
9758
|
canEdit
|
|
9587
9759
|
}
|
|
9588
9760
|
))))),
|
|
9589
|
-
/* @__PURE__ */
|
|
9761
|
+
/* @__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"))
|
|
9590
9762
|
)
|
|
9591
9763
|
);
|
|
9592
9764
|
}
|
|
@@ -9730,44 +9902,45 @@ function XViewScene({
|
|
|
9730
9902
|
}
|
|
9731
9903
|
return null;
|
|
9732
9904
|
}, [ownerId, sceneConfigId]);
|
|
9733
|
-
const sceneDataRef =
|
|
9734
|
-
const parentDataRef =
|
|
9735
|
-
const ancestryDataRef =
|
|
9736
|
-
const [isLoading, setIsLoading] =
|
|
9737
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9738
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9739
|
-
const [isInitialized, setIsInitialized] =
|
|
9740
|
-
const [sceneVersion, setSceneVersion] =
|
|
9741
|
-
const [contextMenu, setContextMenu] =
|
|
9742
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9743
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9744
|
-
const [creationMode, setCreationMode] =
|
|
9745
|
-
const [versionMode, setVersionMode] =
|
|
9746
|
-
const [
|
|
9747
|
-
const [
|
|
9748
|
-
const [
|
|
9749
|
-
const [
|
|
9905
|
+
const sceneDataRef = useRef18(null);
|
|
9906
|
+
const parentDataRef = useRef18(null);
|
|
9907
|
+
const ancestryDataRef = useRef18(null);
|
|
9908
|
+
const [isLoading, setIsLoading] = useState24(true);
|
|
9909
|
+
const [permissionStatus, setPermissionStatus] = useState24("loading");
|
|
9910
|
+
const [userPermissionRole, setUserPermissionRole] = useState24(null);
|
|
9911
|
+
const [isInitialized, setIsInitialized] = useState24(false);
|
|
9912
|
+
const [sceneVersion, setSceneVersion] = useState24(0);
|
|
9913
|
+
const [contextMenu, setContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeData: null });
|
|
9914
|
+
const [multiContextMenu, setMultiContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
9915
|
+
const [relationshipMenu, setRelationshipMenu] = useState24({ visible: false, x: 0, y: 0, linkObject: null });
|
|
9916
|
+
const [creationMode, setCreationMode] = useState24({ isActive: false, sourceNodeData: null });
|
|
9917
|
+
const [versionMode, setVersionMode] = useState24({ isActive: false, sourceNodeData: null });
|
|
9918
|
+
const [questMode, setQuestMode] = useState24({ isActive: false });
|
|
9919
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState24(false);
|
|
9920
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState24(false);
|
|
9921
|
+
const [ancestryMode, setAncestryMode] = useState24({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
9922
|
+
const [readingMode, setReadingMode] = useState24({
|
|
9750
9923
|
isActive: false,
|
|
9751
9924
|
ancestry: null,
|
|
9752
9925
|
branchStack: [],
|
|
9753
9926
|
autoAbstraction: false
|
|
9754
9927
|
});
|
|
9755
|
-
const [formPosition, setFormPosition] =
|
|
9756
|
-
const [detailsNode, setDetailsNode] =
|
|
9757
|
-
const [detailsLink, setDetailsLink] =
|
|
9758
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9759
|
-
const [imageViewer, setImageViewer] =
|
|
9760
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9761
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9762
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9763
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9764
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9765
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9766
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9767
|
-
const mountRef =
|
|
9768
|
-
const tooltipRef =
|
|
9769
|
-
const formRef =
|
|
9770
|
-
const stateRef =
|
|
9928
|
+
const [formPosition, setFormPosition] = useState24({ left: 16, top: 16, opacity: 0 });
|
|
9929
|
+
const [detailsNode, setDetailsNode] = useState24(null);
|
|
9930
|
+
const [detailsLink, setDetailsLink] = useState24(null);
|
|
9931
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState24(null);
|
|
9932
|
+
const [imageViewer, setImageViewer] = useState24({ visible: false, images: [], startIndex: 0 });
|
|
9933
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState24({ visible: false, data: null, path: null });
|
|
9934
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState24(false);
|
|
9935
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState24("");
|
|
9936
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState24(null);
|
|
9937
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState24(false);
|
|
9938
|
+
const [ancestryBoardData, setAncestryBoardData] = useState24([]);
|
|
9939
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState24(false);
|
|
9940
|
+
const mountRef = useRef18(null);
|
|
9941
|
+
const tooltipRef = useRef18(null);
|
|
9942
|
+
const formRef = useRef18(null);
|
|
9943
|
+
const stateRef = useRef18({
|
|
9771
9944
|
readMode: {
|
|
9772
9945
|
currentMaxIndex: 0,
|
|
9773
9946
|
progressMap: {}
|
|
@@ -10809,12 +10982,15 @@ function XViewScene({
|
|
|
10809
10982
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
10810
10983
|
}
|
|
10811
10984
|
function handleKeyDown(event) {
|
|
10985
|
+
var _a2, _b2, _c2, _d2;
|
|
10812
10986
|
const context = actionHandlerContext;
|
|
10813
10987
|
if (event.key === "Escape") {
|
|
10814
10988
|
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
10815
10989
|
if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
|
|
10816
10990
|
if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
|
|
10991
|
+
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
|
|
10817
10992
|
if (stateRef.current.ancestry.isActive) handleCancelAncestryCreation();
|
|
10993
|
+
if ((_b2 = context.questMode) == null ? void 0 : _b2.isActive) context.setters.setQuestMode({ isActive: false });
|
|
10818
10994
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
10819
10995
|
stateRef.current.selectedNodes.clear();
|
|
10820
10996
|
}
|
|
@@ -10822,6 +10998,17 @@ function XViewScene({
|
|
|
10822
10998
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
10823
10999
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
10824
11000
|
}
|
|
11001
|
+
if (event.key.toLowerCase() === "q") {
|
|
11002
|
+
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;
|
|
11003
|
+
if (isUiClear) {
|
|
11004
|
+
const isView = ((_d2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _d2.toLowerCase()) === "view";
|
|
11005
|
+
if (!isView) {
|
|
11006
|
+
alert("Nodes de Quest s\xF3 podem ser criados dentro de uma View.");
|
|
11007
|
+
return;
|
|
11008
|
+
}
|
|
11009
|
+
setQuestMode({ isActive: true });
|
|
11010
|
+
}
|
|
11011
|
+
}
|
|
10825
11012
|
}
|
|
10826
11013
|
function handleDoubleClick(event) {
|
|
10827
11014
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
@@ -10980,9 +11167,7 @@ function XViewScene({
|
|
|
10980
11167
|
mountEl: currentMount,
|
|
10981
11168
|
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10982
11169
|
parentData: parentDataRef.current,
|
|
10983
|
-
// <--- ADICIONADO AQUI
|
|
10984
11170
|
ancestryData: ancestryDataRef.current
|
|
10985
|
-
// <--- ADICIONADO AQUI
|
|
10986
11171
|
});
|
|
10987
11172
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10988
11173
|
stateRef.current.controls.update();
|
|
@@ -11288,6 +11473,16 @@ function XViewScene({
|
|
|
11288
11473
|
mountRef,
|
|
11289
11474
|
creationMode,
|
|
11290
11475
|
versionMode,
|
|
11476
|
+
questMode,
|
|
11477
|
+
// <-- Adicionado
|
|
11478
|
+
sceneSaveUrl,
|
|
11479
|
+
// <-- Adicionado
|
|
11480
|
+
sceneConfigId,
|
|
11481
|
+
// <-- Adicionado
|
|
11482
|
+
ownerId,
|
|
11483
|
+
// <-- Adicionado
|
|
11484
|
+
viewType: viewParams == null ? void 0 : viewParams.type,
|
|
11485
|
+
// <-- Adicionado
|
|
11291
11486
|
userId: (_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id,
|
|
11292
11487
|
setters: {
|
|
11293
11488
|
setContextMenu,
|
|
@@ -11299,7 +11494,9 @@ function XViewScene({
|
|
|
11299
11494
|
setDetailsNode,
|
|
11300
11495
|
setDetailsLink,
|
|
11301
11496
|
setSceneVersion,
|
|
11302
|
-
setAncestryMode
|
|
11497
|
+
setAncestryMode,
|
|
11498
|
+
setQuestMode
|
|
11499
|
+
// <-- Adicionado
|
|
11303
11500
|
},
|
|
11304
11501
|
tweenToTarget,
|
|
11305
11502
|
handleVersionTimeline,
|
|
@@ -11315,8 +11512,13 @@ function XViewScene({
|
|
|
11315
11512
|
[
|
|
11316
11513
|
creationMode,
|
|
11317
11514
|
versionMode,
|
|
11318
|
-
|
|
11515
|
+
questMode,
|
|
11516
|
+
sceneSaveUrl,
|
|
11517
|
+
sceneConfigId,
|
|
11518
|
+
ownerId,
|
|
11519
|
+
viewParams == null ? void 0 : viewParams.type,
|
|
11319
11520
|
(_a = session == null ? void 0 : session.user) == null ? void 0 : _a.id,
|
|
11521
|
+
tweenToTarget,
|
|
11320
11522
|
handleVersionTimeline,
|
|
11321
11523
|
save_view_data,
|
|
11322
11524
|
get_single_parent_file,
|
|
@@ -11328,6 +11530,111 @@ function XViewScene({
|
|
|
11328
11530
|
const handleStartVersioning = (nodeData) => {
|
|
11329
11531
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11330
11532
|
};
|
|
11533
|
+
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11534
|
+
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11535
|
+
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
11536
|
+
const newNode = {
|
|
11537
|
+
id: short2.generate(),
|
|
11538
|
+
...newQuestData,
|
|
11539
|
+
type: ["quest", ...newQuestData.type.filter((t) => t !== "quest")]
|
|
11540
|
+
};
|
|
11541
|
+
if (!graphDataRef.current[sceneConfigId2]) {
|
|
11542
|
+
graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
|
|
11543
|
+
}
|
|
11544
|
+
graphDataRef.current[sceneConfigId2].nodes.push(newNode);
|
|
11545
|
+
sceneDataRef2.current.nodes.push(newNode);
|
|
11546
|
+
const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((mesh) => {
|
|
11547
|
+
const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = mesh.userData;
|
|
11548
|
+
return rest;
|
|
11549
|
+
});
|
|
11550
|
+
currentVisualNodes.push(newNode);
|
|
11551
|
+
const currentVisualLinks = stateRef2.current.allLinks.map((line) => {
|
|
11552
|
+
const { sourceNode, targetNode, ...rest } = line.userData;
|
|
11553
|
+
return rest;
|
|
11554
|
+
});
|
|
11555
|
+
const sceneFileData = {
|
|
11556
|
+
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11557
|
+
nodes: currentVisualNodes,
|
|
11558
|
+
links: currentVisualLinks,
|
|
11559
|
+
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11560
|
+
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
11561
|
+
};
|
|
11562
|
+
try {
|
|
11563
|
+
await actions.save_view_data(sceneSaveUrl2, sceneFileData);
|
|
11564
|
+
stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
11565
|
+
parentFileId: sceneConfigId2,
|
|
11566
|
+
ownerId: ownerId2,
|
|
11567
|
+
datasetName: "Quests Internas (View)"
|
|
11568
|
+
});
|
|
11569
|
+
const basePosition = stateRef2.current.controls.target.clone();
|
|
11570
|
+
const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
|
|
11571
|
+
const finalPosition = basePosition.add(offset);
|
|
11572
|
+
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11573
|
+
context.tweenToTarget(finalPosition, 1.2);
|
|
11574
|
+
setters.setQuestMode({ isActive: false });
|
|
11575
|
+
setters.setSceneVersion((v) => v + 1);
|
|
11576
|
+
} catch (error) {
|
|
11577
|
+
console.error("Falha ao salvar Quest na View:", error);
|
|
11578
|
+
alert("Ocorreu um erro ao criar a Quest.");
|
|
11579
|
+
}
|
|
11580
|
+
};
|
|
11581
|
+
userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
|
|
11582
|
+
const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2 } = context;
|
|
11583
|
+
const { sourceNodeData } = stateRef2.current.connection;
|
|
11584
|
+
if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
|
|
11585
|
+
userActionHandlers.handleCancelConnection(context);
|
|
11586
|
+
return;
|
|
11587
|
+
}
|
|
11588
|
+
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id);
|
|
11589
|
+
const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id);
|
|
11590
|
+
let parentInfoToSave = sourceParentInfo;
|
|
11591
|
+
if (sourceParentInfo.parentFileId === sceneConfigId2 && targetParentInfo.parentFileId !== sceneConfigId2) {
|
|
11592
|
+
parentInfoToSave = targetParentInfo;
|
|
11593
|
+
} else if (targetParentInfo.parentFileId === sceneConfigId2 && sourceParentInfo.parentFileId !== sceneConfigId2) {
|
|
11594
|
+
parentInfoToSave = sourceParentInfo;
|
|
11595
|
+
}
|
|
11596
|
+
const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
|
|
11597
|
+
const newLink = {
|
|
11598
|
+
id: `link_${short2.generate()}`,
|
|
11599
|
+
source: sourceNodeData.id,
|
|
11600
|
+
target: targetNodeData.id
|
|
11601
|
+
};
|
|
11602
|
+
try {
|
|
11603
|
+
if (parentFileIdToSave === sceneConfigId2) {
|
|
11604
|
+
const specificParentData = graphDataRef.current[sceneConfigId2];
|
|
11605
|
+
specificParentData.links.push(newLink);
|
|
11606
|
+
const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((m) => {
|
|
11607
|
+
const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = m.userData;
|
|
11608
|
+
return rest;
|
|
11609
|
+
});
|
|
11610
|
+
const currentVisualLinks = stateRef2.current.allLinks.map((l) => {
|
|
11611
|
+
const { sourceNode, targetNode, ...rest } = l.userData;
|
|
11612
|
+
return rest;
|
|
11613
|
+
});
|
|
11614
|
+
currentVisualLinks.push(newLink);
|
|
11615
|
+
const viewFilePayload = {
|
|
11616
|
+
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11617
|
+
nodes: currentVisualNodes,
|
|
11618
|
+
links: currentVisualLinks,
|
|
11619
|
+
quest_nodes: specificParentData.nodes,
|
|
11620
|
+
quest_links: specificParentData.links
|
|
11621
|
+
// Salva a conexão aqui!
|
|
11622
|
+
};
|
|
11623
|
+
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11624
|
+
} else {
|
|
11625
|
+
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
11626
|
+
specificParentData.links.push(newLink);
|
|
11627
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
11628
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
11629
|
+
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
11630
|
+
}
|
|
11631
|
+
addNewLinkToScene(stateRef2.current, newLink);
|
|
11632
|
+
} catch (error) {
|
|
11633
|
+
console.error("Falha ao salvar a nova conex\xE3o:", error);
|
|
11634
|
+
alert("Ocorreu um erro ao salvar a nova conex\xE3o.");
|
|
11635
|
+
}
|
|
11636
|
+
userActionHandlers.handleCancelConnection(context);
|
|
11637
|
+
};
|
|
11331
11638
|
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
11332
11639
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
11333
11640
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
@@ -12595,6 +12902,7 @@ function XViewScene({
|
|
|
12595
12902
|
[actionHandlerContext]
|
|
12596
12903
|
);
|
|
12597
12904
|
const handleSaveCurrentView = useCallback4(async () => {
|
|
12905
|
+
var _a2, _b2;
|
|
12598
12906
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12599
12907
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12600
12908
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12619,14 +12927,17 @@ function XViewScene({
|
|
|
12619
12927
|
const sceneFileData = {
|
|
12620
12928
|
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
12621
12929
|
nodes: currentNodes,
|
|
12622
|
-
links: currentLinks
|
|
12930
|
+
links: currentLinks,
|
|
12931
|
+
// --- ADICIONE ESTAS DUAS LINHAS PARA PRESERVAR A FONTE DA VERDADE ---
|
|
12932
|
+
quest_nodes: ((_a2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _a2.nodes) || [],
|
|
12933
|
+
quest_links: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.links) || []
|
|
12623
12934
|
};
|
|
12624
12935
|
try {
|
|
12625
12936
|
await save_view_data(sceneSaveUrl, sceneFileData);
|
|
12626
12937
|
} catch (error) {
|
|
12627
12938
|
console.error("Erro na chamada de save_view_data:", error);
|
|
12628
12939
|
}
|
|
12629
|
-
}, [sceneSaveUrl, save_view_data]);
|
|
12940
|
+
}, [sceneSaveUrl, save_view_data, sceneConfigId]);
|
|
12630
12941
|
const allAvailableNodes = useMemo12(() => {
|
|
12631
12942
|
if (!parentDataRef.current) return [];
|
|
12632
12943
|
return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
@@ -12712,20 +13023,20 @@ function XViewScene({
|
|
|
12712
13023
|
}
|
|
12713
13024
|
}, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
|
|
12714
13025
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
12715
|
-
return /* @__PURE__ */
|
|
13026
|
+
return /* @__PURE__ */ React24.createElement(LoadingScreen, null);
|
|
12716
13027
|
}
|
|
12717
13028
|
if (permissionStatus === "denied") {
|
|
12718
|
-
return /* @__PURE__ */
|
|
13029
|
+
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(
|
|
12719
13030
|
"button",
|
|
12720
13031
|
{
|
|
12721
13032
|
onClick: () => router.push("/dashboard/scenes"),
|
|
12722
13033
|
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"
|
|
12723
13034
|
},
|
|
12724
|
-
/* @__PURE__ */
|
|
13035
|
+
/* @__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" })),
|
|
12725
13036
|
"Voltar para Scenes"
|
|
12726
13037
|
)));
|
|
12727
13038
|
}
|
|
12728
|
-
return /* @__PURE__ */
|
|
13039
|
+
return /* @__PURE__ */ React24.createElement(
|
|
12729
13040
|
"div",
|
|
12730
13041
|
{
|
|
12731
13042
|
ref: mountRef,
|
|
@@ -12737,7 +13048,7 @@ function XViewScene({
|
|
|
12737
13048
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12738
13049
|
}
|
|
12739
13050
|
},
|
|
12740
|
-
userPermissionRole !== "link_viewer" && /* @__PURE__ */
|
|
13051
|
+
userPermissionRole !== "link_viewer" && /* @__PURE__ */ React24.createElement(
|
|
12741
13052
|
XViewSidebar,
|
|
12742
13053
|
{
|
|
12743
13054
|
dbNodes: searchableDbNodes,
|
|
@@ -12757,7 +13068,7 @@ function XViewScene({
|
|
|
12757
13068
|
userRole: userPermissionRole
|
|
12758
13069
|
}
|
|
12759
13070
|
),
|
|
12760
|
-
creationMode.isActive && /* @__PURE__ */
|
|
13071
|
+
creationMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
12761
13072
|
InSceneCreationForm,
|
|
12762
13073
|
{
|
|
12763
13074
|
onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
|
|
@@ -12782,7 +13093,7 @@ function XViewScene({
|
|
|
12782
13093
|
availableAncestries: allAvailableAncestries
|
|
12783
13094
|
}
|
|
12784
13095
|
),
|
|
12785
|
-
versionMode.isActive && /* @__PURE__ */
|
|
13096
|
+
versionMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
12786
13097
|
InSceneVersionForm,
|
|
12787
13098
|
{
|
|
12788
13099
|
onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
|
|
@@ -12801,13 +13112,27 @@ function XViewScene({
|
|
|
12801
13112
|
availableAncestries: allAvailableAncestries
|
|
12802
13113
|
}
|
|
12803
13114
|
),
|
|
12804
|
-
|
|
13115
|
+
questMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
13116
|
+
InSceneQuestForm,
|
|
13117
|
+
{
|
|
13118
|
+
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13119
|
+
onCancel: () => setQuestMode({ isActive: false }),
|
|
13120
|
+
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13121
|
+
refEl: formRef,
|
|
13122
|
+
onOpenImageViewer: handleOpenImageViewer,
|
|
13123
|
+
onMentionClick: handleAddExistingNode,
|
|
13124
|
+
onUploadFile: upload_file_action,
|
|
13125
|
+
availableNodes: allAvailableNodes,
|
|
13126
|
+
availableAncestries: allAvailableAncestries
|
|
13127
|
+
}
|
|
13128
|
+
),
|
|
13129
|
+
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React24.createElement(
|
|
12805
13130
|
"div",
|
|
12806
13131
|
{
|
|
12807
13132
|
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"}`,
|
|
12808
13133
|
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12809
13134
|
},
|
|
12810
|
-
/* @__PURE__ */
|
|
13135
|
+
/* @__PURE__ */ React24.createElement(
|
|
12811
13136
|
"div",
|
|
12812
13137
|
{
|
|
12813
13138
|
onPointerDown: (e) => {
|
|
@@ -12818,7 +13143,7 @@ function XViewScene({
|
|
|
12818
13143
|
title: "Arraste para redimensionar"
|
|
12819
13144
|
}
|
|
12820
13145
|
),
|
|
12821
|
-
/* @__PURE__ */
|
|
13146
|
+
/* @__PURE__ */ React24.createElement(
|
|
12822
13147
|
DescriptionReadModePanel,
|
|
12823
13148
|
{
|
|
12824
13149
|
key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
|
|
@@ -12853,7 +13178,7 @@ function XViewScene({
|
|
|
12853
13178
|
}
|
|
12854
13179
|
)
|
|
12855
13180
|
),
|
|
12856
|
-
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */
|
|
13181
|
+
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React24.createElement(
|
|
12857
13182
|
CreateAncestryPanel,
|
|
12858
13183
|
{
|
|
12859
13184
|
ancestryMode,
|
|
@@ -12880,7 +13205,7 @@ function XViewScene({
|
|
|
12880
13205
|
onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
|
|
12881
13206
|
}
|
|
12882
13207
|
),
|
|
12883
|
-
editingAncestryRel.visible && /* @__PURE__ */
|
|
13208
|
+
editingAncestryRel.visible && /* @__PURE__ */ React24.createElement(
|
|
12884
13209
|
AncestryRelationshipPanel,
|
|
12885
13210
|
{
|
|
12886
13211
|
data: editingAncestryRel.data,
|
|
@@ -12894,7 +13219,7 @@ function XViewScene({
|
|
|
12894
13219
|
onUploadFile: upload_file_action
|
|
12895
13220
|
}
|
|
12896
13221
|
),
|
|
12897
|
-
detailsNode && /* @__PURE__ */
|
|
13222
|
+
detailsNode && /* @__PURE__ */ React24.createElement(
|
|
12898
13223
|
NodeDetailsPanel,
|
|
12899
13224
|
{
|
|
12900
13225
|
node: detailsNode,
|
|
@@ -12921,7 +13246,7 @@ function XViewScene({
|
|
|
12921
13246
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
12922
13247
|
}
|
|
12923
13248
|
),
|
|
12924
|
-
detailsLink && /* @__PURE__ */
|
|
13249
|
+
detailsLink && /* @__PURE__ */ React24.createElement(
|
|
12925
13250
|
RelationshipDetailsPanel,
|
|
12926
13251
|
{
|
|
12927
13252
|
link: detailsLink,
|
|
@@ -12935,7 +13260,7 @@ function XViewScene({
|
|
|
12935
13260
|
userRole: userPermissionRole
|
|
12936
13261
|
}
|
|
12937
13262
|
),
|
|
12938
|
-
ancestryLinkDetails && /* @__PURE__ */
|
|
13263
|
+
ancestryLinkDetails && /* @__PURE__ */ React24.createElement(
|
|
12939
13264
|
AncestryLinkDetailsPanel,
|
|
12940
13265
|
{
|
|
12941
13266
|
data: ancestryLinkDetails,
|
|
@@ -12946,7 +13271,7 @@ function XViewScene({
|
|
|
12946
13271
|
onUploadFile: upload_file_action
|
|
12947
13272
|
}
|
|
12948
13273
|
),
|
|
12949
|
-
/* @__PURE__ */
|
|
13274
|
+
/* @__PURE__ */ React24.createElement(
|
|
12950
13275
|
"div",
|
|
12951
13276
|
{
|
|
12952
13277
|
ref: tooltipRef,
|
|
@@ -12973,7 +13298,7 @@ function XViewScene({
|
|
|
12973
13298
|
}
|
|
12974
13299
|
}
|
|
12975
13300
|
),
|
|
12976
|
-
/* @__PURE__ */
|
|
13301
|
+
/* @__PURE__ */ React24.createElement(
|
|
12977
13302
|
ContextMenu,
|
|
12978
13303
|
{
|
|
12979
13304
|
data: contextMenu,
|
|
@@ -12996,7 +13321,7 @@ function XViewScene({
|
|
|
12996
13321
|
onFocusNode: handleFocusNode
|
|
12997
13322
|
}
|
|
12998
13323
|
),
|
|
12999
|
-
/* @__PURE__ */
|
|
13324
|
+
/* @__PURE__ */ React24.createElement(
|
|
13000
13325
|
MultiNodeContextMenu,
|
|
13001
13326
|
{
|
|
13002
13327
|
data: multiContextMenu,
|
|
@@ -13007,7 +13332,7 @@ function XViewScene({
|
|
|
13007
13332
|
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
|
|
13008
13333
|
}
|
|
13009
13334
|
),
|
|
13010
|
-
/* @__PURE__ */
|
|
13335
|
+
/* @__PURE__ */ React24.createElement(
|
|
13011
13336
|
RelationshipContextMenu,
|
|
13012
13337
|
{
|
|
13013
13338
|
data: relationshipMenu,
|
|
@@ -13025,8 +13350,8 @@ function XViewScene({
|
|
|
13025
13350
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
13026
13351
|
}
|
|
13027
13352
|
),
|
|
13028
|
-
/* @__PURE__ */
|
|
13029
|
-
/* @__PURE__ */
|
|
13353
|
+
/* @__PURE__ */ React24.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
|
|
13354
|
+
/* @__PURE__ */ React24.createElement(
|
|
13030
13355
|
AncestryBoard,
|
|
13031
13356
|
{
|
|
13032
13357
|
isOpen: isAncestryBoardOpen,
|
|
@@ -13039,7 +13364,7 @@ function XViewScene({
|
|
|
13039
13364
|
userRole: userPermissionRole
|
|
13040
13365
|
}
|
|
13041
13366
|
),
|
|
13042
|
-
/* @__PURE__ */
|
|
13367
|
+
/* @__PURE__ */ React24.createElement(
|
|
13043
13368
|
ImportParentFileModal,
|
|
13044
13369
|
{
|
|
13045
13370
|
isOpen: isImportModalOpen,
|
|
@@ -13100,11 +13425,22 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13100
13425
|
);
|
|
13101
13426
|
}
|
|
13102
13427
|
}
|
|
13428
|
+
parentData[scene_config] = {
|
|
13429
|
+
dataset_name: "Quests Internas (View)",
|
|
13430
|
+
nodes: sceneData.quest_nodes || [],
|
|
13431
|
+
links: sceneData.quest_links || []
|
|
13432
|
+
};
|
|
13103
13433
|
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
13104
13434
|
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
13105
13435
|
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
13106
13436
|
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
13107
|
-
const validatedNodes = (sceneData.nodes || []).map((sceneNode) =>
|
|
13437
|
+
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
13438
|
+
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
13439
|
+
if (nodeTypes.includes("quest")) {
|
|
13440
|
+
return sceneNode;
|
|
13441
|
+
}
|
|
13442
|
+
return parentNodeMap.get(String(sceneNode.id));
|
|
13443
|
+
}).filter(Boolean);
|
|
13108
13444
|
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
13109
13445
|
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|
|
13110
13446
|
const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
|